muhammadsalmanalfaridzi commited on
Commit
f46a5a0
·
verified ·
1 Parent(s): f280e18

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -28
app.py CHANGED
@@ -26,7 +26,7 @@ rf = Roboflow(api_key=rf_api_key)
26
  project = rf.workspace(workspace).project(project_name)
27
  yolo_model = project.version(model_version).model
28
 
29
- # ========== Fungsi untuk Mengecek Overlap ==========
30
  def is_overlap(box1, boxes2, threshold=0.3):
31
  """
32
  Mengecek apakah box1 (format: (x_min, y_min, x_max, y_max)) overlap dengan salah satu box di boxes2.
@@ -50,67 +50,87 @@ def is_overlap(box1, boxes2, threshold=0.3):
50
  return True
51
  return False
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  # ========== Fungsi Deteksi Kombinasi ==========
54
  def detect_combined(image):
55
- # Simpan image ke file sementara
56
  with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file:
57
  image.save(temp_file, format="JPEG")
58
  temp_path = temp_file.name
59
-
60
  try:
61
  # ===== YOLO Detection (Produk Nestlé) =====
62
  yolo_pred = yolo_model.predict(temp_path, confidence=50, overlap=80).json()
63
  nestle_class_count = {}
64
- nestle_boxes = [] # Menyimpan bounding box YOLO (format: x_center, y_center, width, height)
65
  for pred in yolo_pred['predictions']:
66
  class_name = pred['class']
67
  nestle_class_count[class_name] = nestle_class_count.get(class_name, 0) + 1
68
  nestle_boxes.append((pred['x'], pred['y'], pred['width'], pred['height']))
69
  total_nestle = sum(nestle_class_count.values())
70
-
71
  # ===== CountGD Detection (Produk Kompetitor) =====
72
  url = "https://api.landing.ai/v1/tools/text-to-object-detection"
73
  competitor_class_count = {}
74
- competitor_boxes = [] # Menyimpan bounding box CountGD (format: x_min, y_min, x_max, y_max)
75
  # Daftar prompt yang akan digunakan
76
  COUNTGD_PROMPTS = ["cans", "bottle", "mixed box"]
77
  headers = {"Authorization": f"Basic {COUNTGD_API_KEY}"}
78
 
79
  for prompt in COUNTGD_PROMPTS:
80
- # Untuk setiap prompt, buka file gambar dan kirim request
81
  with open(temp_path, "rb") as f:
82
  files = {"image": f}
83
  data = {"prompts": [prompt], "model": "countgd"}
84
  response = requests.post(url, files=files, data=data, headers=headers)
85
  result = response.json()
86
- # Cek apakah API mengembalikan data
87
  if 'data' in result and result['data']:
88
  detections = result['data'][0]
89
  for obj in detections:
90
  if 'bounding_box' in obj:
91
  x1, y1, x2, y2 = obj['bounding_box']
92
  countgd_box = (x1, y1, x2, y2)
93
- # Hanya tambahkan deteksi jika tidak overlap signifikan dengan YOLO
94
  if not is_overlap(countgd_box, nestle_boxes, threshold=0.3):
95
- # Gunakan label dari respons jika ada, jika tidak gunakan prompt sebagai default
96
- label = obj.get('label', prompt)
97
- competitor_class_count[label] = competitor_class_count.get(label, 0) + 1
98
- competitor_boxes.append(countgd_box)
 
 
 
 
 
 
 
99
  total_competitor = sum(competitor_class_count.values())
100
-
101
  # ===== Format Output Text =====
102
  result_text = "Product Nestlé\n\n"
103
  for class_name, count in nestle_class_count.items():
104
  result_text += f"{class_name}: {count}\n"
105
  result_text += f"\nTotal Products Nestlé: {total_nestle}\n\n"
106
  if total_competitor:
107
- result_text += "Produk Kompetitor (CountGD):\n"
108
- for label, count in competitor_class_count.items():
109
- result_text += f"{label}: {count}\n"
110
- result_text += f"\nTotal Produk Kompetitor: {total_competitor}\n"
111
  else:
112
  result_text += "No Unclassified Products detected\n"
113
-
114
  # ===== Visualisasi =====
115
  img = cv2.imread(temp_path)
116
  # Gambar bounding box YOLO (hijau)
@@ -127,14 +147,14 @@ def detect_combined(image):
127
  cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 2)
128
  cv2.putText(img, "unclassified", (int(x1), int(y1)-10),
129
  cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0,0,255), 3)
130
-
131
  output_path = "/tmp/combined_output.jpg"
132
  cv2.imwrite(output_path, img)
133
  return output_path, result_text
134
-
135
  except Exception as e:
136
  return temp_path, f"Error: {str(e)}"
137
-
138
  finally:
139
  if os.path.exists(temp_path):
140
  os.remove(temp_path)
@@ -160,14 +180,12 @@ def detect_objects_in_video(video_path):
160
  if not video_path:
161
  return None, f"Video conversion error: {err}"
162
 
163
- # Buka video untuk diproses
164
  video = cv2.VideoCapture(video_path)
165
  frame_rate = int(video.get(cv2.CAP_PROP_FPS))
166
  frame_width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
167
  frame_height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
168
  frame_size = (frame_width, frame_height)
169
 
170
- # Setup VideoWriter untuk output
171
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
172
  output_video = cv2.VideoWriter(temp_output_path, fourcc, frame_rate, frame_size)
173
 
@@ -176,14 +194,11 @@ def detect_objects_in_video(video_path):
176
  if not ret:
177
  break
178
 
179
- # Simpan frame untuk deteksi YOLO
180
  frame_path = os.path.join(temp_frames_dir, f"frame_{frame_count}.jpg")
181
  cv2.imwrite(frame_path, frame)
182
 
183
- # YOLO detection pada frame
184
  predictions = yolo_model.predict(frame_path, confidence=50, overlap=80).json()
185
 
186
- # Gambar deteksi YOLO pada frame
187
  current_detections = {}
188
  for prediction in predictions['predictions']:
189
  class_name = prediction['class']
@@ -197,7 +212,6 @@ def detect_objects_in_video(video_path):
197
  cv2.putText(frame, class_name, (pt1[0], pt1[1]-10),
198
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2)
199
 
200
- # Hitung dan tampilkan jumlah deteksi pada frame
201
  object_counts = {}
202
  for detection_id in current_detections:
203
  cls = current_detections[detection_id]
 
26
  project = rf.workspace(workspace).project(project_name)
27
  yolo_model = project.version(model_version).model
28
 
29
+ # ========== Fungsi untuk Mengecek Overlap antara YOLO dan CountGD ==========
30
  def is_overlap(box1, boxes2, threshold=0.3):
31
  """
32
  Mengecek apakah box1 (format: (x_min, y_min, x_max, y_max)) overlap dengan salah satu box di boxes2.
 
50
  return True
51
  return False
52
 
53
+ # ========== Fungsi untuk Menghitung IoU antar dua bounding box ==========
54
+ def iou(boxA, boxB):
55
+ """
56
+ Menghitung Intersection over Union (IoU) antara dua bounding box.
57
+ Masing-masing box dalam format (x_min, y_min, x_max, y_max).
58
+ """
59
+ xA = max(boxA[0], boxB[0])
60
+ yA = max(boxA[1], boxB[1])
61
+ xB = min(boxA[2], boxB[2])
62
+ yB = min(boxA[3], boxB[3])
63
+ interArea = max(0, xB - xA) * max(0, yB - yA)
64
+ boxAArea = (boxA[2] - boxA[0]) * (boxA[3] - boxA[1])
65
+ boxBArea = (boxB[2] - boxB[0]) * (boxB[3] - boxB[1])
66
+ iou_val = interArea / float(boxAArea + boxBArea - interArea) if (boxAArea + boxBArea - interArea) > 0 else 0
67
+ return iou_val
68
+
69
  # ========== Fungsi Deteksi Kombinasi ==========
70
  def detect_combined(image):
 
71
  with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file:
72
  image.save(temp_file, format="JPEG")
73
  temp_path = temp_file.name
74
+
75
  try:
76
  # ===== YOLO Detection (Produk Nestlé) =====
77
  yolo_pred = yolo_model.predict(temp_path, confidence=50, overlap=80).json()
78
  nestle_class_count = {}
79
+ nestle_boxes = [] # List untuk menyimpan bounding box YOLO (format: x_center, y_center, width, height)
80
  for pred in yolo_pred['predictions']:
81
  class_name = pred['class']
82
  nestle_class_count[class_name] = nestle_class_count.get(class_name, 0) + 1
83
  nestle_boxes.append((pred['x'], pred['y'], pred['width'], pred['height']))
84
  total_nestle = sum(nestle_class_count.values())
85
+
86
  # ===== CountGD Detection (Produk Kompetitor) =====
87
  url = "https://api.landing.ai/v1/tools/text-to-object-detection"
88
  competitor_class_count = {}
89
+ competitor_boxes = [] # List untuk menyimpan bounding box CountGD (format: x_min, y_min, x_max, y_max)
90
  # Daftar prompt yang akan digunakan
91
  COUNTGD_PROMPTS = ["cans", "bottle", "mixed box"]
92
  headers = {"Authorization": f"Basic {COUNTGD_API_KEY}"}
93
 
94
  for prompt in COUNTGD_PROMPTS:
 
95
  with open(temp_path, "rb") as f:
96
  files = {"image": f}
97
  data = {"prompts": [prompt], "model": "countgd"}
98
  response = requests.post(url, files=files, data=data, headers=headers)
99
  result = response.json()
 
100
  if 'data' in result and result['data']:
101
  detections = result['data'][0]
102
  for obj in detections:
103
  if 'bounding_box' in obj:
104
  x1, y1, x2, y2 = obj['bounding_box']
105
  countgd_box = (x1, y1, x2, y2)
106
+ # Hanya tambahkan deteksi jika tidak overlap dengan deteksi YOLO
107
  if not is_overlap(countgd_box, nestle_boxes, threshold=0.3):
108
+ # Cek duplikasi antar deteksi CountGD menggunakan IoU
109
+ duplicate = False
110
+ for existing_box in competitor_boxes:
111
+ if iou(countgd_box, existing_box) > 0.5:
112
+ duplicate = True
113
+ break
114
+ if not duplicate:
115
+ # Gunakan label dari respons jika ada, jika tidak gunakan prompt sebagai default
116
+ label = obj.get('label', prompt)
117
+ competitor_class_count[label] = competitor_class_count.get(label, 0) + 1
118
+ competitor_boxes.append(countgd_box)
119
  total_competitor = sum(competitor_class_count.values())
120
+
121
  # ===== Format Output Text =====
122
  result_text = "Product Nestlé\n\n"
123
  for class_name, count in nestle_class_count.items():
124
  result_text += f"{class_name}: {count}\n"
125
  result_text += f"\nTotal Products Nestlé: {total_nestle}\n\n"
126
  if total_competitor:
127
+ #result_text += "Produk Kompetitor (CountGD):\n"
128
+ #for label, count in competitor_class_count.items():
129
+ # result_text += f"{label}: {count}\n"
130
+ result_text += f"\nTotal Unclassified Products: {total_competitor}\n"
131
  else:
132
  result_text += "No Unclassified Products detected\n"
133
+
134
  # ===== Visualisasi =====
135
  img = cv2.imread(temp_path)
136
  # Gambar bounding box YOLO (hijau)
 
147
  cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 2)
148
  cv2.putText(img, "unclassified", (int(x1), int(y1)-10),
149
  cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0,0,255), 3)
150
+
151
  output_path = "/tmp/combined_output.jpg"
152
  cv2.imwrite(output_path, img)
153
  return output_path, result_text
154
+
155
  except Exception as e:
156
  return temp_path, f"Error: {str(e)}"
157
+
158
  finally:
159
  if os.path.exists(temp_path):
160
  os.remove(temp_path)
 
180
  if not video_path:
181
  return None, f"Video conversion error: {err}"
182
 
 
183
  video = cv2.VideoCapture(video_path)
184
  frame_rate = int(video.get(cv2.CAP_PROP_FPS))
185
  frame_width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
186
  frame_height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
187
  frame_size = (frame_width, frame_height)
188
 
 
189
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
190
  output_video = cv2.VideoWriter(temp_output_path, fourcc, frame_rate, frame_size)
191
 
 
194
  if not ret:
195
  break
196
 
 
197
  frame_path = os.path.join(temp_frames_dir, f"frame_{frame_count}.jpg")
198
  cv2.imwrite(frame_path, frame)
199
 
 
200
  predictions = yolo_model.predict(frame_path, confidence=50, overlap=80).json()
201
 
 
202
  current_detections = {}
203
  for prediction in predictions['predictions']:
204
  class_name = prediction['class']
 
212
  cv2.putText(frame, class_name, (pt1[0], pt1[1]-10),
213
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2)
214
 
 
215
  object_counts = {}
216
  for detection_id in current_detections:
217
  cls = current_detections[detection_id]