如何从含噪图像中提取蓝红箭头?OpenCV-Python实现遇阻
含噪图像中提取蓝红色箭头的优化方案
问题背景
我需要从一张含噪图像中提取仅有的4个箭头,但噪声过滤难度极大,且箭头处于蓝色和红色的HSV色域范围,颜色过滤存在不小的困难。已尝试以下OpenCV-Python操作,但均未达到理想的箭头过滤效果:
- 应用
GaussianBlur模糊降噪 - 提取色相通道后使用Canny边缘检测
- 轮廓检测与绘制
- 先进行颜色过滤再执行Canny边缘检测
附相关图像:


针对性优化思路与实现
1. 分区间颜色掩码+形态学去噪
红色在HSV色域中属于跨0度的特殊区间,需要拆分两段提取;蓝色使用常规区间提取。合并两种颜色的掩码后,通过形态学闭操作填充箭头内部缝隙,开操作清除零散噪声点。
import cv2 import numpy as np # 读取图像并转换为HSV色域 img = cv2.imread("your_image_path.png") hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 提取红色掩码(HSV双区间) lower_red1 = np.array([0, 50, 50]) upper_red1 = np.array([10, 255, 255]) lower_red2 = np.array([170, 50, 50]) upper_red2 = np.array([180, 255, 255]) red_mask1 = cv2.inRange(hsv_img, lower_red1, upper_red1) red_mask2 = cv2.inRange(hsv_img, lower_red2, upper_red2) red_mask = cv2.bitwise_or(red_mask1, red_mask2) # 提取蓝色掩码 lower_blue = np.array([90, 50, 50]) upper_blue = np.array([120, 255, 255]) blue_mask = cv2.inRange(hsv_img, lower_blue, upper_blue) # 合并红蓝掩码 combined_mask = cv2.bitwise_or(red_mask, blue_mask) # 形态学操作优化掩码 kernel = np.ones((3, 3), np.uint8) # 闭操作填充箭头内部空洞 combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_CLOSE, kernel, iterations=2) # 开操作去除小噪声点 combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_OPEN, kernel, iterations=1)
2. 轮廓几何特征筛选
提取掩码中的轮廓后,通过面积范围、近似多边形边数等箭头特有的几何特征,过滤掉噪声轮廓:
# 提取外部轮廓 contours, _ = cv2.findContours(combined_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) arrow_contours = [] for cnt in contours: # 过滤面积异常的轮廓 area = cv2.contourArea(cnt) if area < 100 or area > 5000: continue # 多边形近似,简化轮廓 epsilon = 0.05 * cv2.arcLength(cnt, True) approx_shape = cv2.approxPolyDP(cnt, epsilon, True) # 箭头的近似多边形边数通常在6-9之间,以此为筛选条件 if 6 <= len(approx_shape) <= 9: arrow_contours.append(cnt) # 绘制筛选出的箭头轮廓 result_img = img.copy() cv2.drawContours(result_img, arrow_contours, -1, (0, 255, 0), 2) cv2.imshow("Extracted Arrows", result_img) cv2.waitKey(0) cv2.destroyAllWindows()
3. 颜色掩码与边缘检测结合
先对原始图像做Canny边缘检测,再通过颜色掩码过滤掉非目标颜色的边缘,进一步减少噪声干扰:
# 提取原始图像边缘 edges = cv2.Canny(img, 50, 150) # 保留颜色掩码范围内的边缘 masked_edges = cv2.bitwise_and(edges, combined_mask) # 基于掩码边缘提取轮廓(后续可复用步骤2的筛选逻辑) contours_from_edges, _ = cv2.findContours(masked_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
内容的提问来源于stack exchange,提问作者Keefe Ho
相关产品推荐
相关产品推荐

