OpenCV红色轮廓检测:轮廓计数不符(预期3个实际14个)问题排查
问题:检测红色轮廓时轮廓数量不符的排查与解决
问题背景
我尝试检测带有红色轮廓的特定轮廓,当前代码输出的轮廓数量为14,但正确结果应为3个,请问哪里处理有误?
我的处理代码
import numpy as np import cv2 image = cv2.imread('C:/Users/htc/Desktop/image.png') original = image.copy() image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) lower = np.array([0,50,50], dtype="uint8") upper = np.array([10, 255,255], dtype="uint8") mask = cv2.inRange(image, lower, upper) # Find contours cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Extract contours depending on OpenCV version cnts = cnts[0] if len(cnts) == 2 else cnts[1] print(len(cnts)) # Iterate through contours and filter by the number of vertices for c in cnts: perimeter = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.04 * perimeter, True) if len(approx) > 5: cv2.drawContours(original, [c], -1, (36, 255, 12), -1) cv2.imshow('mask', mask) cv2.imshow('original', original) cv2.waitKey()
问题排查与解决思路
咱们一步一步拆解问题,看看哪里出了问题:
1. HSV红色范围不完整
红色在HSV色彩空间里是跨区间的:一部分H值在0-10左右(偏亮红),另一部分在170-180左右(偏深红/暗红)。你现在只取了低区间的红色,会导致目标红色区域没被完全覆盖,反而把一些杂色小区域误识别成轮廓,直接让数量暴增。
解决方法:把两个红色区间的mask合并起来:
# 低区间亮红色 lower_red1 = np.array([0,50,50], dtype="uint8") upper_red1 = np.array([10, 255,255], dtype="uint8") mask1 = cv2.inRange(image, lower_red1, upper_red1) # 高区间暗红色 lower_red2 = np.array([170,50,50], dtype="uint8") upper_red2 = np.array([180, 255,255], dtype="uint8") mask2 = cv2.inRange(image, lower_red2, upper_red2) # 合并两个mask,覆盖所有红色区域 mask = cv2.bitwise_or(mask1, mask2)
2. Mask未做降噪处理
如果原始图像里有红色噪点、小斑点,findContours会把这些都当成独立轮廓,这是轮廓数量超标的常见原因。
解决方法:在找轮廓前对mask做形态学闭运算(先膨胀再腐蚀),把小噪点消除:
# 创建3x3的矩形结构元素 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) # 闭运算消除小噪点,迭代2次增强效果 mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)
3. 轮廓过滤条件太宽松
你现在只用顶点数量len(approx) >5过滤,但很多小杂轮廓也可能满足这个条件。建议加上面积过滤,直接跳过面积过小的轮廓:
for c in cnts: area = cv2.contourArea(c) # 跳过面积小于100的小轮廓(阈值可根据你的图像调整) if area < 100: continue perimeter = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.04 * perimeter, True) if len(approx) > 5: cv2.drawContours(original, [c], -1, (36, 255, 12), -1)
验证小技巧
调整后可以先单独查看处理后的mask:如果mask里还有很多小白色斑点,说明噪点没清干净;如果目标红色区域有缺失,就再微调HSV的区间阈值。
内容的提问来源于stack exchange,提问作者Shahnawaz Irfan
相关产品推荐
相关产品推荐

