基于OpenCV提取产品外框并计算宽高的技术求助
提取带附加部件箱体的外框并计算宽高解决方案
问题背景
需要提取带附加部件的箱体外框,获取其高度h和宽度w,尝试阈值处理、Canny边缘检测及findContours方法后未得到理想结果。
现有尝试代码及结果
阈值处理
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) ret, t = cv2.threshold(img, 40, 200, cv2.THRESH_BINARY_INV) plt.imshow(t)

边缘检测
edge = cv2.Canny(t, 70, 150) edge = cv2.dilate(edge, None, iterations = 1) edge = cv2.erode(edge, None, iterations = 1)

原始产品图像:
针对性解决步骤
1. 预处理:过滤干扰区域
原始图像中箱体与附加部件、背景存在颜色差异,优先通过颜色分割缩小有效区域,减少干扰:
import cv2 import numpy as np # 读取彩色图像并转HSV空间 img_color = cv2.imread(img_path) hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV) # 设定深色箱体的HSV范围(可根据实际图像微调) lower_hsv = np.array([0, 0, 0]) upper_hsv = np.array([180, 255, 80]) mask = cv2.inRange(hsv, lower_hsv, upper_hsv) # 形态学闭运算消除小噪点,填补箱体内部缝隙 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7)) mask_clean = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)
2. 轮廓提取与最优外框筛选
在预处理后的mask上提取轮廓,通过多边形拟合筛选矩形外框:
# 提取最外层轮廓 contours, _ = cv2.findContours(mask_clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 按轮廓面积降序排序,优先处理大轮廓(箱体外框面积最大) contours_sorted = sorted(contours, key=cv2.contourArea, reverse=True) target_rect = None for cnt in contours_sorted: # 计算轮廓周长,用多边形拟合近似形状 perimeter = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True) # 筛选四边形(箱体外框为矩形) if len(approx) == 4: # 获取外接矩形的坐标、宽度、高度 x, y, w, h = cv2.boundingRect(approx) # 验证宽高比例(根据实际箱体比例调整阈值,示例为0.6-1.8) if 0.6 < w/h < 1.8: target_rect = (x, y, w, h) # 在原图绘制外框 cv2.rectangle(img_color, (x,y), (x+w, y+h), (0,255,0), 3) print(f"箱体宽度:{w} 像素,高度:{h} 像素") break # 显示结果 cv2.imshow("Result", img_color) cv2.waitKey(0) cv2.destroyAllWindows()
3. 备选方案:霍夫直线拟合外框
若轮廓提取仍受干扰,可通过霍夫直线检测识别箱体四条边,计算交点得到外框:
# 对干净的mask做边缘检测 edges = cv2.Canny(mask_clean, 50, 150) # 检测长直线(过滤短干扰线) lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=120, minLineLength=250, maxLineGap=30) # 分离水平和垂直直线 horizontal_lines = [] vertical_lines = [] for line in lines: x1, y1, x2, y2 = line[0] # 计算直线角度,区分水平/垂直 angle = np.arctan2(y2-y1, x2-x1) * 180 / np.pi if abs(angle) < 10 or abs(angle) > 170: horizontal_lines.append(line[0]) elif 80 < abs(angle) < 100: vertical_lines.append(line[0]) # 取最上下的水平直线、最左右的垂直直线,计算交点得到外框 # (需补充直线排序、交点计算逻辑,此处为核心思路)
内容的提问来源于stack exchange,提问作者Gangil Seo
相关产品推荐
相关产品推荐

