qonitasal commited on
Commit
152b780
·
verified ·
1 Parent(s): 7c1de4e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +128 -87
app.py CHANGED
@@ -1,91 +1,132 @@
1
- import os
2
- import cv2
3
- import numpy as np
4
  import gradio as gr
5
- import pandas as pd
6
  from ultralytics import YOLO
7
- from pathlib import Path
8
-
9
- # === Konfigurasi ===
10
- model_path = "best.pt" # Ganti dengan path model kamu
11
- class_names = ['coral or rock', 'pipeline', 'ripple marks', 'shipwreck']
12
- model = YOLO(model_path)
13
-
14
- # === Fungsi untuk menggambar prediksi lengkap ===
15
- def draw_predictions(img, segments, class_ids, confs, color=(255, 0, 0), alpha=0.5):
16
- overlay = img.copy()
17
- for i, seg in enumerate(segments):
18
- polygon = np.array(seg).reshape(-1, 2)
19
- polygon[:, 0] *= img.shape[1]
20
- polygon[:, 1] *= img.shape[0]
21
- polygon = polygon.astype(np.int32)
22
-
23
- cls_id = int(class_ids[i]) # pastikan integer
24
- conf = confs[i]
25
-
26
- # Draw mask
27
- cv2.fillPoly(overlay, [polygon], color)
28
-
29
- # Draw bounding box
30
- x, y, w, h = cv2.boundingRect(polygon)
31
- cv2.rectangle(overlay, (x, y), (x + w, y + h), color, 2)
32
-
33
- # Draw label + confidence
34
- label = f"{class_names[cls_id]} ({conf:.2f})"
35
- cv2.putText(overlay, label, (x, y - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 2)
36
-
37
- return cv2.addWeighted(overlay, alpha, img, 1 - alpha, 0)
38
-
39
- # === Fungsi proses gambar dan hasil deteksi ===
40
- def process_image_and_report(image):
41
- temp_path = "temp.jpg"
42
- image.save(temp_path)
43
- img = cv2.imread(temp_path)
44
- img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
45
-
46
- # === Prediksi menggunakan YOLOv8
47
- results = model(temp_path)[0]
48
- segs = [seg.xy for seg in results.masks] if results.masks else []
49
- cls_ids = results.boxes.cls.tolist() if results.boxes else []
50
- confs = results.boxes.conf.tolist() if results.boxes else []
51
- xywh = results.boxes.xywhn.tolist() if results.boxes else []
52
-
53
- # === Visualisasi prediksi
54
- img_pred = draw_predictions(img.copy(), segs, cls_ids, confs)
55
-
56
- # === Buat laporan CSV
57
- rows = []
58
- for i in range(len(cls_ids)):
59
- rows.append({
60
- "Filename": Path(temp_path).name,
61
- "Class": class_names[int(cls_ids[i])],
62
- "Confidence": round(float(confs[i]), 4),
63
- "X_center": round(xywh[i][0], 4),
64
- "Y_center": round(xywh[i][1], 4),
65
- "Width": round(xywh[i][2], 4),
66
- "Height": round(xywh[i][3], 4),
67
- })
68
-
69
- df = pd.DataFrame(rows)
70
- csv_path = "detection_report.csv"
71
- df.to_csv(csv_path, index=False)
72
-
73
- return img_pred, csv_path
74
-
75
- # === Gradio UI ===
76
- with gr.Blocks() as demo:
77
- gr.Markdown("## 🧠 YOLOv8 Segmentation Viewer + Detection Report")
78
- gr.Markdown("Upload image → lihat hasil deteksi (mask, box, label, confidence) → unduh CSV")
79
-
80
- with gr.Row():
81
- with gr.Column():
82
- image_input = gr.Image(type="pil", label="Upload Image")
83
- submit_btn = gr.Button("Predict and Generate Report")
84
- with gr.Column():
85
- image_output = gr.Image(type="numpy", label="Prediction Result")
86
- download_csv = gr.File(label="Download Detection CSV")
87
-
88
- submit_btn.click(fn=process_image_and_report, inputs=image_input, outputs=[image_output, download_csv])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  if __name__ == "__main__":
91
- demo.launch()
 
 
 
 
1
  import gradio as gr
2
+ from PIL import Image, ImageDraw, ImageFont
3
  from ultralytics import YOLO
4
+ import numpy as np
5
+ import os
6
+
7
+ # Load model
8
+ try:
9
+ model_path = "best.pt"
10
+ if not os.path.exists(model_path):
11
+ raise FileNotFoundError(f"❌ File {model_path} tidak ditemukan. Upload 'best.pt' ke root.")
12
+ model = YOLO(model_path)
13
+ print("✅ Model loaded successfully!")
14
+ except Exception as e:
15
+ print("❌ Gagal load model:", e)
16
+ model = None
17
+
18
+ # Label dan Warna untuk tiap class
19
+ label_map = {
20
+ 0: "coral or rock",
21
+ 1: "pipeline",
22
+ 2: "ripple marks",
23
+ 3: "shipwreck"
24
+ }
25
+
26
+ color_map = {
27
+ 0: (0, 255, 0), # coral or rock - hijau
28
+ 1: (255, 0, 0), # pipeline - merah
29
+ 2: (255, 165, 0), # ripple marks - oranye
30
+ 3: (0, 0, 255) # shipwreck - biru
31
+ }
32
+
33
+ def predict_segmentation_with_legend(image):
34
+ try:
35
+ if model is None:
36
+ print("❌ Model belum dimuat.")
37
+ return image
38
+
39
+ image = image.convert("RGB")
40
+ print("📥 Gambar diterima:", image.size)
41
+
42
+ results = model.predict(image, conf=0.0, iou=0.5)
43
+ result = results[0]
44
+
45
+ masks = result.masks.data.cpu().numpy() if result.masks else []
46
+ boxes = result.boxes.xyxy.cpu().numpy() if result.boxes else []
47
+ scores = result.boxes.conf.cpu().numpy() if result.boxes else []
48
+ class_ids = result.boxes.cls.cpu().numpy().astype(int) if result.boxes else []
49
+
50
+ image_np = np.array(image).copy()
51
+ draw = ImageDraw.Draw(image)
52
+
53
+ try:
54
+ font = ImageFont.truetype("DejaVuSans.ttf", 18)
55
+ except:
56
+ font = ImageFont.load_default()
57
+
58
+ CONFIDENCE_THRESHOLD = 0.5
59
+
60
+ if len(boxes) == 0:
61
+ draw.text((10, 10), "No detections", fill="red", font=font)
62
+ return image
63
+
64
+ indices_to_use = [i for i, s in enumerate(scores) if s >= CONFIDENCE_THRESHOLD]
65
+
66
+ if len(indices_to_use) == 0:
67
+ top_idx = int(np.argmax(scores))
68
+ indices_to_use = [top_idx]
69
+
70
+ # Tampilkan mask
71
+ for i in indices_to_use:
72
+ mask = masks[i]
73
+ class_id = class_ids[i]
74
+ color = color_map.get(class_id, (255, 255, 0))
75
+ mask_pil = Image.fromarray((mask * 255).astype(np.uint8))
76
+ mask_resized = mask_pil.resize((image_np.shape[1], image_np.shape[0]), resample=Image.BILINEAR)
77
+ mask_resized = np.array(mask_resized) / 255.0
78
+
79
+ color_mask = np.zeros_like(image_np)
80
+ for c in range(3):
81
+ color_mask[:, :, c] = mask_resized * color[c]
82
+
83
+ image_np = np.where(mask_resized[..., None] > 0.5,
84
+ image_np * 0.5 + color_mask * 0.5, image_np)
85
+
86
+ final_image = Image.fromarray(image_np.astype(np.uint8))
87
+ draw = ImageDraw.Draw(final_image)
88
+
89
+ # Tampilkan box & label
90
+ for i in indices_to_use:
91
+ box = boxes[i].astype(int).tolist()
92
+ score = scores[i]
93
+ class_id = class_ids[i]
94
+ label = label_map.get(class_id, str(class_id))
95
+ color = color_map.get(class_id, (255, 255, 0))
96
+ text_color = "white" if score >= CONFIDENCE_THRESHOLD else "gray"
97
+
98
+ draw.rectangle(box, outline=color, width=2)
99
+ draw.text((box[0], box[1] - 30), label, fill=text_color, font=font)
100
+ draw.text((box[0], box[1] - 10), f"Confidence: {score:.2f}", fill=text_color, font=font)
101
+
102
+ # Buat legenda
103
+ legend = Image.new("RGB", (500, 50), (255, 255, 255))
104
+ draw_legend = ImageDraw.Draw(legend)
105
+ x = 10
106
+ for cid, label in label_map.items():
107
+ draw_legend.rectangle([x, 10, x + 20, 30], fill=color_map[cid])
108
+ draw_legend.text((x + 25, 10), label, fill="black", font=font)
109
+ x += 130
110
+
111
+ # Gabungkan dengan gambar
112
+ combined = Image.new("RGB", (final_image.width, final_image.height + 50), (255, 255, 255))
113
+ combined.paste(final_image, (0, 0))
114
+ combined.paste(legend, (10, final_image.height))
115
+
116
+ return combined
117
+
118
+ except Exception as e:
119
+ print("❌ Error saat segmentasi:", e)
120
+ return image
121
+
122
+ iface = gr.Interface(
123
+ fn=predict_segmentation_with_legend,
124
+ inputs=gr.Image(type="pil", label="Upload Citra Side Scan Sonar"),
125
+ outputs=gr.Image(type="pil", label="Hasil Segmentasi"),
126
+ title="YOLOv11 Segmentasi Citra Sonar",
127
+ description="Upload citra sonar dan dapatkan hasil segmentasi lengkap dengan warna mask, label, confidence, dan legenda warna.",
128
+ allow_flagging="never"
129
+ )
130
 
131
  if __name__ == "__main__":
132
+ iface.launch(share=True)