OpenCV基于颜色检测矩形失效:无法识别重叠矩形问题求助
解决OpenCV检测重叠矩形的问题
问题根源
你的代码处理重叠矩形时失效,核心原因是重叠的同色矩形在掩码中会形成单一连通区域,cv2.findContours会将其识别为一个整体轮廓,无法区分独立的矩形。
可行解决方案
方案1:分水岭算法分割连通区域
通过距离变换和分水岭算法拆分合并的连通区域,再逐个检测矩形:
import cv2 import numpy as np # 读取图像 image = cv2.imread("your_input_image.png") image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 颜色掩码 lower_blue = np.array([110, 50, 50]) upper_blue = np.array([130, 255, 255]) mask = cv2.inRange(image_hsv, lower_blue, upper_blue) # 开运算去除噪声 kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=2) # 确定背景区域 sure_bg = cv2.dilate(opening, kernel, iterations=3) # 距离变换提取前景区域 dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0) # 计算未知区域(背景与前景的差) sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) # 标记连通区域 ret, markers = cv2.connectedComponents(sure_fg) markers += 1 # 背景标记为1,避免与分水岭的边界标记(-1)冲突 markers[unknown == 255] = 0 # 应用分水岭算法分割区域 markers = cv2.watershed(image, markers) image[markers == -1] = [255, 0, 0] # 标记分割边界 # 遍历每个分割后的区域,检测矩形 for marker_idx in range(2, ret + 1): # 创建当前区域的掩码 marker_mask = np.zeros_like(mask) marker_mask[markers == marker_idx] = 255 # 提取区域轮廓 contours, _ = cv2.findContours(marker_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for contour in contours: # 轮廓近似 epsilon = 0.02 * cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, epsilon, True) # 判断是否为矩形 if len(approx) == 4: x, y, w, h = cv2.boundingRect(approx) cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2) # 保存或显示结果 cv2.imwrite("output_watershed.png", image) # cv2.imshow("Result", image) # cv2.waitKey(0)
方案2:霍夫线变换重建矩形
通过检测矩形的边缘直线,再通过直线交点组合出独立矩形,不受连通区域限制:
import cv2 import numpy as np # 读取图像 image = cv2.imread("your_input_image.png") image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 颜色掩码 lower_blue = np.array([110, 50, 50]) upper_blue = np.array([130, 255, 255]) mask = cv2.inRange(image_hsv, lower_blue, upper_blue) # 边缘检测 edges = cv2.Canny(mask, 50, 150) # 霍夫线变换检测直线(调整参数适配你的图像) lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=50, minLineLength=30, maxLineGap=10) # 分类水平和垂直线 horizontal_lines = [] vertical_lines = [] for line in lines: x1, y1, x2, y2 = line[0] # 判断水平线(y坐标差异小) if abs(y2 - y1) < 10: horizontal_lines.append(((x1, y1), (x2, y2))) # 判断垂直线(x坐标差异小) elif abs(x2 - x1) < 10: vertical_lines.append(((x1, y1), (x2, y2))) # 计算直线交点,收集矩形顶点候选 rect_pts = [] for h_line in horizontal_lines: h_y = h_line[0][1] h_x_min = min(h_line[0][0], h_line[1][0]) h_x_max = max(h_line[0][0], h_line[1][0]) for v_line in vertical_lines: v_x = v_line[0][0] v_y_min = min(v_line[0][1], v_line[1][1]) v_y_max = max(v_line[0][1], v_line[1][1]) # 检查交点是否同时在两条直线上 if h_x_min <= v_x <= h_x_max and v_y_min <= h_y <= v_y_max: rect_pts.append((v_x, h_y)) # 聚类顶点,生成矩形(假设图像中有4个矩形,可根据实际调整聚类数) if len(rect_pts) >= 4: rect_pts_np = np.array(rect_pts, dtype=np.float32) # K-means聚类分组顶点 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) ret, labels, centers = cv2.kmeans(rect_pts_np, 4, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) # 遍历每个聚类,生成矩形 for i in range(ret): group_pts = rect_pts_np[labels.ravel() == i] if len(group_pts) >= 4: x_min, y_min = np.min(group_pts, axis=0) x_max, y_max = np.max(group_pts, axis=0) cv2.rectangle(image, (int(x_min), int(y_min)), (int(x_max), int(y_max)), (0, 255, 0), 2) # 保存或显示结果 cv2.imwrite("output_hough.png", image) # cv2.imshow("Result", image) # cv2.waitKey(0)
参数调整提示
- 方案1中,可调整
0.7 * dist_transform.max()的系数,控制前景区域的阈值; - 方案2中,霍夫线的
threshold、minLineLength、maxLineGap参数需要根据图像的矩形大小、边缘清晰度调整; - 两种方案都可先对掩码做形态学操作(开/闭运算),优化掩码质量。
内容的提问来源于stack exchange,提问作者spd
相关产品推荐
相关产品推荐

