前言
今天这篇文章主要记录一下如何切分验证码,用到的主要库就是Pillow和Linux下的图像处理工具GIMP。首先假设一个固定位置和宽度、无粘连、无干扰的例子学习一下如何使用Pillow来切割图片。
使用GIMP打开图片后,按 加号 放大图片,然后点击View->Show Grid来显示网格线:
其中,每个正方形边长为10像素,所以数字1切割坐标为左20、上20、右40、下70。以此类推可以知道剩下3个数字的切割位置。
代码如下:
from PIL import Imagep = Image.open("1.png")# 注意位置顺序为左、上、右、下cuts = [(20,20,40,70),(60,20,90,70),(100,10,130,60),(140,20,170,50)]for i,n in enumerate(cuts,1): temp = p.crop(n) # 调用crop函数进行切割 temp.save("cut%s.png" % i)
切割后得到4张图片:
那么,如果字符位置不固定怎么办呢?现在假设一种随机位置宽度、无粘连、无干扰线的情况。
第一种方法,也是最简单的方法叫做”投影法”。原理就是将二值化后的图片在竖直方向进行投影,根据投影后的极值来判断分割边界。这里我依然使用上面的验证码图片来进行演示:
def vertical(img): """传入二值化后的图片进行垂直投影""" pixdata = img.load() w,h = img.size ver_list = [] # 开始投影 for x in range(w): black = 0 for y in range(h): if pixdata[x,y] == 0: black += 1 ver_list.append(black) # 判断边界 l,r = 0,0 flag = False cuts = [] for i,count in enumerate(ver_list): # 阈值这里为0 if flag is False and count > 0: l = i flag = True if flag and count == 0: r = i-1 flag = False cuts.append((l,r)) return cutsp = Image.open('1.png')b_img = binarizing(p,200)v = vertical(b_img)
通过vertical函数我们就得到了一个包含所有黑色像素在X轴上投影后左右边界的位置。由于验证码没有任何干扰,所以我的阈值设定为0。 关于binarizing函数可以参考上一篇文章
输出如下:
[(21, 37), (62, 89), (100, 122), (146, 164)]
可以看到,投影法给出左右边界和我们手工查看得到很接近。对于上下边界,偷懒的可以直接使用0和图片的高度,也可以在水平方向进行投影,这里有兴趣的小伙伴可以自己尝试。
但是,对于字符间有粘连的情况,投影法就会出现拆分错误,比如上篇文章中的:
修改阈值为5后,投影法给出的左右边界是:
[(5, 27), (33, 53), (59, 108)]
新闻热点
疑难解答