想要识别验证码,收集足够多的样本后,首先要做的就是对验证码原始图片进行处理,对验证码识别分类之前,一般包括:将彩色图片转换成灰度图、将灰度图二值化和去除噪点三个基本过程。这里仅以比较简单的验证码为例,介绍一下如何通过Python的PIL库对图片去噪处理。
首先看一下未经处理的验证码图片:
对图片处理主要使用了PIL库的Image类。
1、彩色图片转换成灰度图首先使用Image的open方法打开上面的图片,可以得到一个PIL.Image.Image对象,之后就可以调用convert、filter、point和putpixel等方法来处理图片。
我们可以通过convert方法将上面的彩色图片转换成灰度图:
# encoding=utf8 from PIL import Image def main(): image = Image.open('RandomPicture.png') imgry = image.convert('L') imgry.save('gray.png') if __name__ == '__main__': main()
运行结果:
通过保存的图片可以看出来,已经由原来的彩图变成了灰度图,或者也可以认为是黑白图。什么叫灰度图?我们知道彩色图片是由不同的颜色的像素组合到一起的,那灰度图可以类似的认为是由不同灰度值的像素组合在一起后呈现出来的。任何颜色都有红、绿、蓝三原色组成,假如原来某点的颜色为RGB(R,G,B),那么,我们可以通过下面几种方法,将其转换为灰度:
1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
2.整数方法:Gray=(R*30+G*59+B*11)/100
3.移位方法:Gray =(R*76+G*151+B*28)>>8;
4.平均值法:Gray=(R+G+B)/3;
5.仅取绿色:Gray=G;
通过上述任一种方法求得Gray后,将原来的RGB(R,G,B)中的R,G,B统一用Gray替换,形成新的颜色RGB(Gray,Gray,Gray),用它替换原来的RGB(R,G,B)就是灰度图了。
用代码实现看一下:
# encoding=utf8 from PIL import Image def main(): image = Image.open('RandomPicture.png') print ('image mode: ', image.mode) print (image.getpixel((0, 0))) print ('-' * 40) imgry = image.convert('L') print ('imgry mode: ', imgry.mode) print (imgry.getpixel((0, 0))) if __name__ == '__main__': main()
运行结果:
image mode: RGB
(234, 235, 236)
----------------------------------------
imgry mode: L
234
[Finished in 0.1s]
代码说明:
通过image.mode方法可以获得当前的PIL.Image.Image对象(也就是当前打开的图片)的mode值,而mode值表示图片的单位颜色是由RGB三个值组成的还是由灰度值组成的;
而getpixel可以获取某个像素的RGB值或者灰度值。我们知道图片是由许多像素组成的,每个像素在图片上都有一个对应的坐标x和y,而“(0, 0)”就表示该图片左上角顶点的像素。
由上面的结果我们可以知道,在将图片转换成灰度图之前,“(0, 0)”代表的像素的颜色是由RGB组成的:(21, 10, 26);在通过concert将彩色图片转换成灰度后,“(0, 0)”代表的像素的颜色值就变成了一个值:“15”,通过打印imgry.mode我们也可以知道,此时图片已经变成了灰度图,它的每一个像素的颜色都变成了一个灰度值。
其实这时候我们也可以简单的计算一下,使用前面说的浮点算法将上面的(21, 10, 26)三个值带入计算:
>>> 21*0.3+10*0.59+26*0.11
15.059999999999999
结果显示确实由浮点算法将RGB值变成了灰度值。
2、灰度图二值化我们已经得到了灰度图,接下来就是将灰度图二值化。所谓二值化就是将灰度图像转换成由黑白二色组成的图像。思路就是确定一个阈值,大于阈值的像素表示为白色,小于阈值的像素表示为黑色,以此将图片的像素(灰度值)划分为两部分:0和1,例如0代表黑色,1代表白色,然后我们就可以用一串0和1组成的数字来表示一张图片。
将灰度图二值化会用到point方法,它可以接收一个灰度转二值的映射table,具体原理暂时还没弄明白,代码实现过程是这样的: