验证码识别是一个适合入门机器学习的项目,之前用knn 做过一个很简单的,这次用svm来实现。svm直接用了开源的库libsvm。验证码选的比较简单,代码也写得略乱,大家看看就好。
1. 爬取验证码图片
1 import urllib 2 from urllib import request 3 4 5 def download_pics(pic_name): 6 url = 'http://smart.gzeis.edu.cn:8081/Content/AuthCode.aspx' 7 res = request.urlopen(url) 8 get_img = res.read() 9 10 with open( 'D:\python\验证码\%s.jpg'%(pic_name),'wb') as f: 11 f.write(get_img) 12 13 if __name__ == '__main__': 14 for i in range(100): 15 pic_name = i 16 download_pics(pic_name)
2. 二值化
接下来要做的工作就是二值化验证码,所谓二值化,就是将每一个像素点用0或1来表示,图像的每个像素点都有rgb三个值,我们首先转化成灰度图,这样每个像素点就只有一个灰度值了。接下来根据自己设定的阈值来确定每个像素点是该为0还是为1。
我的思路是首先将图像转化为array处理,当然完全可以直接图像处理。
1 def binarization(im): #二值化 2 imgry = im.convert('L') 3 imgry = np.array(imgry) #将图像转化为数组 4 height, width = imgry.shape 5 #f = open('s.txt','w') 6 for i in range(height): 7 for j in range(width): 8 gray = imgry[i,j] 9 if gray <= 220: #阈值设为220 10 imgry[i, j] = 0 11 else: 12 imgry[i, j] = 1 13 #f.write(str(imgry[i,j])) #输出到txt查看 14 #f.write('\n') 15 ''' 16 plt.figure('') 17 plt.imshow(imgry, cmap='gray') 18 plt.axis('off') 19 plt.show() 20 ''' 21 return imgry
在二值化处理之后,处理结果如下所示:
在txt的结果如下所示,可以很明显的看到0413:
3. 去除噪点
在二值化之后,还存在一个问题就是图像之中还有许多黑点,这成为噪点,是干扰项,去除噪点有很多不同的方法,由于我只是一个小菜鸟,所以我就用了最简单的8-邻域去除噪点法。依次检查每个像素点周围8个点的情况,如果黑点少于阈值时,那么就可以认为该点是噪点。其实这样的处理效果是比较差的,只是适用于去除小点,但是对于干扰线条这种可能就没什么作用了。
1 def noiseReduction(imgry): #去除噪点 2 global dx, dy 3 height, width = imgry.shape 4 for i in range(height): 5 for j in range(width): 6 cnt = 0 7 if imgry[i, j] == 1: #白点不用管 8 continue 9 else: 10 for k in range(8): 11 x = dx[k] + i 12 y = dy[k] + j 13 if x < 0 or x >= height or y < 0 or y >= width: 14 continue 15 if imgry[x, y] == 0: 16 cnt += 1 17 if cnt < 4: #周围少于4点就算噪点 18 imgry[i, j] = 1 19 return imgry
处理之后可以明显的看到黑点基本上都被处理掉了。
4. 图片分割
接下来要做的就是将这四个数字分割开来形成训练集,这个操作并不难。因为这些验证码的位置都是差不多的,如果验证码字符位置比较乱的话就会比较麻烦。。
1 def cutImg(img): #图像切割 2 s = 12 3 w = 40 4 h = 81 5 t = 0 6 cut_img = [] 7 for i in range(4): 8 pic = img.crop((s + w * i, t, s + w * (i + 1), h)) 9 cut_img.append(pic) 10 return cut_img
5. 图片分类
这个步骤的目的就是人为的给训练集打上标签。 将相同的数字放在同一个文件夹下面。
6. 训练模型
训练模型很简单,因为直接就是使用libsvm库,我们只需要按照数据格式生成一些特征值即可。在切割完图片并保存之后,我发现我图片的像素值有略微的改变,可能是重新保存了的原因,所有我这里又进行了一次二值化。。。
这里说明依稀libsvm数据格式的要求:
[label] [index:value] [index:value] [index:value].....
每一个数据都是这样的格式,label是标签,[index:value]是数据的特征值,index就是从0开始的编号,value是特征值。
在这里对于每一张图片,我就把特征值设为每行每列的黑点个数了。如第一个特征值就是第一行黑点个数。。。
1 import os 2 from PIL import * 3 from PIL import Image 4 import numpy as np 5 from libsvm.python.svmutil import * 6 from libsvm.python.svm import * 7 8 9 address = 'D:\python\验证码-sort\\' 10 f = open('train.txt', 'w') 11 12 def get_feature(dir, file): 13 f.write(dir) 14 im = Image.open(address + dir +'\\' + file) 15 imarr = np.array(im) 16 height, width = imarr.shape 17 for i in range(height): 18 for j in range(width): 19 gray = imarr[i,j] 20 if gray <= 150: 21 imarr[i, j] = 0 22 else: 23 imarr[i, j] = 255 24 im = Image.fromarray(imarr) 25 count = 0 26 width, height = im.size 27 for i in range(height): 28 c = 0 29 for j in range(width): 30 if im.getpixel((j, i)) == 0: c += 1 31 f.write(' %d:%d'%(count, c)) 32 count += 1 33 for i in range(width): 34 c = 0 35 for j in range(height): 36 if im.getpixel((i, j)) == 0: c += 1 37 f.write(' %d:%d'%(count, c)) 38 count += 1 39 f.write('\n') 40 41 def train_svm_model(): 42 y, x = svm_read_problem('train.txt') 43 model = svm_train(y, x) 44 svm_save_model('model_file', model) 45 46 if __name__ == '__main__': 47 dirs = os.listdir(address) 48 for dir in dirs: 49 files = os.listdir(address + dir) 50 for file in files: 51 get_feature(dir, file) 52 train_svm_model()
7. 测试模型
用测试数据对模型进行测试。
1 from libsvm.python.svmutil import * 2 from libsvm.python.svm import * 3 import image_slove 4 5 if __name__ == '__main__': 6 model = svm_load_model('model_file') 7 yt, xt = svm_read_problem('test.txt') 8 p_label, p_acc, p_val = svm_predict(yt, xt, model)
还是不错的,毕竟验证码很简单。。。
8. 预测验证码
终于走到最后一步了,得到一张验证码后先按照之前的操作根据该图片生成特征值,这里标签还是需要的,可以随便填一个,反正这个不重要。或许有别的方法,反正我暂时还不知道。
1 from libsvm.python.svmutil import * 2 from libsvm.python.svm import * 3 from PIL import Image 4 import image_slove 5 6 if __name__ == '__main__': 7 ''' 8 在这里处理图片生成特征值 9 ''' 10 model = svm_load_model('model_file') 11 yt, xt = svm_read_problem('predict.txt') 12 p_label, p_acc, p_val = svm_predict(yt, xt, model) 13 print('该验证码为:', end='') 14 for label in p_label: 15 print(int(label), end='')
最后成功的验证出来了。
9. 总结
通过这个实验对于验证码识别流程有了一定的了解,这次也是直接使用了支持向量机,后续需要稍微学习一下。