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

如何剔除OpenCV图像目标检测结果中的重叠矩形框?

我使用OpenCV库检测图像中的目标,检测输入图效果如下:
图1

为实现该检测功能,我编写了如下代码:

import matplotlib.pyplot as plt
import cv2 

# source data
img_file= "Fig1.jpg"

# create an OpenCV image
img= cv2.imread(img_file)

# convert color image to grey image
gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

im_gauss = cv2.GaussianBlur(gray_img, (5, 5), 0)
ret, thresh = cv2.threshold(im_gauss, 127, 255, 0)
# get contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

margin = 40
# calculate area and filter 
for con in contours:
    area = cv2.contourArea(con)
    if 100 < area < 500:
        x,y,w,h = cv2.boundingRect(con)
        cv2.rectangle(img, (x-margin, y-margin), (x + w+margin, y + h+margin), (0,255,0), 2)
        
plt.imshow(img, cmap='gray')

上述代码运行后,可得到标注了检测目标的结果图,效果如下:
图2

目前检测生成的部分矩形标注框存在重叠,并非预期的输出效果。目标是剔除所有重叠的矩形框,最终输出仅保留无重叠矩形的结果图。


解决方法

要剔除重叠的矩形框,直接用OpenCV自带的非极大值抑制(NMS)算法就行,不用自己写复杂的矩形相交判断逻辑。整体调整思路很简单:

  • 遍历轮廓的时候别急着画框,先把所有符合面积要求的框的坐标、对应参数统一存到列表里
  • 调用cv2.dnn.NMSBoxes对所有存好的框做过滤,通过设置交并比阈值判定哪些框是重叠的,算法会自动优先保留面积最大的框,把和它重叠的其他框全删掉
  • 只对过滤后剩下的不重叠的框执行绘制就行
  • 顺带把原代码里matplotlib显示OpenCV图像的色彩偏差问题修好,不然显示出来的图颜色不对

修改后的完整可运行代码如下:

import matplotlib.pyplot as plt
import cv2 

# 基础参数配置
img_file= "Fig1.jpg"
margin = 40
min_contour_area = 100
max_contour_area = 500
# 重叠判定阈值:两个框交并比超过该值就判定为重叠,会被自动剔除
iou_threshold = 0.2

# 读取图像
img = cv2.imread(img_file)
# 转换色彩空间避免matplotlib显示颜色偏差
img_show = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 图像预处理
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
im_gauss = cv2.GaussianBlur(gray_img, (5, 5), 0)
ret, thresh = cv2.threshold(im_gauss, 127, 255, 0)

# 提取轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 收集所有符合面积要求的矩形框
bbox_list = []
score_list = []
for con in contours:
    area = cv2.contourArea(con)
    if min_contour_area < area < max_contour_area:
        x,y,w,h = cv2.boundingRect(con)
        # 计算加边距的矩形坐标,适配NMS输入格式
        bbox_x = x - margin
        bbox_y = y - margin
        bbox_w = w + 2 * margin
        bbox_h = h + 2 * margin
        bbox_list.append([bbox_x, bbox_y, bbox_w, bbox_h])
        # 统一给所有框设相同置信度,NMS会优先保留面积最大的框
        score_list.append(1.0)

# 执行NMS过滤重叠框
nms_keep_index = cv2.dnn.NMSBoxes(
    bboxes=bbox_list,
    scores=score_list,
    score_threshold=0.5,
    nms_threshold=iou_threshold
)

# 绘制过滤后的无重叠框
if len(nms_keep_index) > 0:
    for idx in nms_keep_index.flatten():
        x, y, w, h = bbox_list[idx]
        cv2.rectangle(img_show, (x, y), (x + w, y + h), (0, 255, 0), 2)

plt.imshow(img_show)
plt.show()

调参提示

  • 代码里的iou_threshold是重叠判定的阈值,两个框的交并比超过这个值就会被判定为重叠,可以根据实际效果调整:数值越小,对重叠的判定越严格,哪怕离得近的框也会被删掉;数值越大,只有几乎完全重合的框才会被剔除
  • 如果想多保留一些距离近但不怎么重叠的框,就把这个值调高一点

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 10:45:06