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

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 random
import string
import sys
import math
from 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 Image
import ImageEnhance
import ImageFilter
import sys
import os
from pytesser import *
os.chdir('C:\Python27\Lib\site-packages\pytesser')
# 二值化
threshold = 128
table = []
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 text
getverify1('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_import
from __future__ import division
from __future__ import print_function

import gzip
import os
import tempfile
from PIL import Image,ImageFilter
from numpy import *
from six.moves import urllib
from six.moves import xrange  
import tensorflow as tf
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets
os.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 temp
x = 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解决。

猜你喜欢

转载自blog.csdn.net/qq_15508113/article/details/73010620