图形验证码识别系统说明书.docx
《图形验证码识别系统说明书.docx》由会员分享,可在线阅读,更多相关《图形验证码识别系统说明书.docx(21页珍藏版)》请在冰豆网上搜索。
![图形验证码识别系统说明书.docx](https://file1.bdocx.com/fileroot1/2023-5/19/8f760818-895f-4923-a8b3-85137d2f0e37/8f760818-895f-4923-a8b3-85137d2f0e371.gif)
图形验证码识别系统说明书
*******************
实践教学
*******************
某某理工大学
计算机与通信学院
2015年春季学期
工程开发综合训练课程设计
题目:
图形验证码识别系统
专业班级:
计算机科学与技术12级1班
姓名:
王喆
学号:
12240102
指导教师:
李明
成绩:
摘要
随着互联网的高速开展,网络在给人们的生活带来极大便利的同时,其安全问题也日益突出。
图形验证码作为一项广泛使用的验证手段,对网络安全起到了重要的作用。
本设计要求学生开发一个基于图像处理的图形验证码识别系统。
该系统可以对验证码图像进展灰度化、二值化、去噪、字符分割、字符识别等处理,并能够显示识别结果。
此外,学生通过该题目的设计过程,可以初步应用软件系统的开发原理和开发方法,全面培养软件开发过程中的分析、设计、编码、测试与文档规X书写的能力,得到软件工程的训练,提高解决实际问题的能力。
关键词:
图形验证码,二值化,去噪,字符分割
随着网络的迅速普与,人们接触电脑的机会越来越多,可以说生活中电脑已经成为不可分割的一局部。
而我们在上网的同时,也会遇到各种各样的问题,比如在网上购物,参与论坛讨论等等的时候,都会遇到各式各样的验证码,纯数字的,带字母的,还有的在字符背景上做文章,改变色彩,添加一些干扰的因素,让上网的环境不是那么轻松。
有时候,人们会因为一两个验证码不能识别导致购物失败或者交易失误而懊恼,毕竟人眼所能看到的X围是很小的一局部,有好多的东西用肉眼是无法区分清楚,所以这个时候就需要依托一些简单的识别系统,比如这个图形验证码识别系统,去帮助人们正确的得到验证码的信息。
本系统有好几种识别验证码的方法,对于各样的验证码都会顺利的得出结果。
比如单纯的数字,带字母的,添加背景干扰信息。
系统通过对图形验证码的样子进展数字图像处理,图像预处理,用这样的技术将图形中的干扰识别的信息去除掉,让真正需要的数字或者字母清晰的显现出来。
所用到的技术有灰度化、二值化、去噪、字符分割、字符识别等。
有了识别验证码系统,人们在使用电脑网上工作的时候防止不必要的失误,节省很多的时间。
数字图象处理
一幅图像可以定义为一个二维数组f(x,y),这里x,y是空间坐标,而在任何一对空间坐标(x,y)上的幅值f称为该点图像的强度或灰度。
当x,y和幅值f为有限的、离散的数值时,称该图像为数字图像。
自然界呈现在人眼中的图像是连续的模拟信号,在计算机处理前,必须用图像传感器把光信号转换为表示亮度的电信号,再通过取样和量化得到一副数字图像。
取样是对图像在坐标上进展离散化的过程,每一个取样点称为一个像素。
量化是对图像灰度上的离散化过程。
取样后将得到M*N个像素,每个像素量化得到一个灰度值L,以L表示灰度值的允许取值X围,如此数字图像存储需要的比特数b可以表示为:
b=M*N*L
图像的灰度值取值X围被称为图像的动态X围。
把占有灰度级全部有效段的图像称为高动态X围图像,高动态X围图像有较高的比照度。
相反,地动态X围的图像看上去是冲淡了的灰暗风格。
图像的预处理
主要是对图像进展灰度化、二值化、抑噪〔滤波〕等技术。
1、图像的灰度化
RGB系统中一个颜色值由3个分量组成,这样的图像称为彩色图像,RGB系统称为颜色空间模型。
常见的颜色空间模型还有HSI、CMYK等。
如果一幅图像的颜色空间是一维的〔一个颜色值只有一个颜色分量〕,如此这幅图像就是一副灰度图。
在位图图像中,一般以R=G=B来显示灰度图像。
常用的灰度化方法有以下三种:
其中,公式〔2.1〕的方法来源于I色彩空间中I分量的计算公式,公式〔2.2〕来源于NTSC色彩空间中Y分量的计算公式。
公式〔2.3〕是基于采用保存最小亮度〔黑色〕的方法。
RGB彩色图像可以看成是由3副单色的灰度图像构成的,可以直接取RGB通道中的任一个通道得到灰度化图像,前提是图像中目标像素的亮度信息主要分布在B通道上,否如此灰度化结果将是亮度信息的大量丢失。
灰度图像又叫亮度图像,由归一化的取值表示亮度,最大取值表示白色,最小取值表示黑色。
以P(x,y)表示图像中一个点,x、y分别是图像的横坐标和纵坐标,R(x,y)表示R通道的颜色分量,G(x,y)表示G通道的颜色分量,B(x,y)表示B通道的颜色分量。
点P(x,y)的亮度值用L(x,y)表示。
彩色图像的亮度没有严格的定义和计算公式,一般用公式〔2.1〕来计算,我们记作L1(x,y)。
同样的用公式〔2.2〕计算的亮度值记作L2(x,y),用公式〔2.3〕计算的亮度值记作L3(x,y)。
可以证明:
公式〔2.1〕取RGB通道的平均值,得到的图像相比照拟柔和,同时也缩小了目标和背景的平均亮度差,不利于后续的阀值处理。
公式〔2.2〕考虑了人眼对绿色的适应度最强,蓝色次之,红色最差。
在处理绿色调和蓝色调的验证码图像时,公式〔2.2〕的效果令人满意,但在处理红色调的图像时,因为公式中红色的权值很小,灰度化后目标像素和背景像素的亮度差值被严重缩小,效果还不如公式〔2.1〕。
公式〔2.3〕基于一个前提,那就是有限保存目标像素的亮度信息,利于后续的阀值分割。
需要说明的是,要根据图像灰度化的目的不同,原图色彩特征的不同,选择适宜的灰度化方法。
2、图像的二值化
一般24位RGB图像的灰度图是8位256个灰度级的,如果把这个灰度级减少到1位2个灰度级,就得到一副二值图,二值图像中的数据全部是0或1。
字符分割
字符分割包括从验证码图像中分割出字符区域和把字符区域划分成单个字符两个局部。
如果采用统计特征匹配以与神经网络法识别,必须要先分割出单个的字符。
简单的分割方法包括等距分割、积分投影分割、交叉点分割、求连通区等。
其中,粘连字符的分割是一个难点,复杂的粘连情况下分割比拟困难,是一个硬人工智能问题。
字符识别
字符识别就是把处理后的图片复原回字符文本的过程。
可以分成基于字符分割的识别〔包括采用神经网络、SVM、各种统计距离的识别法〕和模板匹配法识别。
字符识别的常用做法是:
先获取该字符的特征码,然后使用各种分类算法将对该特征码进展分类,将其打上相应的类标签。
分类模型的训练,是对字符库中的每个字符进展特征化处理,得到每个字符的特征码,该字符的标签就是该字符本身,利用特征码加上字符的标签对字符库中的所有数据进展训练,得到相应的分类模型。
当然,得到了待识别字符的特征码后,也可以使用相似性度量和字符库中的字符的特征码进展比拟,将该字符识别为与其特征码相似性最高的字符。
现在的问题就集中在如何获取字符的特征码。
文章[2]中介绍了一种简单的获取特征码的方法:
对于二值化后的图像进展分割,分割出来的图像是一个个的字符,如如下图所示:
在每个字符的边界内,按行〔或列〕扫描该图片,检测其中的每个像素点,如果像素为白色如此为0,如果像素为黑色如此为1,将这些0和1连起来组成的字符串就构成了该字符图片的特征码。
3.系统实现
单纯的识别数字用如下程序实现:
publicclassImagePreProcess{
publicstaticintisBlack(intcolorInt){
Colorcolor=newColor(colorInt);
if(color.getRed()+color.getGreen()+color.getBlue()<=100){
return1;
}
return0;
}
publicstaticintisWhite(intcolorInt){
Colorcolor=newColor(colorInt);
if(color.getRed()+color.getGreen()+color.getBlue()>100){
return1;
}
return0;
}
publicstaticBufferedImageremoveBackgroud(StringpicFile)
throwsException{
BufferedImageimg=ImageIO.read(newFile(picFile));
intwidth=img.getWidth();
intheight=img.getHeight();
for(intx=0;xfor(inty=0;yif(isWhite(img.getRGB(x,y))==1){
img.setRGB(x,y,Color.WHITE.getRGB());
}else{
img.setRGB(x,y,Color.BLACK.getRGB());
}
}
}
returnimg;
}
publicstaticListsplitImage(BufferedImageimg)
throwsException{
ListsubImgs=newArrayList();
subImgs.add(img.getSubimage(10,6,8,10));
subImgs.add(img.getSubimage(19,6,8,10));
subImgs.add(img.getSubimage(28,6,8,10));
subImgs.add(img.getSubimage(37,6,8,10));
returnsubImgs;
}
publicstaticMaploadTrainData()throwsException{
Mapmap=newHashMap();
Filedir=newFile("train");
File[]files=dir.listFiles();
for(Filefile:
files){
map.put(ImageIO.read(file),file.getName().charAt(0)+"");
}
returnmap;
}
publicstaticStringgetSingleCharOcr(BufferedImageimg,
Mapmap){
Stringresult="";
intwidth=img.getWidth();
intheight=img.getHeight();
intmin=width*height;
for(BufferedImagebi:
map.keySet()){
intcount=0;
Label1:
for(intx=0;xfor(inty=0;yif(isWhite(img.getRGB(x,y))!
=isWhite(bi.getRGB(x,y))){
count++;
if(count>=min)
breakLabel1;
}
}
}
if(countmin=count;
result=map.get(bi);
}
}
returnresult;
}
publicstaticStringgetAllOcr(Stringfile)throwsException{
BufferedImageimg=removeBackgroud(file);
ListlistImg=splitImage(img);
Mapmap=loadTrainData();
Stringresult="";
for(BufferedImagebi:
listImg){
result+=getSingleCharOcr(bi,map);
}
ImageIO.write(img,"JPG",newFile("result\\"+result+".jpg"));
returnresult;
}
publicstaticvoiddownloadImage(){
ClientClient=newClient();
GetMethodgetMethod=newGetMethod(
".puke888./authimg.php");
for(inti=0;i<30;i++){
try{
//执行getMethod
intstatusCode=Client.executeMethod(getMethod);
if(statusCode!
=Status.SC_OK){
System.err.println("Methodfailed:
"
+getMethod.getStatusLine());
}
//读取内容
Stringpiame="img\\"+i+".jpg";
InputStreaminputStream=getMethod.getResponseBodyAsStream();
OutputStreamoutStream=newFileOutputStream(piame);
IOUtils.copy(inputStream,outStream);
outStream.close();
System.out.println(i+"OK!
");
}catch(Exceptione){
e.printStackTrace();
}finally{
//释放连接
getMethod.releaseConnection();
}
}
}
publicstaticvoidmain(String[]args)throwsException{
for(inti=0;i<30;++i){
Stringtext=getAllOcr("img\\"+i+".jpg");
System.out.println(i+".jpg="+text);
}
}
}
识别有背景颜色和字母的代码段如下:
publicclassImagePreProcess2{
privatestaticMaptrainMap=null;
privatestaticintindex=0;
publicstaticintisBlack(intcolorInt){
Colorcolor=newColor(colorInt);
if(color.getRed()+color.getGreen()+color.getBlue()<=100){
return1;
}
return0;
}
publicstaticintisWhite(intcolorInt){
Colorcolor=newColor(colorInt);
if(color.getRed()+color.getGreen()+color.getBlue()>100){
return1;
}
return0;
}
publicstaticBufferedImageremoveBackgroud(StringpicFile)
throwsException{
BufferedImageimg=ImageIO.read(newFile(picFile));
returnimg;
}
publicstaticBufferedImageremoveBlank(BufferedImageimg)throwsException{
intwidth=img.getWidth();
intheight=img.getHeight();
intstart=0;
intend=0;
Label1:
for(inty=0;yfor(intx=0;xif(isWhite(img.getRGB(x,y))==1){
start=y;
breakLabel1;
}
}
}
Label2:
for(inty=height-1;y>=0;--y){
for(intx=0;xif(isWhite(img.getRGB(x,y))==1){
end=y;
breakLabel2;
}
}
}
returnimg.getSubimage(0,start,width,end-start+1);
}
publicstaticListsplitImage(BufferedImageimg)
throwsException{
ListsubImgs=newArrayList();
intwidth=img.getWidth();
intheight=img.getHeight();
Listweightlist=newArrayList();
for(intx=0;xintcount=0;
for(inty=0;yif(isWhite(img.getRGB(x,y))==1){
count++;
}
}
weightlist.add(count);
}
for(inti=0;iintlength=0;
while(weightlist.get(i++)>1){
length++;
}
if(length>12){
subImgs.add(removeBlank(img.getSubimage(i-length-1,0,
length/2,height)));
subImgs.add(removeBlank(img.getSubimage(i-length/2-1,0,
length/2,height)));
}elseif(length>3){
subImgs.add(removeBlank(img.getSubimage(i-length-1,0,
length,height)));
}
}
returnsubImgs;
}
publicstaticMaploadTrainData()throwsException{
if(trainMap==null){
Mapmap=newHashMap();
Filedir=newFile("train2");
File[]files=dir.listFiles();
for(Filefile:
files){
map.put(ImageIO.read(file),file.getName().charAt(0)+"");
}
trainMap=map;
}
returntrainMap;
}
publicstaticStringgetSingleCharOcr(BufferedImageimg,
Mapmap){
Stringresult="";
intwidth=img.getWidth();
intheight=img.getHeight();
intmin=width*height;
for(BufferedImagebi:
map.keySet()){
intcount=0;
intwidthmin=widthwidth:
bi.getWidth();
intheightmin=heightheight:
bi.getHeight();
Label1:
for(intx=0;xfor(inty=0;yif(isWhite(img.getRGB(x,y))!
=isWhite(bi.getRGB(x,y))){
count++;
if(count>=min)
breakLabel1;
}
}
}
if(countmin=count;
result=map.get(bi);
}
}
returnresult;
}
publicstaticStringgetAllOcr(Stringfile)throwsException{
BufferedImageimg=removeBackgroud(file);
ListlistImg=splitImage(img);
Mapmap=loadTrainData();
Stringresult="";
for(BufferedImagebi:
listImg){
result+=getSingleCharOcr(bi,map);
}
ImageIO.write(img,"JPG",newFile("result2\\"+result+".jpg"));
returnresult;
}
publicstaticvoiddownloadImage(){
ClientClient=newClient();
GetMethodgetMethod=null;
for(inti=0;i<30;i++){
getMethod=newGetMethod("
+(2000+i));
try{
//执行getMethod
intstatusCo