581 lines
6.7 KiB
Python
581 lines
6.7 KiB
Python
from flask import Flask, request, jsonify
|
|
from flask_cors import CORS
|
|
import os
|
|
from datetime import datetime
|
|
import numpy as np
|
|
from PIL import Image
|
|
from tensorflow.keras.models import load_model
|
|
|
|
|
|
# ==========================================
|
|
# FLASK CONFIG
|
|
# ==========================================
|
|
|
|
app = Flask(__name__)
|
|
CORS(app)
|
|
|
|
|
|
# ==========================================
|
|
# FOLDER & MODEL
|
|
# ==========================================
|
|
|
|
UPLOAD_FOLDER = os.path.join(
|
|
os.path.dirname(__file__),
|
|
'uploads'
|
|
)
|
|
|
|
os.makedirs(
|
|
UPLOAD_FOLDER,
|
|
exist_ok=True
|
|
)
|
|
|
|
|
|
MODEL_PATH = os.path.join(
|
|
os.path.dirname(__file__),
|
|
'model_padi.h5'
|
|
)
|
|
|
|
|
|
|
|
# ==========================================
|
|
# CLASS SESUAI TRAINING MODEL
|
|
# ==========================================
|
|
|
|
CLASS_NAMES = [
|
|
|
|
'Healthy',
|
|
'Blast',
|
|
'Blight',
|
|
'Non-Padi',
|
|
'Tungro'
|
|
|
|
]
|
|
|
|
|
|
|
|
# ==========================================
|
|
# DESKRIPSI HASIL
|
|
# ==========================================
|
|
|
|
DESCRIPTIONS = {
|
|
|
|
|
|
'Healthy': {
|
|
|
|
'deskripsi':
|
|
'Daun padi dalam kondisi sehat.',
|
|
|
|
'solusi':
|
|
'Pertahankan pemupukan, pengairan, dan perawatan tanaman secara rutin.'
|
|
|
|
},
|
|
|
|
|
|
'Blast': {
|
|
|
|
'deskripsi':
|
|
'Blast merupakan penyakit daun padi yang disebabkan oleh jamur Pyricularia oryzae.',
|
|
|
|
'solusi':
|
|
'Gunakan fungisida dan varietas padi yang tahan terhadap penyakit blast.'
|
|
|
|
},
|
|
|
|
|
|
'Blight': {
|
|
|
|
'deskripsi':
|
|
'Blight merupakan penyakit hawar daun yang disebabkan oleh bakteri.',
|
|
|
|
'solusi':
|
|
'Gunakan benih sehat dan lakukan sanitasi lahan.'
|
|
|
|
},
|
|
|
|
|
|
'Tungro': {
|
|
|
|
'deskripsi':
|
|
'Tungro merupakan penyakit virus yang ditularkan oleh wereng hijau.',
|
|
|
|
'solusi':
|
|
'Lakukan pengendalian wereng dan gunakan varietas tahan tungro.'
|
|
|
|
},
|
|
|
|
|
|
'Non-Padi': {
|
|
|
|
'deskripsi':
|
|
'Gambar yang diunggah bukan daun padi.',
|
|
|
|
'solusi':
|
|
'Silakan upload gambar daun padi yang jelas.'
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# ==========================================
|
|
# LOAD MODEL
|
|
# ==========================================
|
|
|
|
model = None
|
|
|
|
|
|
try:
|
|
|
|
model = load_model(MODEL_PATH)
|
|
|
|
print("Model berhasil dimuat")
|
|
|
|
print(
|
|
"Input Shape :",
|
|
model.input_shape
|
|
)
|
|
|
|
print(
|
|
"Output Shape:",
|
|
model.output_shape
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print(
|
|
"Gagal load model:",
|
|
e
|
|
)
|
|
|
|
|
|
|
|
|
|
# ==========================================
|
|
# PREPROCESS IMAGE
|
|
# ==========================================
|
|
|
|
|
|
def preprocess_image(path):
|
|
|
|
image = Image.open(path)
|
|
|
|
image = image.convert('RGB')
|
|
|
|
|
|
image = image.resize(
|
|
(224,224)
|
|
)
|
|
|
|
|
|
image_array = np.array(image)
|
|
|
|
|
|
image_array = (
|
|
image_array.astype('float32')
|
|
/
|
|
255.0
|
|
)
|
|
|
|
|
|
image_array = np.expand_dims(
|
|
image_array,
|
|
axis=0
|
|
)
|
|
|
|
|
|
return image_array
|
|
|
|
|
|
|
|
|
|
|
|
# ==========================================
|
|
# TEST API
|
|
# ==========================================
|
|
|
|
|
|
@app.route('/')
|
|
|
|
|
|
def home():
|
|
|
|
return jsonify({
|
|
|
|
"status":
|
|
"API Klasifikasi Penyakit Daun Padi Aktif"
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
# ==========================================
|
|
# PREDIKSI
|
|
# ==========================================
|
|
|
|
|
|
@app.route(
|
|
'/prediksi',
|
|
methods=['POST']
|
|
)
|
|
|
|
|
|
def prediksi():
|
|
|
|
|
|
if 'gambar' not in request.files:
|
|
|
|
|
|
return jsonify({
|
|
|
|
"error":
|
|
"Tidak ada gambar dikirim"
|
|
|
|
}),400
|
|
|
|
|
|
|
|
|
|
file = request.files['gambar']
|
|
|
|
|
|
|
|
if file.filename == '':
|
|
|
|
|
|
return jsonify({
|
|
|
|
"error":
|
|
"File kosong"
|
|
|
|
}),400
|
|
|
|
|
|
|
|
|
|
|
|
filename = (
|
|
|
|
datetime.now()
|
|
.strftime('%Y%m%d%H%M%S_')
|
|
|
|
+
|
|
|
|
file.filename
|
|
|
|
)
|
|
|
|
|
|
|
|
filepath = os.path.join(
|
|
|
|
UPLOAD_FOLDER,
|
|
|
|
filename
|
|
|
|
)
|
|
|
|
|
|
|
|
file.save(filepath)
|
|
|
|
|
|
|
|
print("\n====================")
|
|
|
|
print(
|
|
"Gambar diterima:",
|
|
filename
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if model is None:
|
|
|
|
|
|
return jsonify({
|
|
|
|
"error":
|
|
"Model tidak tersedia"
|
|
|
|
}),500
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
# preprocessing
|
|
|
|
image_array = preprocess_image(filepath)
|
|
|
|
|
|
|
|
|
|
# prediksi
|
|
|
|
predictions = model.predict(
|
|
|
|
image_array,
|
|
|
|
verbose=0
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
predicted_index = int(
|
|
|
|
np.argmax(predictions[0])
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
confidence = float(
|
|
|
|
np.max(predictions[0])
|
|
|
|
)
|
|
|
|
confidence_percent = confidence * 100
|
|
|
|
|
|
|
|
|
|
label = CLASS_NAMES[
|
|
|
|
predicted_index
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
print("\nHASIL PREDIKSI")
|
|
|
|
|
|
for i,nama in enumerate(CLASS_NAMES):
|
|
|
|
|
|
print(
|
|
|
|
nama,
|
|
|
|
":",
|
|
|
|
round(
|
|
|
|
predictions[0][i]*100,
|
|
|
|
2
|
|
|
|
),
|
|
|
|
"%"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
print(
|
|
|
|
"HASIL AKHIR:",
|
|
|
|
label
|
|
|
|
)
|
|
|
|
|
|
|
|
print(
|
|
|
|
"CONFIDENCE:",
|
|
|
|
confidence_percent
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================
|
|
# FILTER GAMBAR TIDAK JELAS
|
|
# ==============================
|
|
|
|
|
|
if confidence_percent < 60:
|
|
|
|
|
|
return jsonify({
|
|
|
|
"error":
|
|
|
|
"Gambar tidak dikenali. Pastikan gambar daun padi."
|
|
|
|
}),400
|
|
|
|
|
|
|
|
|
|
# ==============================
|
|
# TOLAK NON PADI
|
|
# ==============================
|
|
|
|
|
|
if label == "Non-Padi":
|
|
|
|
|
|
return jsonify({
|
|
|
|
"error":
|
|
|
|
"Gambar bukan daun padi. Silakan upload daun padi."
|
|
|
|
}),400
|
|
|
|
|
|
|
|
|
|
|
|
all_predictions = {}
|
|
|
|
|
|
|
|
for i in range(len(CLASS_NAMES)):
|
|
|
|
|
|
all_predictions[
|
|
|
|
CLASS_NAMES[i]
|
|
|
|
] = round(
|
|
|
|
float(
|
|
|
|
predictions[0][i]*100
|
|
|
|
),
|
|
|
|
2
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
detail = DESCRIPTIONS[label]
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
|
|
"penyakit":
|
|
|
|
label,
|
|
|
|
|
|
|
|
"confidence":
|
|
|
|
f"{confidence_percent:.2f}%",
|
|
|
|
|
|
|
|
|
|
"all_predictions":
|
|
|
|
all_predictions,
|
|
|
|
|
|
|
|
|
|
"deskripsi":
|
|
|
|
detail['deskripsi'],
|
|
|
|
|
|
|
|
|
|
"solusi":
|
|
|
|
detail['solusi']
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(
|
|
|
|
"ERROR:",
|
|
|
|
e
|
|
|
|
)
|
|
|
|
|
|
return jsonify({
|
|
|
|
"error":
|
|
|
|
str(e)
|
|
|
|
}),500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==========================================
|
|
# RUN FLASK
|
|
# ==========================================
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
print("="*50)
|
|
|
|
print(
|
|
"Klasifikasi Penyakit Daun Padi"
|
|
)
|
|
|
|
print("="*50)
|
|
|
|
|
|
|
|
app.run(
|
|
|
|
host='127.0.0.1',
|
|
|
|
port=5000,
|
|
|
|
debug=False
|
|
|
|
) |