如何基于OpenCV Canny边缘检测计算印刷网点的均值与标准差
半色调网点提取与尺寸统计方案
方案选择说明
你当前使用Canny边缘检测的方案不适合半色调网点提取,原因是浅色网点(比如黄色)和背景的灰度差很小,边缘梯度不足,Canny很容易漏检。更适合的方案是颜色空间转换+二值化+轮廓查找,直接基于色块而非边缘分割,对浅色网点的识别准确率高很多。
实现步骤
- 第一步:颜色空间转换,将默认BGR格式转为HSV格式,基于色相(H)通道区分不同颜色的网点,规避亮度、饱和度差异的干扰,可单独提取黄、品、青、黑各分色的网点掩膜。
- 第二步:图像二值化,若需统计所有网点可将图像转灰度后使用
cv2.adaptiveThreshold自适应二值化,比固定阈值适配性更强,能完整分割出浅色网点;若需分颜色统计则对对应颜色的HSV掩膜做二值化处理。 - 第三步:轮廓筛选,使用
cv2.findContours提取二值图中的所有轮廓,按面积过滤掉过小的噪点后,剩余轮廓即为有效网点。
尺寸计算方法
- 单个网点尺寸可采用等效直径计算:通过
cv2.contourArea获取轮廓面积后,按照圆形面积公式换算等效直径d = √(4*面积/π),适配不规则的印刷网点。 - 将所有有效网点的等效直径存入数组后,直接调用numpy的
np.mean()计算均值,np.std()计算标准差即可。
参考代码
import cv2 import numpy as np # 读取原始图像 img = cv2.imread('img/color_dots.png') # 转HSV颜色空间用于分色提取 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 示例:提取黄色网点掩膜,可根据实际网点颜色调整上下限 lower_yellow = np.array([20, 50, 50]) upper_yellow = np.array([30, 255, 255]) yellow_mask = cv2.inRange(hsv, lower_yellow, upper_yellow) # 提取所有颜色网点的二值化处理 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) binary = cv2.adaptiveThreshold( gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) # 查找所有外层轮廓 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) dot_diameters = [] for cnt in contours: area = cv2.contourArea(cnt) # 过滤面积小于5像素的噪点,阈值可根据图像分辨率调整 if area < 5: continue # 计算等效直径 diameter = np.sqrt(4 * area / np.pi) dot_diameters.append(diameter) # 统计结果 mean_d = np.mean(dot_diameters) std_d = np.std(dot_diameters) print(f"网点平均等效直径:{mean_d:.2f} 像素") print(f"网点尺寸标准差:{std_d:.2f} 像素")
参数调整说明
- 自适应二值化的块大小(代码中11的位置,必须为奇数)、阈值偏移量(代码中2的位置)可根据实际网点大小调整,块大小建议略大于单个网点的直径。
- 分色提取的HSV上下限可通过取色工具拾取实际网点的颜色后调整,确保目标颜色网点完整出现在掩膜中。
内容的提问来源于stack exchange,提问作者Haidepzai
相关产品推荐
相关产品推荐

