前面咱们学习了 Python 的图像处理库 PIL,学会了一些相关的图像处理方法,好多人内心会问:有什么用呢?这一节咱们就拿实际的例子来回答你们。算法
如今大多数网站登陆再也不是简单地输入用户名密码了,通常都伴随着此两者以外的验证手段,目的是阻止一些居心不良的行为。而图片验证码是其中一种比较经常使用的手段。所谓道高一尺魔高一丈,在 IT 行业中,对于这种安全防守,确定会有针对性地破解势力。对于图片验证码的识别破解,目前已经有了不少成熟的方法。我想大概是从自动抢火车票兴起以后快速发展而来的吧。安全
首先咱们来看一张未处理的验证码图片:bash
想要识别验证码,咱们须要有一套图片识别算法(这个目前已经有成熟的应用,你们能够自行搜索),而后拿到足够多的样本去喂养它,让它不断地自我学习,不断提高识别准确率。在喂养算法以前,咱们首先要作的就是对原始图片进行处理,通常包括的步骤是:app
通过这三步处理以后,通常图片的验证码数字或者字母会比较明显好辨别了。函数
下面咱们以上面那张简单的验证码图片为例,来运用 Python 的 PIL 库的方法对图片进行去噪处理。学习
什么事灰度图呢?灰度图,也能够认为是黑白图。咱们知道彩色图片是有不一样的颜色的像素组合到一块儿的,灰度图能够相似的认为是由不一样灰度值的像素组合在一块儿后呈现出来的。网站
任何颜色都有红、绿、蓝三原色组成,假如原来某点的颜色为 RGB(R,G,B),那么,咱们能够经过下面几种方法,将其转换为灰度:ui
Gray=R*0.3+G*0.59+B*0.11
复制代码
Gray=(R*30+G*59+B*11)/100
复制代码
Gray =(R*76+G*151+B*28)>>8
复制代码
Gray=(R+G+B)/3
复制代码
Gray=G
复制代码
经过上述任一种方法求得Gray后,将原来的RGB(R,G,B)中的R,G,B统一用Gray替换,造成新的颜色RGB(Gray,Gray,Gray),用它替换原来的RGB(R,G,B)就是灰度图了。spa
咱们用代码实现很是简单:3d
from PIL import Image
# 打开原始图片
im = Image.open('vc.png')
# 展现原始图片
im.show()
# 将原始图片灰度化
grey_im = im.convert('L')
# 展现灰度化图片
grey_im.show()
# 保存灰度化图片
grey_im.save('grey.png')
复制代码
运行上面代码后,咱们能够看到转换后的灰度图了,以下所示:
咱们已经获得了灰度图,接下来就是将灰度图二值化。所谓二值化就是将灰度图像转换成由黑白二色组成的图像。思路就是肯定一个阈值,大于阈值的像素表示为白色,小于阈值的像素表示为黑色,以此将图片的像素(灰度值)划分为两部分:0和1,例如0表明黑色,1表明白色,而后咱们就能够用一串0和1组成的数字来表示一张图片。
from PIL import Image
# 二值处理
# 设定阈值threshold,像素值小于阈值,取值0,像素值大于阈值,取值1
# 阈值具体多少须要屡次尝试,不一样阈值效果不同
def get_table(threshold=115):
table = []
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(1)
return table
# 打开灰度化图片并进行二值处理
binary_im = Image.open('grey.png').point(get_table(120), "1")
# 展现二值化图片
binary_im.show()
# 保存二值化图片
binary_im.save('binary.png')
复制代码
咱们首先定义了一个二值处理的方法,该方法就是根据传入的一个阈值,将0到256之间的数进行分类,大于这个阈值取1,小于阈值取0。而后咱们使用 Image 的 point 方法,该方法针对传入的函数对每个像素点进行操做。咱们传入二值处理方法,对每一个像素点进行二值化处理,将图片转换成二值图片。
这里的阈值是须要你们尝试以后才能肯定的,不一样的图片,在阈值不一样时会出现不一样的处理效果,你们须要用不一样的阈值去处理,查看处理以后的效果图,找到比较合理的阈值。本例中使用的是120。
通过二值化处理以后,咱们的图片变成了下面这样:
咱们看二值化后的图片,能够看到还有一些干扰线,这些线条也会影响算法的识别准确率,因此咱们须要想办法去掉这些干扰线。
降噪的方法有不少,主要难点是判断哪些点是噪点。因为咱们这张验证码图片上的数字和字母的线条比干扰线的线条粗,所以咱们认为字母和数字线条上的点周围8个点范围内黑色点的个数应该比干扰线上的点要多。所以咱们这里采用的思路是:
根据一个点 A 的 RGB 值,与周围的8个点的 RBG 值比较,设定一个值 N(0 <N <8),当 A 的 RGB 值与周围8个点的 RGB 相等数小于 N 时,此点为噪点。
对应的程序代码为:
from PIL import Image, ImageDraw
# 判断噪点,若是确认是噪点,用该点的上面一个点的灰度进行替换
# 根据一个点A的RGB值,与周围的8个点的RBG值比较,设定一个值 N(0 <N <8),当A的RGB值与周围8个点的RGB相等数小于N时,此点为噪点
# x, y: 像素点坐标
# G: 图像二值化阀值
# N: 降噪率 0 < N <8
def get_pixel(image, x, y, G, N):
# 获取像素值
L = image.getpixel((x, y))
# 与阈值比较
if L > G:
L = True
else:
L = False
nearDots = 0
if L == (image.getpixel((x - 1, y - 1)) > G):
nearDots += 1
if L == (image.getpixel((x - 1, y)) > G):
nearDots += 1
if L == (image.getpixel((x - 1, y + 1)) > G):
nearDots += 1
if L == (image.getpixel((x, y - 1)) > G):
nearDots += 1
if L == (image.getpixel((x, y + 1)) > G):
nearDots += 1
if L == (image.getpixel((x + 1, y - 1)) > G):
nearDots += 1
if L == (image.getpixel((x + 1, y)) > G):
nearDots += 1
if L == (image.getpixel((x + 1, y + 1)) > G):
nearDots += 1
if nearDots < N:
return image.getpixel((x, y - 1))
else:
return None
# 降噪
# Z: 降噪次数
def clear_noise(image, G, N, Z):
draw = ImageDraw.Draw(image)
for i in range(0, Z):
for x in range(1, image.size[0] - 1):
for y in range(1, image.size[1] - 1):
color = get_pixel(image, x, y, G, N)
if color is not None:
draw.point((x, y), color)
# 打开二值化图片
b_im = Image.open('binary.png')
# 将二值化图片降噪
clear_noise(b_im, 50, 4, 4)
# 展现降噪后的图片
b_im.show()
# 保存降噪后的图片
b_im.save('result.png')
复制代码
在本例中,咱们设置的二值化阈值为50,降噪率为4,降噪次数为4.这几个参数也是不一样的图片会有不一样的值,你们须要根据不一样的图片自行设定。
降噪后的图片效果以下:
咱们能够看到,通过上面的处理以后,图片上的字母和数字已经很清晰了,再使用图片识别算法,准确率应该会很高。
除了上面的步骤,咱们还能够经过 PIL 库的 ImageEnhance 和 ImageFilter 对图片作其余处理,例如增长对比度、亮度、锐化等,最终的目的都是去除图片的噪点,是图片更容易辨别。你们若是感兴趣的话能够试试看。
本节咱们经过使用 PIL 库的一些简单方法,对验证码图片进行一系列的处理,从而达到降噪的目标。经过本节的学习,你们应该要学会学以至用,运用咱们学习的一些理论知识去解决工做或生活中遇到的实际问题。 PIL 库还有不少其余的方法均可以用来对图片进行不一样的处理,你们能够本身去探索。