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/') 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)