最近因为做的一件事情需要对图片验证码进行识别,几年前因为怕麻烦,逃避困难,所以没有做。但这次却必须要做,先是收集各种资料,选择最简单的一种实现方法。看到了C#和python的资料比较多,也比较简单,最后还是选择了python进行实现。
首先找到的方法是使用python开源代码PyTesser进行实现,这个方法网上资料比较多,而且实现也比较容易(调用的时候代码较少,封装的比较好)。
官方地址:https://code.google.com/p/pytesser/
官方demo也比较简单:
>>> from pytesser import *
>>> image = Image.open('fnord.tif') # Open image object using PIL
>>> print image_to_string(image) # Run tesseract.exe on image
fnord
>>> print image_file_to_string('fnord.tif')
fnord
第一行就是导入模块,第二行是打开测试的图片,第三行就是将图片识别出来的结果显示出来。
代码非常简单,但是这个东西我正式的时候看到了网上说依赖较多,于是先下载了两个辅助包程序。
第一个是:tesseract-ocr 下载地址:https://code.google.com/p/tesseract-ocr/downloads/list,我这里是win7,所以选择:tesseract-ocr-setup-3.02.02.exe进行下载安装。
第二个是:ocr-uvg 下载地址:https://code.google.com/p/ocr-uvg/downloads/list,我这里是win7,python 2.7.3环境所以选择:PIL-1.1.7.win32-py2.7.exe进行下载安装。
有人安装好了这两个包后还是无法运行成功,但是我这里是运行成功了的。下面上个图吧:
有人说PyTesser只能够支持tif、tiff格式的图片,但是我这里测试了除了支持png外,我尝试了gif貌似也支持。
本来以为验证码的破解已经结束了,但是在正式使用识别的时候发现错误率太高了,好多识别不出来啊。
因此有了第二种方法,这种方法也来自网络,这里记录一下:
主要参考这两篇文章:
https://blog.feshine.net/technology/1163.html
https://blog.feshine.net/technology/1164.html
第一步:批量下载50个验证码来取字库,这里使用python脚本来实现:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#下载样本图片
import urllib
for i in range(50):
url = 'https://yourtarget.com/Code.aspx' #验证码的地址
print "download", i
file("./pic/%04d.gif" % i, "wb").write(urllib.urlopen(url).read())
然后可以在pic目录下看到下载的50张gif图片了。
第二步:再参考上面的第二篇文章进行图片的二值化处理。从pic目录中逐个读出图片,然后将每张图片都二值化处理后存入font目录中。以后提取字符就提取font目录中的结果。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#图像二值处理
import os
from PIL import Image
j=1
dir="./pic/"
path = "./font/"
for f in os.listdir(dir):
if f.endswith(".gif"):
img = Image.open(dir+f) # 读入图片
img = img.convert("RGBA")
pixdata = img.load()
#二值化
for y in xrange(img.size[1]):
for x in xrange(img.size[0]):
if pixdata[x, y][0] < 90:
pixdata[x, y] = (0, 0, 0, 255)
for y in xrange(img.size[1]):
for x in xrange(img.size[0]):
if pixdata[x, y][1] < 136:
pixdata[x, y] = (0, 0, 0, 255)
for y in xrange(img.size[1]):
for x in xrange(img.size[0]):
if pixdata[x, y][2] > 0:
pixdata[x, y] = (255, 255, 255, 255)
img.save(path+f, "GIF")
第三步:对处理后font目录下的图片进行图像分割。图片分割后的结果保存在fonts目录中,命名规则按数字命名。注意:里面的x、y坐标像素需要自己按照特定验证码进行微调。精确到像素,可以使用photoshop进行详细分析。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#图像分割
import os ,Image
j = 1
dir="./font/"
for f in os.listdir(dir):
if f.endswith(".gif"):
img = Image.open(dir+f)
for i in range(4):
x = 16 + i*15 #这里的数字参数需要自己
y = 2 #根据验证码图片的像素进行
img.crop((x, y, x+7, y+10)).save("fonts/%d.gif" % j) #适当的修改
print "j=",j
j += 1
第四步:对本地的验证码进行识别验证。读取pic目录下的图片,然后将结果保存在result中,命名规则按照识别出来验证码值命名如下:(我这里发现参考文章中有两处需要修改,否则,我这里无法显示结果)
#!/usr/bin/env python
# ?*? coding: UTF?8 ?*?
import os, Image
def binary(f): #图像的二值化处理
print f
img = Image.open(f)
#img = img.convert('1')
img = img.convert("RGBA") #参考文章中无该行,无该行,我这里会报错
pixdata = img.load()
for y in xrange(img.size[1]):
for x in xrange(img.size[0]):
if pixdata[x, y][0] < 90:
pixdata[x, y] = (0, 0, 0, 255)
for y in xrange(img.size[1]):
for x in xrange(img.size[0]):
if pixdata[x, y][1] < 136:
pixdata[x, y] = (0, 0, 0, 255)
for y in xrange(img.size[1]):
for x in xrange(img.size[0]):
if pixdata[x, y][2] > 0:
pixdata[x, y] = (255, 255, 255, 255)
return img
nume = 0
def division(img):#图像的分割,就是验证码按字符分割出来
global nume
font=[]
for i in range(4):
x=16+i*15#该函数中的像素值都需要自己进行微调
y=2
temp = img.crop((x,y,x+7,y+10))
temp.save("./temp/%d.gif" % nume)
nume=nume+1
font.append(temp)
return font
def recognize(img):#分隔出来的字符与预先定义的字体库中的结果逐个像素进行对比找出差别最小的项fontMods = []
for i in range(10):
fontMods.append((str(i), Image.open("./num/%d.gif" % i)))
result=""
font=division(img)
for i in font:
target=i
points = []
for mod in fontMods:
diffs = 0
for yi in range(10):
for xi in range(7): #以下多行为自己修改,参考文章中的值对比存在问题
#print "mod[1].getpixel((xi, yi)):"+str(mod[1].getpixel((xi, yi)))
#print "target.getpixel((xi, yi)):"+str(target.getpixel((xi, yi)))
if 0 in target.getpixel((xi, yi)):
compare = 0
else:
compare = 255
if mod[1].getpixel((xi, yi)) != compare:
diffs += 1
print "diffs:" + str(diffs)
points.append((diffs, mod[0]))
points.sort()
result += points[0][1]
return result
if __name__ == '__main__':
codedir="./pic/"
for imgfile in os.listdir(codedir):
if imgfile.endswith(".gif"):
dir="./result/"
img=binary(codedir+imgfile)
num=recognize(img)
dir += (num+".gif")
print "save to", dir
img.save(dir)
来源:vipscu
评论