You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何移除重叠/内部占比超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)

改进解决方案

要实现需求,需完成以下步骤:

  1. 计算每个Box的面积
  2. 遍历所有Box对,计算重叠区域面积
  3. 判断重叠占比是否超过80%,或一个Box的80%区域在另一个内部
  4. 保留面积更大的符合要求的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的重叠区域面积,无重叠时返回0
  • filter_boxes:遍历所有Box对,判断是否满足移除条件,优先保留面积更大的Box;使用集合keep跟踪保留索引,避免重复处理
  • 最终输出会符合需求:保留0、1、2、3(面积大于Box4)、5、6、8、9、10(面积略大于Box11)

内容的提问来源于stack exchange,提问作者Talha Anwar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 12:15:41