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

OpenCV如何为指定上下目标轮廓绘制外接bounding box

问题描述

需求是为检测到的1个顶部轮廓、1个底部轮廓绘制整体外接bounding box:

原有基础实现代码在无干扰场景可以正常运行,效果见无干扰运行效果,代码如下:

import cv2
import numpy as np

img = cv2.imread('light2.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (0, 0, 46), (179, 255, 255))

kernel = np.ones((5,5),np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

try: hierarchy = hierarchy[0]
except: hierarchy = []

height, width, _ = img.shape
min_x, min_y = width, height
max_x = max_y = 0

for contour, hier in zip(contours, hierarchy):
  (x, y, w, h) = cv2.boundingRect(contour)
  min_x, max_x = min(x, min_x), max(x+w, max_x)
  min_y, max_y = min(y, min_y), max(y+h, max_y)
  if w > 80 and h > 80:
      cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

if max_x - min_x > 0 and max_y - min_y > 0:
    cv2.rectangle(img, (min_x, min_y), (max_x, max_y), (255, 0, 0), 2)

原有代码逻辑缺陷:遍历所有轮廓时无差别更新全局外接框的坐标边界,当场景存在无关轮廓时,会把干扰轮廓也纳入计算范围,最终得到范围错误的外接框,错误效果见错误运行效果。

解决思路

核心是先从所有检测到的轮廓里精准筛选出顶部、底部两个目标轮廓,再仅基于这两个轮廓计算整体外接框,不要把无关轮廓纳入坐标计算:

  1. 第一轮遍历轮廓时,根据目标轮廓的几何特征过滤干扰项:可以用轮廓面积、宽高比、矩形度等特征做筛选,比如目标是横向长条状光带,宽高比会远大于零散小干扰,设置对应宽高比阈值即可排除大部分干扰
  2. 筛选出的有效轮廓按垂直坐标(轮廓顶部y值)排序,y值最小的是顶部目标轮廓,y值最大的是底部目标轮廓
  3. 仅用筛选出的两个目标轮廓的坐标,计算整体外接框的min_x、min_y、max_x、max_y,绘制最终外框
修正后参考代码
import cv2
import numpy as np

img = cv2.imread('light2.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (0, 0, 46), (179, 255, 255))

kernel = np.ones((5,5),np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
height, width, _ = img.shape
valid_rects = []

# 第一轮遍历:筛选符合特征的目标轮廓
for contour in contours:
    x, y, w, h = cv2.boundingRect(contour)
    # 阈值根据实际场景调整:过滤小尺寸、宽高比不符合横向长条特征的干扰
    if w > 80 and h > 20 and w/h > 3:
        valid_rects.append((x, y, w, h))
        # 绘制单个目标轮廓的边框
        cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

# 取上下两个目标轮廓计算整体外框
if len(valid_rects) >= 2:
    # 按轮廓顶部y值升序排序
    valid_rects.sort(key=lambda r: r[1])
    top_rect = valid_rects[0]
    bottom_rect = valid_rects[-1]

    # 仅用两个目标轮廓计算全局边界
    min_x = min(top_rect[0], bottom_rect[0])
    min_y = top_rect[1]
    max_x = max(top_rect[0] + top_rect[2], bottom_rect[0] + bottom_rect[2])
    max_y = bottom_rect[1] + bottom_rect[3]

    # 绘制整体外接框
    cv2.rectangle(img, (min_x, min_y), (max_x, max_y), (0, 255, 0), 2)

cv2.imshow('result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

提示:代码中的尺寸、宽高比阈值可根据实际场景调整,如果存在和目标尺寸接近的干扰,可增加轮廓面积、轮廓占外接矩形比例(矩形度)等筛选条件进一步提升准确率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 00:06:24