这两天想学一下验证码的识别,那就拿简单的入手吧,也不舍近求远了,就拿大乌云的验证码试试吧。
乌云的验证码很规则简单,以前也有人做过实验,基本图片都没有什么干扰。
基本的思路就是验证码图片二值化,分割图片,与之前分割好的单个验证码比较(乌云的验证码好像没有0、1、O、I)。
既然验证码就是两种颜色,处理起来就简单了,首先判断验证码是什么颜色,如果黑色,正常处理,白色的话,白色变黑色,其他颜色变白色。
一开始处理下面这种类型的验证码有点问题,根据验证码颜色来处理,背景颜色复杂点都无所谓了。
下面给出代码,注释掉的代码为前期调试的代码,主要用于去背景,分割图片,然后得到单个字符,这些单个字符坐字库来做标准,用于比较,共32个(0、1、O、I没有),这个大家自己去做吧,不用上传附件了,还有jar包自己去下载吧。
乌云大大来个赞吧。
package cn.pwntcha.test; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.io.IOUtils; public class Wooyun { public static void main(String[] args) throws Exception { // 下载图片 downloadImage(); // 处理图片 // for (int i = 0; i < 30; ++i) { // BufferedImage img = removeBackgroud("wooyun\\" + i + ".jpg"); // ImageIO.write(img, "jpg", new File("wooyun\\" + i + "_.jpg")); // } // 分割图片 // for (int i = 0; i < 30; ++i) { // BufferedImage img = removeBackgroud("wooyun\\" + i + ".jpg"); // List<BufferedImage> images = splitImage(img); // int j = 0; // for (BufferedImage bufferedImage : images) { // j++; // ImageIO.write(bufferedImage, "jpg", new File("wooyun\\" + i // + "_" + j + "_.jpg")); // } // } // 识别图片 for (int i = 0; i < 30; ++i) { getAllOcr("wooyun\\" + i + ".jpg"); } System.exit(0); } //判断验证码颜色 public static int getCaptchaBackgroud(BufferedImage img) { int width = img.getWidth(); int height = img.getHeight(); int black = 0; for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { if (getRGB(img.getRGB(x, y)) <= 10) {// 黑色 black++; } } } if (black > 10) {// 验证码为纯黑的背景偏白,否则验证码白色背景偏黑 return 0; } else { return 1; } } // 验证码为白色时,白色变为黑色,其他颜色全为白色 public static void change(BufferedImage img) { int width = img.getWidth(); int height = img.getHeight(); for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { if (getRGB(img.getRGB(x, y)) == 765) {// 白色 img.setRGB(x, y, Color.BLACK.getRGB()); } else { img.setRGB(x, y, Color.WHITE.getRGB()); } } } } public static int getRGB(int colorInt) { Color color = new Color(colorInt); return color.getRed() + color.getGreen() + color.getBlue(); } public static int isBlack(int colorInt) { Color color = new Color(colorInt); if (color.getRed() + color.getGreen() + color.getBlue() <= 100) { return 1; } return 0; } public static int isWhite(int colorInt) { Color color = new Color(colorInt); if (color.getRed() + color.getGreen() + color.getBlue() > 100) { return 1; } return 0; } public static BufferedImage removeBackgroud(String picFile) throws Exception { BufferedImage img = ImageIO.read(new File(picFile)); if (getCaptchaBackgroud(img) == 1) { change(img); } int width = img.getWidth(); int height = img.getHeight(); for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { if (isWhite(img.getRGB(x, y)) == 1) { img.setRGB(x, y, Color.WHITE.getRGB()); } else { img.setRGB(x, y, Color.BLACK.getRGB()); } } } return img; } public static List<BufferedImage> splitImage(BufferedImage img) throws Exception { List<BufferedImage> subImgs = new ArrayList<BufferedImage>(); subImgs.add(img.getSubimage(14, 4, 8, 10)); subImgs.add(img.getSubimage(23, 4, 8, 10)); subImgs.add(img.getSubimage(32, 4, 8, 10)); subImgs.add(img.getSubimage(41, 4, 8, 10)); return subImgs; } public static Map<BufferedImage, String> loadTrainData() throws Exception { Map<BufferedImage, String> map = new HashMap<BufferedImage, String>(); File dir = new File("wooyun\\train"); File[] files = dir.listFiles(); for (File file : files) { map.put(ImageIO.read(file), file.getName().charAt(0) + ""); } return map; } public static String getAllOcr(String file) throws Exception { BufferedImage img = removeBackgroud(file); List<BufferedImage> listImg = splitImage(img); Map<BufferedImage, String> map = loadTrainData(); String result = ""; for (BufferedImage bi : listImg) { result += getSingleCharOcr(bi, map); } ImageIO.write(img, "JPG", new File("wooyun\\result\\" + result + ".jpg")); return result; } 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; Label1: for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { if (isWhite(img.getRGB(x, y)) != isWhite(bi.getRGB(x, y))) { count++; if (count >= min) break Label1; } } } if (count < min) { min = count; result = map.get(bi); } } return result; } public static void downloadImage() { HttpClient httpClient = new HttpClient(); GetMethod getMethod = new GetMethod("http://wooyun.org/captcha.php"); for (int i = 0; i < 30; i++) { try { // 执行getMethod int statusCode = httpClient.executeMethod(getMethod); if (statusCode != HttpStatus.SC_OK) { System.err.println("Method failed: " + getMethod.getStatusLine()); } // 读取内容 String picName = "wooyun\\" + i + ".jpg"; File file = new File(picName); if (!file.exists()) { file.createNewFile(); } InputStream inputStream = getMethod.getResponseBodyAsStream(); OutputStream outStream = new FileOutputStream(picName); IOUtils.copy(inputStream, outStream); outStream.close(); System.out.println(i + "OK!"); } catch (Exception e) { e.printStackTrace(); } finally { // 释放连接 getMethod.releaseConnection(); } } } }
相关内容:
论防刷票、恶意提交表单:公司网站被恶意提交订单,看你如何解决?
身为码农,为12306说两句公道话,前淘宝工程师发帖谈12306:几乎是奇迹!
BurpSuite有点“懒”,你们是怎样完成带验证码爆破的?
短信炸弹,短信轰炸,利用各大网站的验证码功能批量轰炸某个号码
各种吐槽:
1#
he1renyagao ([code]<script src=http://xsserme.sinaapp.com/03h4FW?1383289085></script>[/code]) | 2014-04-21 17:44
前排占位
2#
寂寞的瘦子 (我喜欢放荡不羁的编程,所以选择动态语言。) | 2014-04-21 18:06
java果然长,用python只要几行。不过我用python写的识别率不能到100%,不会处理图片!--
#!/usr/bin/env python # -*- coding: UTF-8 -*- import Image import tesseract def Captcha(filepath): im = Image.open(filepath) im = im.convert("P") im2 = Image.new("P",im.size,255) im = im.convert("P") histo = im.histogram() if histo[0]== 0: #white for x in range(im.size[1]): for y in range(im.size[0]): pix = im.getpixel((y,x)) if pix == 225: im2.putpixel((y,x),0) else: for x in range(im.size[1]): for y in range(im.size[0]): pix = im.getpixel((y,x)) if pix == 0: im2.putpixel((y,x),0) im2.save('10.png') api = tesseract.TessBaseAPI() api.Init(".","eng",tesseract.OEM_DEFAULT) api.SetVariable("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") api.SetPageSegMode(tesseract.PSM_AUTO) mImgFile = "10.png" mBuffer=open(mImgFile,"rb").read() result = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api) if not result: api = tesseract.TessBaseAPI() api.Init(".","eng",tesseract.OEM_DEFAULT) api.SetVariable("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") api.SetPageSegMode(tesseract.PSM_AUTO) mImgFile = filepath mBuffer=open(mImgFile,"rb").read() result = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api) return result[:4] else: return result[:4]
3#
xsser (十根阳具有长短!!) | 2014-04-21 18:09
日
4#
浮生若梦 | 2014-04-21 18:33
二值化,分割,轻松搞定。。。。。
5#
hacker@sina.cn | 2014-04-21 18:47
好像很牛比的样子
6#
小威 (呵呵复呵呵,女神敲回车!) | 2014-04-21 18:50
一大波爆破僵尸正在靠近~
7#
Mujj (Krypt VPS特价www.80host.com) | 2014-04-21 18:51
贱心的豆豆……
8#
ylaxfcy | 2014-04-21 18:52
验证码识别还是好做,至少没有复杂背景什么,最近在做毕设,图像处理识别类的,代码已超过1.5k
9#
ylaxfcy | 2014-04-21 18:53
效果图
10#
ylaxfcy | 2014-04-21 18:54
怎么大图显示不全。。。。没过缩放么?
11#
廷廷 (想法最重要) | 2014-04-21 19:16
@ylaxfcy 膜拜···················
12#
小乐天 (Web安全只能当兴趣) | 2014-04-21 19:20
make
13#
大和尚 (www.ieroot.com) | 2014-04-21 20:01
车牌识别太easy了.
14#
insight-labs (Root Yourself in Success) | 2014-04-21 20:02
@ylaxfcy 搞那么复杂干什么,直接用opencv啊
15#
寂寞的瘦子 (我喜欢放荡不羁的编程,所以选择动态语言。) | 2014-04-21 20:04
@ylaxfcy 感觉你这个可以先定位车牌区域的坐标然后截取出来再处理
16#
ylaxfcy | 2014-04-21 20:12
@大和尚 你来试试。。
17#
ylaxfcy | 2014-04-21 20:15
@insight-labs 不准用opencv啊,我就显示载入和显示图像用来opencv,然后用了一下他的基础数据结构,然后算法都自己实现,最后在把载入图片和基础数据结构实现了,然后搞到有gpu的板子上面去跑。
18#
ylaxfcy | 2014-04-21 20:16
@insight-labs 成功率不高,在别人的算法基础上做优化都只成功75%左右,不知道那些论文里面95%+是怎么做出来的
19#
ylaxfcy | 2014-04-21 20:17
@寂寞的瘦子 对,是这样的,做到车牌定位与分割就1500行了
20#
寂寞的瘦子 (我喜欢放荡不羁的编程,所以选择动态语言。) | 2014-04-21 20:51
@ylaxfcy 掉渣。。
21#
高斯 | 2014-04-21 21:19
二值化 去噪 分割