如何用OpenCV检测图像中被白色区域包围的黑色区域轮廓
黑色区域检测与分割方案
针对你提供的预处理后图像,要检测被上下白色区域(顶部白色可能不连通)包围的黑色区域,可采用以下两种实用方案:
方案一:基于连通分量分析
利用连通分量识别上下白色区域,再提取中间黑色区域:
提取白色连通域
用OpenCV的连通分量分析工具,找出图像中所有白色区域的位置与属性:import cv2 import numpy as np # 读入灰度图并确保二值化 img = cv2.imread('your_image.jpg', cv2.IMREAD_GRAYSCALE) _, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # 分析白色连通域(connectivity=8表示8邻域连通) num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary, connectivity=8)筛选上下白色区域
根据连通域的垂直位置,将顶部和底部的白色区域分类:h, w = binary.shape upper_threshold = h // 3 # 顶部区域阈值,可根据实际调整 lower_threshold = h * 2 // 3 # 底部区域阈值 upper_labels = [] lower_labels = [] for i in range(1, num_labels): y = stats[i][1] # 连通域外接矩形的顶部y坐标 height = stats[i][3] # 筛选顶部白色区域 if y + height < upper_threshold: upper_labels.append(i) # 筛选底部白色区域 if y > lower_threshold: lower_labels.append(i)生成掩码并提取黑色区域
合并上下白色区域生成掩码,再提取中间的黑色区域:# 创建上下白色区域的掩码 upper_mask = np.zeros_like(binary) for label in upper_labels: upper_mask[labels == label] = 255 lower_mask = np.zeros_like(binary) for label in lower_labels: lower_mask[labels == label] = 255 combined_mask = cv2.bitwise_or(upper_mask, lower_mask) # 提取中间黑色区域 inverted = cv2.bitwise_not(binary) black_region = cv2.bitwise_and(inverted, cv2.bitwise_not(combined_mask))检测黑色区域轮廓
提取目标区域的轮廓并可视化:contours, _ = cv2.findContours(black_region, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 在原图上绘制绿色轮廓 result = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) cv2.drawContours(result, contours, -1, (0, 255, 0), 2)
方案二:基于水平投影分析
通过统计每行的白色像素占比,快速定位上下白色区域的边界,适合顶部白色不连通的场景:
计算水平投影
统计图像每行的白色像素数量:row_sum = np.sum(binary == 255, axis=1)定位上下边界
找到顶部白色区域的最低行,以及底部白色区域的最高行:# 找顶部白色区域的底部边界 upper_bottom = np.max(np.where(row_sum > 0)[0][np.where(row_sum > 0)[0] < h//3]) # 找底部白色区域的顶部边界 lower_top = np.min(np.where(row_sum > 0)[0][np.where(row_sum > 0)[0] > h*2//3])提取中间黑色区域
直接截取上下边界之间的区域,再检测轮廓:# 截取中间区域 middle_region = binary[upper_bottom:lower_top, :] # 反向后找黑色区域轮廓(此时黑色已转为白色) inverted_middle = cv2.bitwise_not(middle_region) contours, _ = cv2.findContours(inverted_middle, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
注意事项
- 若图像存在噪声小斑点,可先执行形态学开操作去除:
binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, np.ones((3,3), np.uint8)) - 方案二对顶部白色不连通的场景鲁棒性更强,无需关心白色块的数量;方案一更适合需要精确区分上下白色区域的场景。
内容的提问来源于stack exchange,提问作者Yellow_truffle
相关产品推荐
相关产品推荐

