vlambda博客
学习文章列表

图形验证码识别——图像预处理:二值化

上一篇推文中验证码识别出现了错误,因为前景验证码K4P8和背景中的纹理颜色接近, Tesserocr库无法对原始图片准确识别,就需要对原始图片进行预处理来提高图片质量。

https://github.com/tesseract-ocr/tesseract/wiki/ImproveQuality

Tesserocr 分享了常用的预处理方法:重采样、二值化、噪声消除、边框消除、旋转…(非图像专业,部分术语可能不准确)

以下为大家分享图像二维码识别中最常用的预处理方法: 图像二值化


什么是图像二值化

图像的二值化,就是将图像变成黑白两种颜色。对图像进行二值化,可以忽略图像的颜色、背景信息,保留更加重要的形态信息,使得图像的信息量大为减少,处理起来也更加方便。
最简单的图像二值化的方法。就是先将图像转化为灰度图,然后再设置一个阈值。小于这个阈值的像素点调整成0,而大于这个阈值的像素点调整成255。
对于阈值的设置总体有两种方式:一张图一个阈值(全局阈值);分块多个阈值(动态阈值)。多个阈值复杂度更高,但相对效果更好。
全局阈值适用于大部分图像二值化,以下分享全局阈值的使用方式。


图形验证码识别——图像预处理:二值化

全局阈值——otsu算法(自实现版)


otsu算法 原理非常简单,以下文章有原理推导

https://blog.csdn.net/weixin_40647819/article/details/90179953

总结以下:

首先,我们把图像分成大于阈值和小于阈值的两个部分,也就是前景与背景两个部分。我们可以计算这两个部分的类间方差。类间方差越大,就说明两个部分直接的灰度差距越大。将0~255这256个阈值都尝试一遍,找到类间方差最大的值,通常就是我们要找的最佳阈值了。

根据算法推导,算法和测试代码如下:
import numpy as npfrom PIL import Imageimport tesserocr
def otsu_threshold(im): width, height = im.size pixel_counts = np.zeros(256) for x in range(width): for y in range(height): pixel = im.getpixel((x, y)) pixel_counts[pixel] = pixel_counts[pixel] + 1 # 得到图片的以0-255索引的像素值个数列表 s_max = (0, -10) for threshold in range(256): # 遍历所有阈值,根据公式挑选出最好的 # 更新 w_0 = sum(pixel_counts[:threshold]) # 得到阈值以下像素个数 w_1 = sum(pixel_counts[threshold:]) # 得到阈值以上像素个数 # 得到阈值下所有像素的平均灰度 u_0 = sum([i * pixel_counts[i] for i in range(0, threshold)]) / w_0 if w_0 > 0 else 0 # 得到阈值上所有像素的平均灰度 u_1 = sum([i * pixel_counts[i] for i in range(threshold, 256)]) / w_1 if w_1 > 0 else 0 # 总平均灰度 u = w_0 * u_0 + w_1 * u_1 # 类间方差 g = w_0 * (u_0 - u) * (u_0 - u) + w_1 * (u_1 - u) * (u_1 - u) # 类间方差等价公式 # g = w_0 * w_1 * (u_0 * u_1) * (u_0 * u_1) # 取最大的 if g > s_max[1]: s_max = (threshold, g) return s_max[0] if __name__ == "__main__": image = Image.open('yzm.jpg')    image = image.convert('L'#rgb转h灰度图 threshold = otsu_threshold(image)#调用算法 blackwhite = image.point(lambda x: 0 if x < threshold else 255, '1') blackwhite.show()    print(tesserocr.image_to_text(blackwhite)) 

    代码输入如下图片,文字识别正确。

图形验证码识别——图像预处理:二值化

图形验证码识别——图像预处理:二值化


otsu算法——skimage库

使用方法参考如下:

https://scikit-image.org/docs/dev/auto_examples/segmentation/plot_thresholding.html#sphx-glr-auto-examples-segmentation-plot-thresholding-py


测试代码如下:

import numpy as npfrom skimage.filters import threshold_otsufrom skimage import io,color,img_as_uint
if __name__ == "__main__": image = io.imread('yzm.jpg',as_gray=True) width,height = image.shape thresh = threshold_otsu(image) for x in range(width): for y in range(height): if image[x,y] < thresh: image[x,y] = 0 else: image[x,y] = 1 io.imsave('yzm_copy.jpg', image)


skimage 库真的很简单……


两篇文章结合一下,图形验证码完成!