验证码数字与字母识别

package com;


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
 


import javax.imageio.ImageIO;
public final class ImageUtil {
static final char[] chars = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I' ,'J','k','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x','y','z'};
private static final int SIZE = 4;
private static final int LINES = 5;
private static final int WIDTH = 130;
private static final int HEIGHT = 35;
private static final int FONT_SIZE =16;
/**
* 生成验证码图片,并存入流中。
*/
public static BufferedImage createImage() throws IOException {
StringBuffer sb = new StringBuffer();
BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics graphic = image.getGraphics();
graphic.setColor(Color.WHITE);
graphic.fillRect(0, 0, WIDTH, HEIGHT);
Random ran = new Random();
// 画随机字符
for (int i = 1; i <= SIZE; i++) {
int r = ran.nextInt(chars.length);
graphic.setColor(Color.BLACK);
graphic.setFont(new Font(null, Font.BOLD, FONT_SIZE));
graphic.drawString(chars[r] + "", (i - 1) * WIDTH / SIZE,
HEIGHT / 2);

}
ImageIO.write(image, "png", new File("C:\\Users\\Administrator\\Desktop\\com\\com\\2.png"));
return image;

}

}

package com;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;


public class NumShiBieDemo2 {

public static void main(String[] args) {

                imageShuZiModel();

BufferedImage img3=null;
try {
img3=ImageUtil.createImage();//调用方法生成验证码图片
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
getRealValue(img3);//处理图片


}
public static void getRealValue(BufferedImage img){
int[][][] allModel=new int[ImageUtil.chars.length][][];//定义模板数组
int[][][] jieXiArr=oneArrJianHua(caiFenPic(img));
for(int i=0;i<ImageUtil.chars.length;i++){
BufferedImage lowercase=null;
try {
lowercase = ImageIO.read(new File("C:\\Users\\Administrator\\Desktop\\com\\com\\model\\"+i+".png"));//生成模板图片,使用默认字体
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
allModel[i]=oneArr(lowercase);
}
for(int i=0;i<ImageUtil.chars.length;i++){
for(int j=0;j<allModel[i].length;j++){
for(int n=0;n<allModel[i][j].length;n++){
}
}
}
System.out.println(jieXiArr.length);
String str=makeShuZi(jieXiArr,allModel);
System.out.println("解析结果为:"+str);
}   
/*
* 将新生成的数字或字母的数组与模块数组进行比对,获取数字或字母内容
*/
public static String makeShuZi(int[][][] jieXiArr,int[][][] allModel){
StringBuffer str=new StringBuffer(); 
for(int i=0;i<jieXiArr.length;i++){
for(int n=0;n<allModel.length;n++){
if(jieXiArr[i][0].length==allModel[n][0].length&&jieXiArr[i].length==allModel[n].length){
int h=0;
for(int j=0;j<allModel[n].length;j++){
int l=0;
for(int m=0;m<allModel[n][j].length;m++){
if(jieXiArr[i][j][m]==allModel[n][j][m]){
l++;
}
}
if(l==allModel[n][j].length){
h++;
}
}
if(h==allModel[n].length){
str.append(ImageUtil.chars[n]+"");
}
}
}
}
return new String(str);
}
public static BufferedImage getImg(String srcImg){  
BufferedImage img   = null;  
try {  
img = ImageIO.read(new File(srcImg));  
} catch (IOException e) {  
e.printStackTrace();  
}  
return img;  
}      
/** 
* 取色
*/  
public static int getValue(int rgb){  
int r   = (rgb>>16)&255;  
int g   = (rgb>>8)&255;  
int b   = rgb&255;  
double avg  = 0.299*r+0.587*g+0.114*b; 
return (int)avg;  
}  
//取出数字模板并存入数组中
public static int[][]  oneArr(BufferedImage img){
int width=img.getWidth();//取出图片宽度
int height=img.getHeight();//取出图片高度
int m=0;
int p=0;
int mm=18;
int pp=18;
int[][] ret=new int[height][width];
for(int i=0;i<width;i++){
for(int j=0;j<height;j++){//通过判断门阀值来判断,灰度化处理(将图片上颜色较深的全部转变为黑色,其他的全部为白色,并且将此时的坐标存入数组中)
if(getValue(img.getRGB(i, j))>100){
img.setRGB(i, j,0xffffff);
ret[j][i]=1;//1为黑色
}
else{
img.setRGB(i, j,0x000000);
ret[j][i]=0;//0为白色
};
}
} //算出模块的边界值,目的是为了使所有为1的部分靠左和考上,并返回处理过后的模块数组
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
if(ret[i][j]==0){
m=i>m?i:m;
mm=i<mm?i:mm;
p=j>p?j:p;
pp=j<pp?j:pp;
}
}   
}  
int[][] oneModel=new int[m-mm+1][p-pp+1];
for(int i=0;i<m-mm+1;i++){
for(int j=0;j<p-pp+1;j++){
oneModel[i][j]=ret[i+mm][j+pp];
}
}
return oneModel;
}
//验证码图片解析
public static int[][][] caiFenPic(BufferedImage img){
int width=img.getWidth();
int height=img.getHeight();
int m=0;
int p=0;
int mm=18;
int pp=18;
int num=0;
int st=0;
int st_guodu=0;
int en=0;
int[][] retss=new int[height][width];
/*
* 通过判断门阀值来判断,灰度化处理(将图片上颜色较深的全部转变为黑色,其他的全部为白色,并且将此时的坐标存入数组中
* 1为黑色,0为白色
*/
for(int i=0;i<width;i++){
for(int j=0;j<height;j++){
if(getValue(img.getRGB(i, j))>100){
img.setRGB(i,j,0xffffff);
retss[j][i]=1;
}
else{
img.setRGB(i,j,0x000000);
retss[j][i]=0;
};
}
}
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
if(retss[i][j]==0){
m=i>m?i:m;
mm=i<mm?i:mm;
}
}   
}  
/*
*剪切图片(使验证码图片所有为1的让它靠住四边,多余的部分剔除出数组),记录出此时图片的高度(数组要用)
*/
int[][] ret=new int[m-mm+1][width];
for(int i=0;i<m-mm+1;i++){
for(int j=0;j<width;j++){
ret[i][j]=retss[i+mm][j];
}
}
/*
*判断剪切后图片的数字或字母数量,判断方法(图片中所有有为1的列,挨着此列的右边那一列如果一个1都没有表示为一个数字的结束。因为没有连续)
*/
for(int j=0;j<width-1;j++){
if(j<width-1){
labe:for(int i=0;i<ret.length;i++){
         if(ret[i][j]==0){          
         int sub=0;
         for(int x=0;x<ret.length;x++){
        if(ret[x][j+1]==0){
        sub++;        
        }
         }
         if(sub==0){        
        num++; 
         }
         sub=0;
         break labe;
         }
         
         }
}
else{
aa:for(int i=0;i<ret.length;i++){
if(ret[i][j]==0){
num++;
break aa;
}
}
}
}  
/*
*重新定义每个数字或字母的数组,并将每个数字或字母的起始坐标与结束坐标分别存入两个List集合(下角标决定顺序,值决定坐标值)
*/
    List<Integer> list_st=new ArrayList<Integer>();
    List<Integer> list_en=new ArrayList<Integer>();
int[][][] pigModel=new int[num][ret.length][];
for(int j=0;j<width-1;j++){
labe:for(int i=0;i<ret.length;i++){
         if(ret[i][j]==0){
         st_guodu++;
         int sub=0;
         for(int x=0;x<ret.length;x++){
        if(ret[x][j+1]==0){
        sub++;        
        }
         }
         if(sub==0){
        st_guodu=0;
        en=j;
        list_st.add(st);
        list_en.add(en);
        num++; 
         }
         else{
        if(st_guodu==1){
        st=j;
        }  
         }
         sub=0;
         break labe;
         }
         
         }
}
/*
*将每个数字或字母的坐标值重新存入新定义的数组
*/
for(int i=0;i<list_st.size();i++){
for(int j=0;j<ret.length;j++){
pigModel[i][j]=new int[list_en.get(i)-list_st.get(i)+1];
for(int z=0;z<list_en.get(i)-list_st.get(i)+1;z++){
pigModel[i][j][z]=ret[j][z+list_st.get(i)];
}
}
}
return pigModel;
}
/*
*将新定义的每个数字或字母数组,所有为1的值让它靠上(因为每个数字或字母的高度不一定完全相同,特别是小写字母)
*/
public static int[][][]  oneArrJianHua(int[][][] pigModel){
int[][][] oneModelJianHua=new int[pigModel.length][][];
for(int i=0;i<pigModel.length;i++){
int p=0;
int pp=180; 
for(int j=0;j<pigModel[i].length;j++){
for(int z=0;z<pigModel[i][j].length;z++){
if(pigModel[i][j][z]==0){
p=j>p?j:p;
pp=j<pp?j:pp;
}
}
}
oneModelJianHua[i]=new int[p-pp+1][pigModel[i][0].length];
for(int m=0;m<p-pp+1;m++){
for(int n=0;n<pigModel[i][0].length;n++){
oneModelJianHua[i][m][n]=pigModel[i][m+pp][n];
}
}
}
return oneModelJianHua;

}

//画数字模板
public static void imageShuZiModel(){
BufferedImage lowercase = null; 
for(int i=0;i<ImageUtil.chars.length;i++){
try {
lowercase=ImageIO.read(new File("C:\\Users\\Administrator\\Desktop\\com\\com\\1.png"));//我调用了我电脑里面的一张空白图片,你可以直接画一张空白图片。(这里我就不啰嗦了)
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();

Graphics2D g2d = lowercase.createGraphics();
g2d.setPaint(Color.BLACK);
g2d.setFont(new Font(null, Font.BOLD, 16));
String s=String.valueOf(ImageUtil.chars[i]);
g2d.drawString(s,0,16);
try {
ImageIO.write(lowercase, "PNG", new File("C:\\Users\\Administrator\\Desktop\\com\\com\\model\\"+i+".png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();


}
}

}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值