数组点分组实现整组操作 OpenCV检测二值图白点遮挡
基于二值图像的LED孔洞白点遮挡检测方案
问题背景
我目前正在开发一款程序,可读取二值图像,自动识别图中是否存在被遮挡的白点:即程序预设应为白色的点位,实际在图像中呈现为黑色,采集场景为LED光线透过孔洞形成白色光点,相关参考图如下:
- 二值化处理后示例图:

- 原始采集图:

当前实现代码
现有代码仅能在理想无干扰场景下生效,实现如下:
import cv2 import numpy as np img = cv2.imread('bwimg.jpg') pixels = np.asarray(img) pixels = np.nonzero(pixels) xpixels = pixels[1] # x coordinate of each white pixel ypixels = pixels[0] # y coordinate of each white pixel # example estimations for the center coordinates of some of the points (can be calibrated further, just an example) xcoords = [60, 160, 255, 350, 445] ycoords = [410, 405, 400, 395, 390] for coo in range(0,4): indexList = np.ravel(np.asarray(xpixels == xcoords[coo]).nonzero()) for y in range(0,4): for x in indexList: if ypixels[x] == ycoords[y]: print(x, xcoords[coo], ycoords[y])
优化需求
现有方案仅判定白点中心单个像素的颜色,鲁棒性极差,需要在以下异常场景下保持检测有效性:
- 白点仅被半遮挡
- 碎屑落在白点上导致少量像素被误判为黑色
预设优化思路:不再仅判定白点中心单个像素的颜色,而是以预设的白点中心坐标为圆心,划定固定半径的检测区域,若区域内白色像素占比超过50%,则判定该白点未被遮挡。已知可借助OpenCV或scipy实现该类数组点分组、整组区域判定的逻辑,求具体实现方法。
附注:我不常于平台发帖,不确定添加scipy标签是否符合板块规范,若不合适我会及时移除该标签。
实现方案
直接用OpenCV的掩码操作即可实现圆形区域的像素统计,不需要额外依赖scipy,计算效率高且逻辑稳定:
- 读取图像时直接转单通道灰度图,避免三通道冗余计算
- 针对每个预设白点坐标生成对应尺寸的圆形掩码,半径可根据实际白点大小标定(建议取白点实际半径的80%~90%)
- 用掩码截取对应检测区域,统计白色像素(值为255)占掩码总有效像素的比例,和设定阈值做对比即可输出判定结果
可直接运行的优化后代码
import cv2 import numpy as np # 可根据实际场景标定的参数 DETECT_RADIUS = 8 # 检测区域圆形半径,匹配实际白点大小调整 WHITE_THRESHOLD = 0.5 # 白色像素占比阈值,超过则判定为正常未遮挡 EXPECTED_POINTS = list(zip([60, 160, 255, 350, 445], [410, 405, 400, 395, 390])) # 预设白点中心坐标格式(x,y) # 读取图像 直接加载为单通道灰度图 img = cv2.imread('bwimg.jpg', cv2.IMREAD_GRAYSCALE) h, w = img.shape # 可选:针对碎屑噪点做小半径形态学开运算,进一步提升鲁棒性 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) for idx, (cx, cy) in enumerate(EXPECTED_POINTS): # 边界校验 避免预设坐标越界导致报错 if cx - DETECT_RADIUS < 0 or cx + DETECT_RADIUS >= w or cy - DETECT_RADIUS <0 or cy + DETECT_RADIUS >=h: print(f"点位{idx} 坐标({cx},{cy})超出图像边界,判定为异常") continue # 生成圆形检测区域掩码 mask = np.zeros((h,w), dtype=np.uint8) cv2.circle(mask, (cx, cy), DETECT_RADIUS, 255, thickness=-1) # 统计区域内总有效像素、白色像素数量 total_pixels = cv2.countNonZero(mask) target_area = cv2.bitwise_and(img, img, mask=mask) white_pixels = cv2.countNonZero(target_area) white_ratio = white_pixels / total_pixels if white_ratio >= WHITE_THRESHOLD: print(f"点位{idx} 坐标({cx},{cy}) 正常,白色像素占比{white_ratio:.1%}") else: print(f"点位{idx} 坐标({cx},{cy}) 被遮挡,白色像素占比{white_ratio:.1%}")
调优提示
- 检测半径不要设置过大,避免把相邻白点的像素纳入当前检测区域造成误判
- 如果预设坐标存在标定偏移,可以先对每个预设点周围做小范围质心计算,将检测圆心对齐到实际白点的质心后再做占比统计,可进一步降低标定误差的影响
- 阈值可根据现场遮挡的实际情况调整,半遮挡场景较多可适当下调阈值到0.30.4,要求严格可上调到0.60.7
内容的提问来源于stack exchange,提问作者Mango Turtl
相关产品推荐
相关产品推荐

