heerjtdev commited on
Commit
3843dd0
·
verified ·
1 Parent(s): 3dd4c9e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -34
app.py CHANGED
@@ -1155,7 +1155,99 @@ IOA_SUPPRESSION_THRESHOLD = 0.7
1155
  # --- BOX COMBINATION LOGIC (PURE VERTICAL FIX) ---
1156
  # ============================================================================
1157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1158
  def calculate_iou(box1, box2):
 
1159
  x1_a, y1_a, x2_a, y2_a = box1
1160
  x1_b, y1_b, x2_b, y2_b = box2
1161
  x_left = max(x1_a, x1_b)
@@ -1169,67 +1261,143 @@ def calculate_iou(box1, box2):
1169
  return intersection_area / union_area if union_area > 0 else 0
1170
 
1171
 
1172
- def filter_nested_boxes(detections, ioa_threshold=0.80):
1173
- if not detections: return []
1174
- for d in detections:
1175
- x1, y1, x2, y2 = d['coords']
1176
- d['area'] = (x2 - x1) * (y2 - y1)
1177
- detections.sort(key=lambda x: x['area'], reverse=True)
1178
- keep_indices = []
1179
- is_suppressed = [False] * len(detections)
1180
- for i in range(len(detections)):
1181
- if is_suppressed[i]: continue
1182
- keep_indices.append(i)
1183
- box_a = detections[i]['coords']
1184
- for j in range(i + 1, len(detections)):
1185
- if is_suppressed[j]: continue
1186
- box_b = detections[j]['coords']
1187
- x_left = max(box_a[0], box_b[0])
1188
- y_top = max(box_a[1], box_b[1])
1189
- x_right = min(box_a[2], box_b[2])
1190
- y_bottom = min(box_a[3], box_b[3])
1191
- intersection = max(0, x_right - x_left) * max(0, y_bottom - y_top)
1192
- area_b = detections[j]['area']
1193
- if area_b > 0 and intersection / area_b > ioa_threshold:
1194
- is_suppressed[j] = True
1195
- return [detections[i] for i in keep_indices]
1196
 
1197
 
1198
- # --- UPDATED: page_width argument removed ---
1199
  def merge_overlapping_boxes(detections, iou_threshold):
1200
- if not detections: return []
 
 
 
 
 
 
 
1201
  detections.sort(key=lambda d: d['conf'], reverse=True)
 
1202
  merged_detections = []
1203
  is_merged = [False] * len(detections)
1204
 
1205
  for i in range(len(detections)):
1206
- if is_merged[i]: continue
 
 
1207
  current_box = detections[i]['coords']
1208
  current_class = detections[i]['class']
1209
  merged_x1, merged_y1, merged_x2, merged_y2 = current_box
 
 
1210
  for j in range(i + 1, len(detections)):
1211
- if is_merged[j] or detections[j]['class'] != current_class: continue
 
 
1212
  other_box = detections[j]['coords']
1213
  iou = calculate_iou(current_box, other_box)
 
1214
  if iou > iou_threshold:
 
1215
  merged_x1 = min(merged_x1, other_box[0])
1216
  merged_y1 = min(merged_y1, other_box[1])
1217
  merged_x2 = max(merged_x2, other_box[2])
1218
- merged_y2 = max(merged_y2, other_box[3])
1219
  is_merged[j] = True
 
1220
  merged_detections.append({
1221
  'coords': (merged_x1, merged_y1, merged_x2, merged_y2),
1222
- 'y1': merged_y1,
1223
- 'class': current_class,
1224
  'conf': detections[i]['conf']
1225
  })
1226
 
1227
- # --- PURE VERTICAL FIX IMPLEMENTATION ---
1228
- # Sort ONLY by the top y-coordinate (coords[1]).
1229
- # This ignores horizontal position and any complex layout.
1230
  merged_detections.sort(key=lambda d: d['coords'][1])
1231
 
1232
  return merged_detections
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1233
 
1234
  # ============================================================================
1235
  # --- UTILITY FUNCTIONS (Retained) ---
 
1155
  # --- BOX COMBINATION LOGIC (PURE VERTICAL FIX) ---
1156
  # ============================================================================
1157
 
1158
+ # def calculate_iou(box1, box2):
1159
+ # x1_a, y1_a, x2_a, y2_a = box1
1160
+ # x1_b, y1_b, x2_b, y2_b = box2
1161
+ # x_left = max(x1_a, x1_b)
1162
+ # y_top = max(y1_a, y1_b)
1163
+ # x_right = min(x2_a, x2_b)
1164
+ # y_bottom = min(y2_a, y2_b)
1165
+ # intersection_area = max(0, x_right - x_left) * max(0, y_bottom - y_top)
1166
+ # box_a_area = (x2_a - x1_a) * (y2_a - y1_a)
1167
+ # box_b_area = (x2_b - x1_b) * (y2_b - y1_b)
1168
+ # union_area = float(box_a_area + box_b_area - intersection_area)
1169
+ # return intersection_area / union_area if union_area > 0 else 0
1170
+
1171
+
1172
+ # def filter_nested_boxes(detections, ioa_threshold=0.80):
1173
+ # if not detections: return []
1174
+ # for d in detections:
1175
+ # x1, y1, x2, y2 = d['coords']
1176
+ # d['area'] = (x2 - x1) * (y2 - y1)
1177
+ # detections.sort(key=lambda x: x['area'], reverse=True)
1178
+ # keep_indices = []
1179
+ # is_suppressed = [False] * len(detections)
1180
+ # for i in range(len(detections)):
1181
+ # if is_suppressed[i]: continue
1182
+ # keep_indices.append(i)
1183
+ # box_a = detections[i]['coords']
1184
+ # for j in range(i + 1, len(detections)):
1185
+ # if is_suppressed[j]: continue
1186
+ # box_b = detections[j]['coords']
1187
+ # x_left = max(box_a[0], box_b[0])
1188
+ # y_top = max(box_a[1], box_b[1])
1189
+ # x_right = min(box_a[2], box_b[2])
1190
+ # y_bottom = min(box_a[3], box_b[3])
1191
+ # intersection = max(0, x_right - x_left) * max(0, y_bottom - y_top)
1192
+ # area_b = detections[j]['area']
1193
+ # if area_b > 0 and intersection / area_b > ioa_threshold:
1194
+ # is_suppressed[j] = True
1195
+ # return [detections[i] for i in keep_indices]
1196
+
1197
+
1198
+ # # --- UPDATED: page_width argument removed ---
1199
+ # def merge_overlapping_boxes(detections, iou_threshold):
1200
+ # if not detections: return []
1201
+ # detections.sort(key=lambda d: d['conf'], reverse=True)
1202
+ # merged_detections = []
1203
+ # is_merged = [False] * len(detections)
1204
+
1205
+ # for i in range(len(detections)):
1206
+ # if is_merged[i]: continue
1207
+ # current_box = detections[i]['coords']
1208
+ # current_class = detections[i]['class']
1209
+ # merged_x1, merged_y1, merged_x2, merged_y2 = current_box
1210
+ # for j in range(i + 1, len(detections)):
1211
+ # if is_merged[j] or detections[j]['class'] != current_class: continue
1212
+ # other_box = detections[j]['coords']
1213
+ # iou = calculate_iou(current_box, other_box)
1214
+ # if iou > iou_threshold:
1215
+ # merged_x1 = min(merged_x1, other_box[0])
1216
+ # merged_y1 = min(merged_y1, other_box[1])
1217
+ # merged_x2 = max(merged_x2, other_box[2])
1218
+ # merged_y2 = max(merged_y2, other_box[3])
1219
+ # is_merged[j] = True
1220
+ # merged_detections.append({
1221
+ # 'coords': (merged_x1, merged_y1, merged_x2, merged_y2),
1222
+ # 'y1': merged_y1,
1223
+ # 'class': current_class,
1224
+ # 'conf': detections[i]['conf']
1225
+ # })
1226
+
1227
+ # # --- PURE VERTICAL FIX IMPLEMENTATION ---
1228
+ # # Sort ONLY by the top y-coordinate (coords[1]).
1229
+ # # This ignores horizontal position and any complex layout.
1230
+ # merged_detections.sort(key=lambda d: d['coords'][1])
1231
+
1232
+ # return merged_detections
1233
+
1234
+
1235
+
1236
+
1237
+
1238
+
1239
+
1240
+
1241
+
1242
+
1243
+
1244
+
1245
+
1246
+
1247
+
1248
+
1249
  def calculate_iou(box1, box2):
1250
+ """Calculate Intersection over Union between two boxes."""
1251
  x1_a, y1_a, x2_a, y2_a = box1
1252
  x1_b, y1_b, x2_b, y2_b = box2
1253
  x_left = max(x1_a, x1_b)
 
1261
  return intersection_area / union_area if union_area > 0 else 0
1262
 
1263
 
1264
+ def calculate_ioa(box1, box2):
1265
+ """Calculate Intersection over Area of box2."""
1266
+ x1_a, y1_a, x2_a, y2_a = box1
1267
+ x1_b, y1_b, x2_b, y2_b = box2
1268
+ x_left = max(x1_a, x1_b)
1269
+ y_top = max(y1_a, y1_b)
1270
+ x_right = min(x2_a, x2_b)
1271
+ y_bottom = min(y2_a, y2_b)
1272
+ intersection_area = max(0, x_right - x_left) * max(0, y_bottom - y_top)
1273
+ box_a_area = (x2_a - x1_a) * (y2_a - y1_a)
1274
+ return intersection_area / box_a_area if box_a_area > 0 else 0
 
 
 
 
 
 
 
 
 
 
 
 
 
1275
 
1276
 
 
1277
  def merge_overlapping_boxes(detections, iou_threshold):
1278
+ """
1279
+ Merges overlapping boxes of the same class based on IOU threshold.
1280
+ Returns boxes sorted by y-coordinate (top to bottom).
1281
+ """
1282
+ if not detections:
1283
+ return []
1284
+
1285
+ # Sort by confidence (highest first) for merge priority
1286
  detections.sort(key=lambda d: d['conf'], reverse=True)
1287
+
1288
  merged_detections = []
1289
  is_merged = [False] * len(detections)
1290
 
1291
  for i in range(len(detections)):
1292
+ if is_merged[i]:
1293
+ continue
1294
+
1295
  current_box = detections[i]['coords']
1296
  current_class = detections[i]['class']
1297
  merged_x1, merged_y1, merged_x2, merged_y2 = current_box
1298
+
1299
+ # Try to merge with all subsequent boxes of same class
1300
  for j in range(i + 1, len(detections)):
1301
+ if is_merged[j] or detections[j]['class'] != current_class:
1302
+ continue
1303
+
1304
  other_box = detections[j]['coords']
1305
  iou = calculate_iou(current_box, other_box)
1306
+
1307
  if iou > iou_threshold:
1308
+ # Expand merged box to encompass both
1309
  merged_x1 = min(merged_x1, other_box[0])
1310
  merged_y1 = min(merged_y1, other_box[1])
1311
  merged_x2 = max(merged_x2, other_box[2])
1312
+ merged_y2 = max(merged_y2, other_box[3]) # ← FIX THE TYPO HERE
1313
  is_merged[j] = True
1314
+
1315
  merged_detections.append({
1316
  'coords': (merged_x1, merged_y1, merged_x2, merged_y2),
1317
+ 'y1': merged_y1,
1318
+ 'class': current_class,
1319
  'conf': detections[i]['conf']
1320
  })
1321
 
1322
+ # Sort by y-coordinate (top to bottom) for consistent ordering
 
 
1323
  merged_detections.sort(key=lambda d: d['coords'][1])
1324
 
1325
  return merged_detections
1326
+
1327
+
1328
+ def filter_nested_boxes(detections, ioa_threshold=0.80):
1329
+ """
1330
+ Removes boxes that are nested inside larger boxes.
1331
+ Keeps the larger (parent) box and suppresses smaller (child) boxes.
1332
+ """
1333
+ if not detections:
1334
+ return []
1335
+
1336
+ # Calculate area for all detections
1337
+ for d in detections:
1338
+ x1, y1, x2, y2 = d['coords']
1339
+ d['area'] = (x2 - x1) * (y2 - y1)
1340
+
1341
+ # Sort by area (largest first) to prioritize keeping parent boxes
1342
+ detections.sort(key=lambda x: x['area'], reverse=True)
1343
+
1344
+ keep_indices = []
1345
+ is_suppressed = [False] * len(detections)
1346
+
1347
+ for i in range(len(detections)):
1348
+ if is_suppressed[i]:
1349
+ continue
1350
+
1351
+ keep_indices.append(i)
1352
+ box_a = detections[i]['coords']
1353
+
1354
+ # Check all smaller boxes
1355
+ for j in range(i + 1, len(detections)):
1356
+ if is_suppressed[j]:
1357
+ continue
1358
+
1359
+ box_b = detections[j]['coords']
1360
+
1361
+ # Calculate intersection
1362
+ x_left = max(box_a[0], box_b[0])
1363
+ y_top = max(box_a[1], box_b[1])
1364
+ x_right = min(box_a[2], box_b[2])
1365
+ y_bottom = min(box_a[3], box_b[3])
1366
+
1367
+ intersection = max(0, x_right - x_left) * max(0, y_bottom - y_top)
1368
+ area_b = detections[j]['area']
1369
+
1370
+ # If small box is mostly inside large box, suppress it
1371
+ if area_b > 0 and intersection / area_b > ioa_threshold:
1372
+ is_suppressed[j] = True
1373
+
1374
+ # Return kept detections in original y-sorted order
1375
+ kept_detections = [detections[i] for i in keep_indices]
1376
+ kept_detections.sort(key=lambda d: d['coords'][1])
1377
+
1378
+ return kept_detections
1379
+
1380
+
1381
+
1382
+
1383
+
1384
+
1385
+
1386
+
1387
+
1388
+
1389
+
1390
+
1391
+
1392
+
1393
+
1394
+
1395
+
1396
+
1397
+
1398
+
1399
+
1400
+
1401
 
1402
  # ============================================================================
1403
  # --- UTILITY FUNCTIONS (Retained) ---