IDRiD / app.py
kodetr's picture
Update app.py
de4b776 verified
raw
history blame
7.97 kB
import tensorflow as tf
import gradio as gr
import numpy as np
import os
import warnings
from PIL import Image
warnings.filterwarnings("ignore")
# ============================================================
# 1. LOAD MODEL
# ============================================================
print("=" * 60)
print("LOADING MODEL")
print("=" * 60)
MODEL_PATH = "model.keras"
try:
best_model = tf.keras.models.load_model(
MODEL_PATH,
custom_objects={"quantization_config": None},
compile=False
)
print("βœ… Model berhasil dimuat")
except Exception as e:
print("❌ Pemuatan model gagal, membuat model dummy:", e)
from tensorflow.keras import layers, Model
inputs = layers.Input(shape=(224, 224, 3))
x = layers.GlobalAveragePooling2D()(inputs)
dr_output = layers.Dense(5, name="dr_head")(x) # logits
dme_output = layers.Dense(3, name="dme_head")(x) # logits
best_model = Model(inputs, {"dr_head": dr_output, "dme_head": dme_output})
best_model.compile(optimizer="adam", loss="categorical_crossentropy")
best_model.summary()
# ============================================================
# 2. CONFIG
# ============================================================
IMG_SIZE = 224
# ============================================================
# 3. PREPROCESSING
# ============================================================
def preprocess_image(img_path):
img = tf.io.read_file(img_path)
img = tf.image.decode_jpeg(img, channels=3)
img = tf.image.resize(img, (IMG_SIZE, IMG_SIZE))
img = tf.cast(img, tf.float32) / 255.0
return tf.expand_dims(img, 0)
# ============================================================
# 4. CLASS MAPPING
# ============================================================
DR_CLASSES = ["No DR", "Mild", "Moderate", "Severe", "Proliferative DR"]
DME_CLASSES = ["No DME", "Low Risk", "High Risk"]
# ============================================================
# 5. SOFTMAX SAFETY
# ============================================================
def ensure_probability(x):
x = np.asarray(x, dtype=np.float32)
if x.min() < 0 or x.max() > 1.0 or abs(x.sum() - 1.0) > 1e-3:
x = tf.nn.softmax(x).numpy()
return x
# ============================================================
# 6. PREDICTION β†’ TABLE ONLY
# ============================================================
def predict_and_format_text(image_path):
img_tensor = preprocess_image(image_path)
preds = best_model.predict(img_tensor, verbose=0)
# ---- handle output model ----
if isinstance(preds, dict):
dr_key, dme_key = None, None
for k in preds.keys():
lk = k.lower()
if "dr" in lk:
dr_key = k
if "dme" in lk:
dme_key = k
dr_pred = preds[dr_key][0]
dme_pred = preds[dme_key][0]
elif isinstance(preds, (list, tuple)):
dr_pred = preds[0][0]
dme_pred = preds[1][0]
elif isinstance(preds, np.ndarray):
dr_pred = preds[0][:5]
dme_pred = preds[0][5:]
else:
raise ValueError("Format output model tidak dikenali")
# ---- softmax ----
dr_pred = ensure_probability(dr_pred)
dme_pred = ensure_probability(dme_pred)
# ---- result ----
dr_idx = int(np.argmax(dr_pred))
dme_idx = int(np.argmax(dme_pred))
dr_name = DR_CLASSES[dr_idx]
dme_name = DME_CLASSES[dme_idx]
dr_conf = dr_pred[dr_idx] * 100
dme_conf = dme_pred[dme_idx] * 100
# ======================================================
# πŸ”₯ JUDUL UTAMA
# ======================================================
main_result = f"""
<div style="text-align:center; font-size:30px; font-weight:800; margin-bottom:20px;">
HASIL PREDIKSI
</div>
"""
# ======================================================
# πŸ“Š TABEL HASIL
# ======================================================
table_result = f"""
<table style="width:100%; border-collapse:collapse; font-size:16px;">
<thead>
<tr style="background-color:#f2f2f2;">
<th style="border:1px solid #ccc; padding:8px;">Aspek</th>
<th style="border:1px solid #ccc; padding:8px;">Klasifikasi</th>
<th style="border:1px solid #ccc; padding:8px;">Confidence (%)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="border:1px solid #ccc; padding:8px;">Diabetic Retinopathy (DR)</td>
<td style="border:1px solid #ccc; padding:8px;"><b>{dr_name}</b></td>
<td style="border:1px solid #ccc; padding:8px;">{dr_conf:.2f}%</td>
</tr>
<tr>
<td style="border:1px solid #ccc; padding:8px;">Diabetic Macular Edema (DME)</td>
<td style="border:1px solid #ccc; padding:8px;"><b>{dme_name}</b></td>
<td style="border:1px solid #ccc; padding:8px;">{dme_conf:.2f}%</td>
</tr>
</tbody>
</table>
"""
# ======================================================
# 🩺 REKOMENDASI (DINAMIS)
# ======================================================
# Rekomendasi DR
if dr_name in ["No DR"]:
rec_dr = "Lanjutkan pola hidup sehat dan lakukan pemeriksaan mata rutin minimal 1 tahun sekali."
elif dr_name in ["Mild", "Moderate"]:
rec_dr = "Disarankan kontrol gula darah secara ketat dan pemeriksaan mata berkala setiap 6 bulan."
else: # Severe / Proliferative
rec_dr = "Disarankan segera konsultasi ke dokter spesialis mata untuk evaluasi dan penanganan lebih lanjut."
# Rekomendasi DME
if dme_name == "No DME":
rec_dme = "Belum ditemukan tanda edema makula diabetik, lanjutkan pemantauan rutin."
elif dme_name == "Low Risk":
rec_dme = "Perlu observasi ketat dan pemeriksaan lanjutan untuk mencegah progresivitas."
else: # High Risk
rec_dme = "Disarankan segera mendapatkan evaluasi klinis dan terapi oleh dokter spesialis mata."
recommendation = f"""
<div style="margin-top:20px; padding:15px; border-left:5px solid #007bff; background-color:#f9f9f9;">
<b>🩺 Rekomendasi Klinis:</b><br/><br/>
<b>β€’ Diabetic Retinopathy (DR):</b><br/>
{rec_dr}<br/><br/>
<b>β€’ Diabetic Macular Edema (DME):</b><br/>
{rec_dme}
</div>
"""
return main_result + table_result + recommendation
# ============================================================
# 7. MULTI TEST IMAGES
# ============================================================
TEST_IMAGES = [
"IDRiD_001test.jpg",
"IDRiD_004test.jpg",
"IDRiD_005test.jpg",
"IDRiD_006test.jpg",
"IDRiD_007test.jpg",
"IDRiD_008test.jpg",
"IDRiD_009test.jpg",
"IDRiD_010test.jpg",
"IDRiD_011test.jpg",
"IDRiD_012test.jpg",
]
TEST_IMAGES = [[p] for p in TEST_IMAGES if os.path.exists(p)]
# ============================================================
# 8. GRADIO WRAPPER
# ============================================================
def gradio_predict(image):
if image is None:
return "❌ Silakan unggah gambar"
temp_path = "uploaded.jpg"
image.save(temp_path)
return predict_and_format_text(temp_path)
# ============================================================
# 9. GRADIO UI
# ============================================================
with gr.Blocks(title="DR & DME Detection") as demo:
gr.Markdown("""
# 🩺 Diabetic Retinopathy Image Dataset (IDRiD)
""")
with gr.Row():
with gr.Column():
input_img = gr.Image(type="pil", label="Upload Gambar Retina")
btn = gr.Button("πŸ” Prediksi")
with gr.Column():
out_text = gr.Markdown()
gr.Markdown("### πŸ§ͺ Data Testing")
gr.Examples(
examples=TEST_IMAGES,
inputs=input_img
)
btn.click(
fn=gradio_predict,
inputs=input_img,
outputs=out_text
)
# ============================================================
# 10. LAUNCH
# ============================================================
demo.launch(share=True)