基于PIL实现验证码生成与MNIST识别验证码

来源:互联网 发布:阿里云部署网站 编辑:程序博客网 时间:2024/06/16 01:37

part 1
在学习验证码识别的一篇博客后,网上学习了如何生成一个验证码图片。在这基础上我进行了一定的改正和学习(这里说一下,伯乐在线不错的学习地方)。
这里准备工作我就借鉴了林炳文的博文了。
1、PIL、pytesser、tesseract
(1)安装PIL:下载地址:http://www.pythonware.com/products/pil/(CSDN下载)
下载后是一个exe,直接双击安装,它会自动安装到C:Python27Libsite-packages中去,
(2)pytesser:下载地址:http://code.google.com/p/pytesser/,(CSDN下载)
(3)Tesseract OCR engine下载:http://code.google.com/p/tesseract-ocr/(CSDN下载)
下载后解压,tessdata文件夹,用其替换掉pytesser解压后的tessdata文件夹即可。(就上面的pytesser文件夹)
2、现在就分部解释如何创建验证码图片的几个主函数
①创建随机生成的背景颜色函数rndColor

#随机生成颜色def rndColor():    return (random.randint(128, 255), random.randint(128, 255), random.randint(128, 255))

这个函数能够创建一个灰度值大于128的像素点,为什么这样设置,是为了方便后面区别文字灰度值为20,这样可以明显的通过二值化图像进行字母数字与噪声背景点的区别。
②生成一个长度为number的数字字母字符串函数gene_text

def gene_text():    source = list(string.letters+string.digits)    for index in range(0,10):        source.append(str(index))    return ''.join(random.sample(source,number))

③绘制干扰线函数gene_line

def gene_line(draw,width,height):     begin = (random.randint(0, width), random.randint(0, height))     end = (random.randint(0, width), random.randint(0, height))     draw.line([begin, end], fill = linecolor)

这里设置了linecolor为(180,180,180),也是为了防止干扰文字颜色,造成二值化图像效果不佳。
④现在就是一个生成验证码图片的函数gene_code

def gene_code():    line_number = random.randint(1,5) #加入干扰线条数的上下限    width,height = size #宽和高    image = Image.new('RGBA',(width,height),bgcolor) #创建图片    draw = ImageDraw.Draw(image) #创建画笔 #调用像素灰度函数,创建一个随机灰度的背景    for x in range(width):        for y in range(height):            draw.point((x, y), fill=rndColor())    text = gene_text() #生成字符串    i = 0    print text #将每个字符填入图像中    for item in text:        draw.text((width/number*i+10, height/3),item,font=None,fill =fontcolor)        i +=1 #这里随机产生1-5条干扰线    while line_number>0:        gene_line(draw,width,height)        line_number -=1    image.save('fourLen.png') #保存验证码图片

这就是生成验证码的各个功能函数,全部代码如下:

# -*-coding:utf-8 -*-import randomimport stringimport sysimport mathfrom PIL import Image,ImageDraw,ImageFont,ImageFilter#生成几位数的验证码number = 4#生成验证码图片的高度和宽度size = (80,20)#背景颜色bgcolor = (255,255,255)#字体颜色fontcolor = (20,20,20)#干扰线颜色linecolor = (180,180,180)#随机生成颜色def rndColor():    return (random.randint(128, 255), random.randint(128, 255), random.randint(128, 255))#用来随机生成一个字符串def gene_text():    source = list(string.letters+string.digits)    for index in range(0,10):        source.append(str(index))    return ''.join(random.sample(source,number))#number是生成验证码的位数#用来绘制干扰线def gene_line(draw,width,height):    begin = (random.randint(0, width), random.randint(0, height))    end = (random.randint(0, width), random.randint(0, height))    draw.line([begin, end], fill = linecolor)#生成验证码def gene_code():    line_number = random.randint(1,5) #加入干扰线条数的上下限    width,height = size #宽和高    image = Image.new('RGBA',(width,height),bgcolor) #创建图片    draw = ImageDraw.Draw(image) #创建画笔    for x in range(width):        for y in range(height):            draw.point((x, y), fill=rndColor())    text = gene_text() #生成字符串    i = 0    print text    for item in text:        draw.text((width/number*i+10, height/3),item,font=None,fill =fontcolor) #填充字符串        i +=1    while line_number>0:        gene_line(draw,width,height)        line_number -=1    image.save('fourLen.png') #保存验证码图片if __name__ == "__main__": gene_code()

来来来,看看效果图吧!
这里写图片描述

part 2
生成了验证码,也就是要来解救自己的验证图片了

# -*-coding:utf-8 -*-import Imageimport ImageEnhanceimport ImageFilterimport sysimport osfrom pytesser import *os.chdir('C:\Python27\Lib\site-packages\pytesser')# 二值化threshold = 128table = []for i in range(256):    if i < threshold:        table.append(0)    else:        table.append(1)def getverify1(name):    #打开图片    im = Image.open(name)    #转化到灰度图    imgry = im.convert('L')    #二值化,采用阈值分割法    out = imgry.point(table,'1')    #识别    text = image_to_string(out)    return textgetverify1('E:\\PythonExample\\fourLen.png')

这里出现一定的问题,发现image_to_string输出的text为空。
我再找找资料解决一下。。。
看下一二值化后的图像吧!
这里写图片描述
等解决了再更吧,我是菜鸟,哈哈!这里也感谢前文的两篇博主。
++++++++++++++++割割++++++++++++++++++++++++++++++++++
生成了验证码,没有识别是件很辛苦的事,通过了解MNIST进行了解,发现可以通过tensorflow进行图片的识别。在ubuntu上安装tensorflow后即可,进行一定train,通过大量的0-9的图片进行学习,然后将上文所述生成的图片进行分割,最终得到了验证码。(目前只含有数字的验证码,所以生成的验证码也只能是四位数的图片)
运行环境:ubuntu14,python2.7(tensorflow目前只支持2.x版本的)
直接附码了:

 # -*- coding: utf-8 -*-from __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionimport gzipimport osimport tempfilefrom PIL import Image,ImageFilterfrom numpy import *from six.moves import urllibfrom six.moves import xrange  import tensorflow as tffrom tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_setsos.environ['TF_CPP_MIN_LOG_LEVEL']='2'mnist = read_data_sets("MNIST_data/",one_hot=True)def weight_variable(shape):    initial = tf.truncated_normal(shape,stddev=0.1)    return tf.Variable(initial)def bias_variable(shape):    initial = tf.constant(0.1,shape=shape)    return tf.Variable(initial)def conv2d(x,W):    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')def max_pool_2x2(x):    return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')def imageprepare(path):#图象处理函数,它用于处理你的手写图片,把图片处理成标准格式便于识别    #你的图片可以在画图中生成,在生成时剪切一下,拖动虚线,使它象素为28*28左右即可,当然也可用相机照一张,再处理也可    im = Image.open(path).convert('L')#打开你书写的图片,转化成黑白的(L表示黑白模式)    #建立一个二维数组返回分割好的四张图片    temp = []    for i in range(4):        region = [i*28,0,(i+1)*28,28]#region(x0,y0,x1,y1)        crp = im.crop(region)#分割函数        tva= list([(255-x)*1.0/255.0 for x in crp.getdata()])        temp.append(tva)    return tempx = tf.placeholder("float",[None,784])y_= tf.placeholder("float",[None,10])W = tf.Variable(tf.zeros([784,10]))b = tf.Variable(tf.zeros([10]))y = tf.nn.softmax(tf.matmul(x,W)+b)#第一层卷积 W_conv1 = weight_variable([5,5,1,32])b_conv1 = bias_variable([32])x_image = tf.reshape(x,[-1,28,28,1])#第一层最大池化h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)h_pool1 = max_pool_2x2(h_conv1)#第二层卷积 W_conv2 = weight_variable([5,5,32,64])b_conv2 = bias_variable([64])#再池化h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)h_pool2 = max_pool_2x2(h_conv2)#密集连接,全连接层,处理整个图片W_fc1 = weight_variable([7*7*64,1024])b_fc1 = bias_variable([1024])h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)#减少过拟合keep_prob = tf.placeholder("float32")h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)#输出层W_fc2 = weight_variable([1024,10])b_fc2 = bias_variable([10])y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))accuracy = tf.reduce_mean(tf.cast(correct_prediction,"float"))sess = tf.InteractiveSession()sess.run(tf.global_variables_initializer())for i in range(20000):    batch_xs,batch_ys = mnist.train.next_batch(50)    if i%100==0:        train_accuracy = accuracy.eval(feed_dict={x:batch_xs,y_:batch_ys,keep_prob:1.0})        print("step %d, training accuracy %g"%(i,train_accuracy))    train_step.run(feed_dict={x:batch_xs,y_:batch_ys,keep_prob:0.5})print("test accuracy %g"%accuracy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))imvalue = imageprepare("fourLen.png")#用类的实例调用类的图片处理函数处理图片,这个图片要放在当前目录下prediction = tf.argmax(y_conv,1)num = []for item in range(4):    num.extend(prediction.eval(feed_dict={x:[imvalue[item]],keep_prob:1.0}))print(num)print ('------------------------------------------------------------------')

这里推荐看一下这位贴心哥哥的博客,很用心的写了MNIST的一些过程。当然也可以看着tensorflow官方网站进行阅读和了解。
最后生成验证对比图:
这里写图片描述
遇到的问题呢有很多,我记下怎么解决的:
一、在虚拟机上运行ubuntu进行tensorflow时,发现内存根本不够用?
解决办法:只能装双系统了,不推荐用centos,因为后面还要安装tflearn,以及git tflearn仓库时,发现不必要的麻烦。
二、错误:
W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn’t compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.
这里写图片描述
解决:在py文件头加入下面两行代码即可
import os
os.environ[‘TF_CPP_MIN_LOG_LEVEL’]=’2’
三、predict结果不准确?
解决:训练次数过少,导致predict的准确率不高。(当时为了省事就只弄1000次,远远不行呢)
四、其他输出错误问题?
解决宗旨,一步步输出,找到出错行,然后进行详细问题google解决。

原创粉丝点击