Java日记——识别简单的验证码

在做爬课表的app时登录要输入验证码

便找到了这个识别简单验证码的源码

package Crackcode;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;




public class Main {

	//private static Map<BufferedImage, String> trainMap = null;
	
	
	 public final static String srcPath = new File("").getAbsolutePath()+"\\srcimg\\";
	 public final static String trainPath = new File("").getAbsolutePath()+"\\trainimg\\";
		
	/**
	 * 下载验证码
	 * @param url
	 * @param imgName  验证码的文件名
	 * @return
	 **/
	public static String downloadImage(String url, String imgName) throws MalformedURLException {
		URL murl;
		try {
			murl = new URL(url);
			URLConnection connection=murl.openConnection();
			InputStream is=connection.getInputStream();		
			//InputStreamReader inputStreamReader=new InputStreamReader(is);  //没有使用
			OutputStream outputStream=new FileOutputStream(new File(srcPath+imgName));
			int length = -1;
			byte[] bytes = new byte[1024];
			while((length = is.read(bytes)) != -1){
				outputStream.write(bytes, 0, length);		//保存图片到本地
			}
			outputStream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(srcPath+imgName);
		return srcPath+imgName;
	}

	/**
	 * 判断是否为蓝色
	 * 如果是,就返回 1 否则返回 0
	 **/
	public static int isBlue(int colorInt) {  	
        Color color = new Color(colorInt);  
        int rgb = color.getRed() + color.getGreen() + color.getBlue();
        if (rgb == 153) {  		
            return 1;  
        }  
        return 0;  
    }  
	
	
	/**
	 * 判断是否为Black
	 * 如果是,就返回 1 否则返回 0
	 **/
	public static int isBlack(int colorInt) {
		Color color = new Color(colorInt);
		if (color.getRed() + color.getGreen() + color.getBlue() <= 100) {
			return 1;
		}
		
		return 0;
	}

	
	/**
	 * 去除背景
	 * 如果是,就返回 1 否则返回 0
	 **/
	public static BufferedImage removeBackgroud(String picFile)
			throws Exception {
		BufferedImage img = ImageIO.read(new File(picFile));  
        img = img.getSubimage(5, 1, img.getWidth()-5, img.getHeight()-2); 	
        img = img.getSubimage(0, 0, 50, img.getHeight());
		

        
        
        System.out.println("正在生成处理后的图片");
        ImageIO.write(img, "png", new File(srcPath+"预处理.png"));
		
        int width = img.getWidth();  
        int height = img.getHeight();  
        for(int x=0; x<width; x++){
        	for(int y=0; y<height; y++){
        		if(isBlue(img.getRGB(x, y)) == 1){
        			img.setRGB(x, y, Color.BLACK.getRGB());		// 如果是蓝色 就全部设置为黑色
        		}else{
        			img.setRGB(x, y, Color.WHITE.getRGB());		// 否则 设置为白色
        		}
        	}
        }
        System.out.println("正在生成处理后的图片");
        ImageIO.write(img, "png", new File(srcPath+"预处理2.png"));
        return img;  
	}
	
	public static List<BufferedImage> splitImage(BufferedImage img)		// 拆分验证码
			throws Exception {
		List<BufferedImage> subImgs = new ArrayList<BufferedImage>();
		int width = img.getWidth()/4;
		int height = img.getHeight();			
		subImgs.add(img.getSubimage(0, 0, width, height));				// 直接平均拆分成4块
		subImgs.add(img.getSubimage(width, 0, width, height));
		subImgs.add(img.getSubimage(width*2, 0, width, height));
		subImgs.add(img.getSubimage(width*3, 0, width, height));
		
		int i = 0;
		for (BufferedImage bi : subImgs) {
			
	        System.out.println("正在生成处理后的图片");
	        ImageIO.write(bi, "png", new File(srcPath+"分割"+i+".png"));
			i++;
		}
		
		
		return subImgs;
	}

	public static Map<BufferedImage, String> loadTrainData() throws Exception {
		//if (trainMap == null) {
			Map<BufferedImage, String> map = new HashMap<BufferedImage, String>();
			File dir = new File(trainPath);			
			File[] files = dir.listFiles();			// 从trainPath中加载文件
			for (File file : files) {
				map.put(ImageIO.read(file), file.getName().charAt(0) + "");	// 加载样本数据      charAt(0) 只取文件名的第一个值
			}
		//	trainMap = map;	
		//}
		return map;
	}

	
	/**
	 * 图片匹配核心代码
	 * 
	 **/
	public static String getSingleCharOcr(BufferedImage img,
			Map<BufferedImage, String> map) {
		String result = "#";
		int width = img.getWidth();			// 得到宽度
		int height = img.getHeight();		// 得到高度
		int min = width * height;			// 像素个数
		for (BufferedImage bi : map.keySet()) {
			int count = 0;
			
			if (Math.abs(bi.getWidth()-width) > 2)		// Math.abs取绝对值 
				continue;
			int widthmin = width < bi.getWidth() ? width : bi.getWidth();		// 取两者最小宽度、高度
			int heightmin = height < bi.getHeight() ? height : bi.getHeight();
			
			Label1: 
			
			for (int x = 0; x < widthmin; ++x) {
				for (int y = 0; y < heightmin; ++y) {
					if (isBlack(img.getRGB(x, y)) != isBlack(bi.getRGB(x, y))) {		// 与样本进行对比,积累误差
						count++;
						if (count >= min)			// 如果有匹配度更高的,就直接break
							break Label1;
					}
				}
			}
			
			if (count < min) {						// 如果当前的样本匹配度更高
				min = count;						// 记录当前的样本的误差值count
				result = map.get(bi);				// 记录样本的名字首字母
			}
		}
		
		System.out.println("识别结果:"+result);		//打印识别结果
		System.out.println("误差值:"+min);		//打印误差值count    最大误差值:width * height

		
		return result;
	}

	public static String getAllOcr(String file) throws Exception {
		BufferedImage img = removeBackgroud(file);  		// 移除背景杂乱的颜色干扰
		
		List<BufferedImage> listImg = splitImage(img);		// 拆分验证码 保存到 listImg
		Map<BufferedImage, String> map = loadTrainData();	// 加载训练数据
		String result = "";
		for (BufferedImage bi : listImg) {		
		
			result += getSingleCharOcr(bi, map);			// Ocr识别 将图片转换成文字
			
		}
		return result;
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		System.out.println(trainPath);
		String pic=downloadImage("http://jwgl.gdut.edu.cn/CheckCode.aspx", "处理前.png"); 	// 从网络下载验证码
		
		//String pic = srcPath+"处理前.png";			// 加载本地图片
		String text = getAllOcr(pic);				// 识别验证码
		System.out.println("验证码:"+text);			// 输出验证码

	}
	
}


感谢东大贡献注释

这个程序需要训练识别验证码的数字图

源码和训练图可以到我的github下载

https://github.com/jkgeekJack/Ctrackcode

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java OCR(Optical Character Recognition)是一种利用计算机识别图像中的文字的技术。在识别复杂验证码方面,Java OCR面临一些挑战,但也有一些方法可以应对。 首先,复杂验证码通常包含噪声、干扰线和扭曲的文字,这使得文字的边缘不清晰。为了提高识别准确性,可以使用图像去噪、平滑和二值化算法。图像去噪可以去除背景噪声,平滑算法可以减少图像的噪声,并提供更清晰的边缘。二值化算法可将灰度图像转换为黑白图像,以便更容易分割和识别文字。 其次,验证码中的文字可能存在扭曲,这会导致字符形状变形。为了解决这个问题,可以使用扭曲矫正算法。该算法通过对验证码进行扭曲反向转换,使字符形状恢复正常。这样就能提高文字边缘的清晰度,提高文字识别的准确性。 第三,验证码中可能有复杂的背景图案,这会干扰文字的识别。为了解决这个问题,可以使用图像分割算法将验证码中的文字与背景分开。图像分割算法可以基于颜色、纹理和形状等特征,将文字与背景区域分离出来,从而提高识别准确性。 最后,对于复杂验证码识别,还可以使用机器学习和深度学习的方法。通过训练模型,使其能够对不同类型的复杂验证码进行识别。机器学习和深度学习的方法可以提高识别准确性,并适应不同类型的验证码。 综上所述,Java OCR识别复杂验证码可以通过图像去噪、平滑和二值化算法,扭曲矫正算法,图像分割算法,机器学习和深度学习等方法来提高识别准确性和鲁棒性。尽管复杂验证码识别仍然具有一定的挑战,但借助这些方法,Java OCR仍然可以达到较高的识别成功率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值