如何移除重叠/内部占比超80%的Bounding Box
问题描述
我有一个Bounding Box列表,绘制时发现部分框存在重叠:Box3与4重叠、Box10与11重叠、Box7完全处于Box6内部。需要识别并移除重叠占比80%以上,或80%区域处于其他框内部的Box,最终期望保留的框为:0、1、2、3或4(保留较大的那个)、5、6、8、9、10或11(保留较大的那个)。
Bounding Box坐标
boxes=[(0, (156.52566528320312, 411.3934326171875, 508.0946350097656, 445.0401611328125)), (1, (153.34573364257812, 447.56744384765625, 1044.3194580078125, 612.4976196289062)), (2, (150.6321258544922, 662.0474243164062, 1076.75439453125, 899.3271484375)), (3, (154.38674926757812, 945.8661499023438, 1060.038330078125, 1026.8682861328125)), (4, (138.6205596923828, 951.3151245117188, 1035.56884765625, 1027.590087890625)), (5, (1245.50048828125, 410.4453430175781, 1393.0701904296875, 445.3376770019531)), (6, (1240.206787109375, 456.7169189453125, 2139.934326171875, 659.1046752929688)), (7, (1236.478759765625, 568.0098876953125, 2145.948486328125, 654.7606201171875)), (8, (1244.784912109375, 702.7620239257812, 2121.079345703125, 736.1748046875)), (9, (1244.885986328125, 746.2633666992188, 2151.534423828125, 991.8198852539062)), (10, (1251.84814453125, 1031.8487548828125, 2134.333251953125, 1153.9320068359375)), (11, (1254.38330078125, 1035.0196533203125, 2163.969970703125, 1153.2939453125))]
可视化代码
运行以下代码可生成示例图像,直观查看Box重叠情况:
import cv2 import matplotlib.pyplot as plt import numpy as np img = np.ones([1654,2339,3],dtype=np.uint8)*255 for i in boxes: box=[int(i) for i in i[1]] image = cv2.rectangle(img, (box[0],box[1]), (box[2],box[3]), (0,0,0), 5) cv2.putText( img = image, text = str(i[0]), org = (box[0]+int(np.random.randint(0, high=500, size=1)),box[1]), fontFace = cv2.FONT_HERSHEY_DUPLEX, fontScale = 3.0, color = (0, 0, 0), thickness = 3 ) plt.imshow(img)
现有解决方案的缺陷
当前代码仅检查相邻Box的包含关系,无法覆盖非相邻Box的重叠场景(比如Box7和Box6),也未计算重叠占比,逻辑存在局限性:
# x_1, y_1, x_2, y_2 for i in range(len(boxes)-1): x_min_1,y_min_1,x_max_1,y_max_1=boxes[i][1][0],boxes[i][1][1],boxes[i][1][2],boxes[i][1][3] x_min_2,y_min_2,x_max_2,y_max_2=boxes[i+1][1][0],boxes[i+1][1][1],boxes[i+1][1][2],boxes[i+1][1][3] box_1_in_box_2 = ((x_max_2> x_min_1 >= x_min_2) or \ (x_max_2>= x_max_1 >x_min_2)) and \ ((y_max_2> y_min_1 >= y_min_2) or \ (y_max_2>= y_max_1 > y_min_2)) box_2_in_box_1 = ((x_max_1> x_min_2 >= x_min_1) or (x_max_1>= x_max_2 >x_min_1)) and ((y_max_1> y_min_2 >= y_min_1) or (y_max_1>= y_max_2 > y_min_1)) overlap = box_1_in_box_2 or box_2_in_box_1 print(i,overlap)
改进解决方案
要实现需求,需完成以下步骤:
- 计算每个Box的面积
- 遍历所有Box对,计算重叠区域面积
- 判断重叠占比是否超过80%,或一个Box的80%区域在另一个内部
- 保留面积更大的符合要求的Box
完整代码
def calculate_area(box): # Box格式:(x_min, y_min, x_max, y_max) x_min, y_min, x_max, y_max = box return (x_max - x_min) * (y_max - y_min) def calculate_overlap_area(box1, box2): # 计算两个Box的重叠区域面积 x_min1, y_min1, x_max1, y_max1 = box1 x_min2, y_min2, x_max2, y_max2 = box2 # 计算重叠区域的坐标 overlap_x_min = max(x_min1, x_min2) overlap_y_min = max(y_min1, y_min2) overlap_x_max = min(x_max1, x_max2) overlap_y_max = min(y_max1, y_max2) # 无重叠的情况 if overlap_x_min >= overlap_x_max or overlap_y_min >= overlap_y_max: return 0.0 return (overlap_x_max - overlap_x_min) * (overlap_y_max - overlap_y_min) def filter_boxes(boxes, threshold=0.8): # 存储需要保留的Box索引 keep = set(range(len(boxes))) # 遍历所有Box对(避免重复比较) for i in range(len(boxes)): if i not in keep: continue box_id1, box1 = boxes[i] area1 = calculate_area(box1) for j in range(i+1, len(boxes)): if j not in keep: continue box_id2, box2 = boxes[j] area2 = calculate_area(box2) overlap_area = calculate_overlap_area(box1, box2) if overlap_area == 0: continue # 判断是否满足移除条件 ratio1 = overlap_area / area1 # box1被box2覆盖的比例 ratio2 = overlap_area / area2 # box2被box1覆盖的比例 if ratio1 >= threshold or ratio2 >= threshold: # 移除面积较小的那个Box if area1 >= area2: keep.remove(j) else: keep.remove(i) break # 当前i已被移除,无需继续比较 # 按原顺序返回保留的Box return [boxes[k] for k in sorted(keep)] # 执行过滤 filtered_boxes = filter_boxes(boxes) print("保留的Box:") for box in filtered_boxes: print(f"Box {box[0]}: {box[1]}")
代码说明
calculate_area:计算单个Box的面积calculate_overlap_area:计算两个Box的重叠区域面积,无重叠时返回0filter_boxes:遍历所有Box对,判断是否满足移除条件,优先保留面积更大的Box;使用集合keep跟踪保留索引,避免重复处理- 最终输出会符合需求:保留0、1、2、3(面积大于Box4)、5、6、8、9、10(面积略大于Box11)
内容的提问来源于stack exchange,提问作者Talha Anwar
相关产品推荐
相关产品推荐

