160 lines
6.1 KiB
Python
160 lines
6.1 KiB
Python
import os
|
|
from flask import Flask, render_template, request, jsonify, send_from_directory
|
|
import joblib # type: ignore
|
|
from werkzeug.utils import secure_filename
|
|
import cv2
|
|
import numpy as np
|
|
import math
|
|
|
|
# Setup Flask
|
|
app = Flask(__name__, template_folder='D:/Kuliah/SKRIPSI/Kakao/templates')
|
|
app.config['UPLOAD_FOLDER'] = 'D:/Kuliah/SKRIPSI/Kakao/uploads'
|
|
|
|
# Pastikan folder uploads ada
|
|
if not os.path.exists(app.config['UPLOAD_FOLDER']):
|
|
os.makedirs(app.config['UPLOAD_FOLDER'])
|
|
|
|
@app.route('/uploads/<filename>')
|
|
def uploaded_file(filename):
|
|
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
|
|
|
|
# Load model KNN
|
|
model_path = os.path.join('D:\Kuliah\SKRIPSI\Kakao\model\model_knn.pkl')
|
|
with open(model_path, 'rb') as model_file:
|
|
model_knn = joblib.load(model_file)
|
|
|
|
# Fungsi untuk memvalidasi file gambar
|
|
def allowed_file(filename):
|
|
allowed_extensions = {'png', 'jpg', 'jpeg'}
|
|
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions
|
|
|
|
# Fungsi preprocessing gambar (GLCM)
|
|
def preprocess_image(image_path):
|
|
img = cv2.imread(image_path)
|
|
resized_img = cv2.resize(img, (32, 43))
|
|
gray_img = cv2.cvtColor(resized_img, cv2.COLOR_BGR2GRAY)
|
|
|
|
def glcm(img, angle):
|
|
max_val = np.max(img)
|
|
imgTmp = np.zeros([max_val+1, max_val+1])
|
|
for i in range(len(img)-1):
|
|
for j in range(len(img[i])-1):
|
|
if angle == 0:
|
|
imgTmp[img[i][j], img[i,j+1]] += 1
|
|
elif angle == 45:
|
|
if i > 0 and j < len(img[i])-1:
|
|
imgTmp[img[i][j], img[i-1,j+1]] += 1
|
|
elif angle == 90:
|
|
if i > 0:
|
|
imgTmp[img[i][j], img[i-1,j]] += 1
|
|
elif angle == 135:
|
|
if i > 0 and j > 0:
|
|
imgTmp[img[i][j], img[i-1,j-1]] += 1
|
|
transpos = np.transpose(imgTmp)
|
|
data = imgTmp + transpos
|
|
data /= np.sum(data)
|
|
return data
|
|
|
|
def contrast(data):
|
|
contrast_val = 0
|
|
for i in range(len(data)):
|
|
for j in range(len(data)):
|
|
contrast_val += data[i,j] * pow(i-j, 2)
|
|
return contrast_val
|
|
|
|
def entropy(data):
|
|
entropy_val = 0
|
|
for i in range(len(data)):
|
|
for j in range(len(data)):
|
|
if data[i,j] > 0:
|
|
entropy_val += - (data[i,j] * math.log(data[i,j]))
|
|
return entropy_val
|
|
|
|
def homogenitas(data):
|
|
homogenitas_val = 0
|
|
for i in range(len(data)):
|
|
for j in range(len(data)):
|
|
homogenitas_val += data[i,j] * (1 + (pow(i-j, 2)))
|
|
return homogenitas_val
|
|
|
|
def energy(data):
|
|
energy_val = 0
|
|
for i in range(len(data)):
|
|
for j in range(len(data)):
|
|
energy_val += data[i,j] ** 2
|
|
return energy_val
|
|
|
|
angles = [0, 45, 90, 135]
|
|
features = []
|
|
for angle in angles:
|
|
glcm_matrix = glcm(gray_img, angle)
|
|
features.append(energy(glcm_matrix))
|
|
features.append(homogenitas(glcm_matrix))
|
|
features.append(entropy(glcm_matrix))
|
|
features.append(contrast(glcm_matrix))
|
|
|
|
return np.array(features).reshape(1, -1) # Mengembalikan 16 fitur
|
|
|
|
@app.route('/')
|
|
def index():
|
|
return render_template('dashboard.html')
|
|
|
|
@app.route('/panduan')
|
|
def panduan():
|
|
return render_template('panduan.html')
|
|
|
|
@app.route('/identifikasi', methods=['GET', 'POST'])
|
|
def identifikasi():
|
|
if request.method == 'POST':
|
|
if 'file' not in request.files:
|
|
return jsonify({"error": "No file part"})
|
|
|
|
file = request.files['file']
|
|
|
|
if file.filename == '':
|
|
return jsonify({"error": "No selected file"})
|
|
|
|
if file and allowed_file(file.filename):
|
|
filename = secure_filename(file.filename)
|
|
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
|
|
|
# Simpan file gambar
|
|
file.save(filepath)
|
|
|
|
try:
|
|
# Preprocess gambar untuk prediksi
|
|
image_features = preprocess_image(filepath)
|
|
|
|
# Prediksi dengan model KNN
|
|
prediction = model_knn.predict(image_features)
|
|
predicted_label = prediction[0]
|
|
|
|
# Menghitung probabilitas (akurasi) prediksi
|
|
probabilities = model_knn.predict_proba(image_features)
|
|
accuracy = np.max(probabilities)
|
|
|
|
# Peta label ke deskripsi
|
|
label_descriptions = {
|
|
'Healthy': "Ini adalah gambar buah kakao yang sehat.",
|
|
'Monilia': "Monilia disebabkan oleh jamur Moniliophthora roreri. solusi pertama dilakukan untuk Monilia secara penanganan sama dengan Phytophthora, namun jika ditemukan di Indonesia perlu adanya tindakan awal berupa eradikasi agar penyebab penyakit itu hilang sama sekali",
|
|
'Phytophthora': "Phytophthora disebabkan oleh jamur Phytophthora palmivora. Untuk penyakit Phytophtora: Solusi pertama dilakukan sanitasi buah yang terserang busuk buah walaupun terserang masih kecil dan di buang jauh dari tanaman kakao dengan cara memendam dengan timbunan lebih dari 30 cm. Kemudian dilakukan penyemprotan dengan fungisida terdaftar di Indonesia waktu itu atau bisa menggunakan bahan aktif Azoxystrobin sesuai dosis di label",
|
|
}
|
|
description = label_descriptions.get(predicted_label, "Tidak diketahui")
|
|
|
|
# Return hasil sebagai response JSON
|
|
return jsonify({
|
|
"filename": filename,
|
|
"predicted_label": predicted_label,
|
|
"description": description,
|
|
"accuracy": f"{accuracy * 100:.2f}%" # Akurasi dalam persen
|
|
})
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)})
|
|
else:
|
|
return jsonify({"error": "File type not allowed. Please upload PNG, JPG, or JPEG images."})
|
|
|
|
return render_template('identifikasi.html')
|
|
|
|
if __name__ == '__main__':
|
|
app.run(debug=True)
|