Python用KNN算法实现验证码识别

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Python用KNN算法实现验证码识别

作为一名爬虫爱好者,把互联网作为数据库的同时总会遇到很多坑,其中一个就是验证码,设置验证码一大理由就是为了限制你乱爬,不过对于很多简单的验证码,破解还是相当容易的。比如类似下面这种。最简单的办法是直接用pytesseract库,具体方法请自行搜索。当然如果不想用它,自己来写一个识别算法也并不难。可以用机器学习里面比较基础的KNN算法。

先来介绍一下这个KNN算法,他全称叫K最近邻(kNN,

k-NearestNeighbor),所谓K最近邻,就是离谁最近,是谁的可能性就更大。什么意思,举个例子就明白了。

我现在已经统计了一组手机数据,方便起见,假设只有高端机和低端机两个分类,如下:此时如果有一个新手机T(1500元,15小时),该怎么判断是什么手机呢?我把它们放到同一个坐标系中去比较一下。它并不能很好地跟已知数据完全重合,但不要紧,可以算一下它与其他手机的距离。经过计算,与T的距离D就是这么简单。当然了,这里面只是举个例子所以数据量比较小,当数据量足够大时,比如有200台低端机和300台高端机,选出最接近的200个数据,其中哪种机器多就归到哪种,得出的结论就会比较准确。这就是最简单的KNN算法,离哪个近,就把它归类为哪个种类。这

是二维,还可以再加个“像素”属性,变为三维,仍然可以求最近距离。拓展到N个属性也是一样的道理。基本原理就是这样,下面来介绍如何识别验证码,以下代码基于Python3 还是这张验证码,我们把它放大一点可以看到,其实他就是一个一个的像素点构成的。

里面颜色太多不好操作,首先把这张图变成黑白的from PIL import Image#引入Image类

im = Image.open('图片路径')#打开图片

im=im.convert('1')#原来图片是彩色的,这里把图片转换成模式'1',即黑白的

im.show()#显示图片

于是我们就得到了这么一张图

可以把每个点的颜色转变成0和1,并打印出来for i in range(im.size[1]):

temp=[]

for j in range(im.size[0]):

pos=(j,i)

col=im.getpixel(pos)

#获取某坐标的点的颜色,黑色为0,白色为255,为了显示规程,把它转变成1了

if col==255:

col=1

temp.append(col)

print(temp)

可以从打印出来的字符中隐约看到这几个数字

然后处理一下这串字符,把不连续的点,即上下左右都没有同色的点去掉

im2 = im

for i in range(im.size[1]):

for j in range(im.size[0]):

#pos=(j,i)

#print(pos)

if i==0 or j==0 or i==im.size[1]-1 or

j==im.size[0]-1:

im2.putpixel((j,i),255)#图片最外面一周都换成白点

elif im.getpixel((j,i))!=im.getpixel((j-1,i)) and im.getpixel((j,i))!=im.getpixel((j+1,i)) and

im.getpixel((j,i-1))!=im.getpixel((j,i)) and

im.getpixel((j,i+1))!=im.getpixel((j,i)):

im2.putpixel((j,i),255)#不连续点也都换成白点

然后开始切割图片

inletter = False

foundletter = False

start = 0

end = 0

letters = []#用来记录每个数字的起始位置

for x in range(im2.size[0]):

for y in range(im2.size[1]):

pix = im2.getpixel((x, y))

if pix != 255:

inletter = True#如果不是白色,这说明已经开始接触到数字了

if foundletter == False and inletter == True:

foundletter = True

start = x#数字的起始坐标

if foundletter == True and inletter == False:

foundletter = False

end = x-1#数字的结束位置

letters.append((start, end))

inletter = False

letters的值为[(7,

14), (20, 27), (33, 40), (46, 54)],就是每个数字的起始X坐标,同样道理获得每个数字的起始Y坐标,然后切割开来。region = (起始X值,起始Y值,结束X值,结束Y值) #裁切图片

im3 = im2.crop(region)#im3就是这个区域内的图形,也就是提取的数字

#im3.show()

于是得出了四个切割好的数字

这个时候怎么做呢,我们把第一个数字9用0和1来打印看看。[1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0,

0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1,

1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1,

1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,

0, 1, 1, 0, 0, 1, 0, 1]总大小7*14,总共98个点到这里差不多就出来了,把每个点看成一个属性,问题就转化成了:已知一个数有98个属性,也知道他的种类是9,同样,还有很多很多这样的数,知道属性+种类。然后要做的,就是拿N 个样本作为标准集合,有新的数要识别的时候,选出最接近

相关文档
最新文档