「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战」
前言
在阈值技术详解中,我们已经知道阈值在使用 cv2.threshold() 对图像进行阈值处理时起着至关重要的作用。假设图像处理算法用于识别图像中的对象,如果阈值较低,则阈值图像中缺少一些信息,而如果阈值较高,则有一些信息会被黑色像素遮挡。因此,为整个图像找到一个全局最优阈值是相当困难的,特别是如果图像受到不同光照条件的影响,找到全局最优阈值几乎是不可能的。这就是为什么我们需要应用其他自适应阈值算法来对图像进行阈值处理的原因。
自适应阈值算法
当由于图像不同区域的光照条件不同时,为了获取更好的阈值结果,可以尝试使用自适应阈值。在 OpenCV 中,自适应阈值由 cv2.adapativeThreshold() 函数实现,其用法如下:
adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]) -> dst
此函数将自适应阈值应用于 src 数组( 8 位单通道图像)。maxValue 参数用于设置 dst 图像中满足条件的像素值。adaptiveMethod 参数设置要使用的自适应阈值算法,有以下两个可选值:
cv2.ADAPTIVE_THRESH_MEAN_C:T(x, y)阈值为(x, y)的blockSize x blockSize邻域的平均值减去参数Ccv2.ADAPTIVE_THRESH_GAUSSIAN_C:T(x, y)阈值为(x, y)的blockSize x blockSize邻域的加权均值减去参数C
blockSize 参数用于计算像素阈值的邻域区域的大小,C 参数是均值或加权均值需要减去的常数(取决于由 adaptiveMethod 参数设置的自适应方法),thresholdType 参数可选值包括 cv2.THRESH_BINARY 和 cv2.THRESH_BINARY_INV。
综上所属,cv2.adapativeThreshold() 函数的计算公式如下,其中 T(x, y) 是为每个像素计算的阈值:
当 thresholdType 参数为 cv2.THRESH_BINARY 时:
当thresholdType 参数为 cv2.THRESH_BINARY_INV 时:
应用不同自适应阈值方法,进行图像处理:
# 加载图像
image = cv2.imread('example.png')
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 应用自适应阈值处理
thresh1 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
thresh2 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 31, 3)
thresh3 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
thresh4 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 3)
# 可视化
show_img_with_matplotlib(cv2.cvtColor(gray_image, cv2.COLOR_GRAY2BGR), "gray img", 1)
show_img_with_matplotlib(cv2.cvtColor(thresh1, cv2.COLOR_GRAY2BGR), "method=THRESH_MEAN_C, blockSize=11, C=2", 2)
# 其他图像可视化方法类似,不再赘述
# ...
在上图中,可以看到应用具有不同参数的 cv2.adaptiveThreshold() 处理后的输出,自适应阈值可以提供更好的阈值图像。但是,图像中也会出现了很多噪点。为了减少噪点,可以应用一些平滑操作,例如双边滤波,因为它会在去除噪声的同时保持锐利边缘。因此,我们在对图像进行阈值处理之前首先应用 OpenCV 提供的双边滤波函数 cv2.bilateralFilter():
# 加载图像
image = cv2.imread('example.png')
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 双边滤波
gray_image = cv2.bilateralFilter(gray_image, 15, 25, 25)
# 应用自适应阈值处理
thresh1 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
# 之后代码与上一示例想同,不再赘述
# ...
从上图可以看到,应用平滑滤波器后,噪声数量大幅减少。