Java多线程加法计算--Java识别静态验证码和动态验证码
Java多线程加法计算
Java识别静态验证码和动态验证码
写了一个简单java工具类,用于验证码点阵打印+自动识别。为了提升识别精度和程序性能,此工具类是针对特定类型的验证码的,若要用于其他类型的验证码识别,需要做相应调整。
文章分两部分演示了此java工具类如何识别静态验证码图片和动态验证码gif。
一、静态验证码图片识别
输入验证码:
程序运行结果:
======= print and recognize captchapic =======
"................................................................................",
"................................................................................",
"................................................................................",
"................##.##........#####..............................................",
"................##.##.......##...##.............................................",
"................##.##.............##............................................",
"............###.##.##.###........##....#####....................................",
"...........##..###.###..##.....###....##...##...................................",
"..........##....##.##....##......##........##...................................",
"..........##....##.##....##.......##..#######...................................",
"..........##....##.##....##.......##.##....##...................................",
"...........##..###.##....##.##...##..##...###...................................",
"............###.##.##....##..#####....####.##...................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................"
recognize: dh3a
相应代码如下:
package com.demo.check;
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;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class CaptchaRecognizer {
public static void main(String[] args) {
HttpClient httpClient = new HttpClient();
GetMethod getMethod = new GetMethod("https://img2020.cnblogs.com/blog/1039974/202011/1039974-20201119224011928-1654538410.png"); // 验证码链接
for (int i = 0; i < 5; i++) {
try {
// 执行get请求
int statusCode = httpClient.executeMethod(getMethod);
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + getMethod.getStatusLine());
} else {
File captcha = File.createTempFile("ybt", ".png");
OutputStream outStream = new FileOutputStream(captcha);
InputStream inputStream = getMethod.getResponseBodyAsStream();
IOUtils.copy(inputStream, outStream);
outStream.close();
BufferedImage image = ImageIO.read(captcha);
System.out.println("======= print and recognize captchapic =======");
printImage(image);
System.out.printf("recognize: %s\n", recognizeCaptcha(image));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放连接
getMethod.releaseConnection();
}
}
}
/**
* @param colorInt 像素点的RGB值
* @return
*/
private static boolean isBlack(int colorInt) {
Color color = new Color(colorInt);
if (color.getRed() + color.getGreen() + color.getBlue() <= 10) {
return true;
}
return false;
}
/**
* @param image 需要打印的图像
* @throws IOException
*/
private static void printImage(BufferedImage image) {
int h = image.getHeight();
int w = image.getWidth();
// 矩阵打印
for (int y = 0; y < h; y++) {
System.out.printf("\"");
for (int x = 0; x < w; x++) {
if (isBlack(image.getRGB(x, y))) {
System.out.print("#");
} else {
System.out.print(".");
}
}
System.out.printf("%s", y == h-1 ? "\"" : "\",");
System.out.println();
}
}
/**
* @param image 待识别的符号图片
* @return
*/
private static char recognizeSymbol(BufferedImage image) {
int h = image.getHeight();
int w = image.getWidth();
int minDiff = 999999;
char symAns = 0;
// 对于某个给定数值
for (int i = 0; i < 10; i++) {
int curDiff = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
boolean pixel1 = digitals[i][y].charAt(x) == '#';
boolean pixel2 = isBlack(image.getRGB(x, y));
if (pixel1 != pixel2) {
++curDiff;
}
}
}
if (curDiff < minDiff) {
minDiff = curDiff;
symAns = (char) ('0' + i);
}
if (minDiff == 0) {
return symAns;
}
}
// 对于某个给定字母
for (int i = 0; i < 26; i++) {
int curDiff = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
boolean pixel1 = alphas[i][y].charAt(x) == '#';
boolean pixel2 = isBlack(image.getRGB(x, y));
if (pixel1 != pixel2) {
++curDiff;
}
}
}
if (curDiff < minDiff) {
minDiff = curDiff;
symAns = (char) ('a' + i);
}
if (minDiff == 0) {
return symAns;
}
}
return symAns;
}
/**
* @param image 需要被分割的验证码
* @return
*/
private static List<BufferedImage> splitImage(BufferedImage image) {
List<BufferedImage> subImgs = new ArrayList<BufferedImage>();
subImgs.add(image.getSubimage(10, 3, 8, 12));
subImgs.add(image.getSubimage(19, 3, 8, 12));
subImgs.add(image.getSubimage(28, 3, 8, 12));
subImgs.add(image.getSubimage(37, 3, 8, 12));
return subImgs;
}
/**
* @param image 待识别的验证码
* @return
*/
public static String recognizeCaptcha(BufferedImage image) {
StringBuilder ans = new StringBuilder();
List<BufferedImage> subImgs = splitImage(image);
for (BufferedImage subImg : subImgs) {
// 依次识别子图片
ans.append(recognizeSymbol(subImg));
}
return ans.toString();
}
private static String[][] digitals = new String[][]{
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....##",
"......##",
".....##.",
"....##..",
"...##...",
"..##....",
".##.....",
"########",
"........",
"........"
},
{
".#####..",
"##...##.",
"......##",
".....##.",
"...###..",
".....##.",
"......##",
"......##",
"##...##.",
".#####..",
"........",
"........"
},
{
".....##.",
"....###.",
"...####.",
"..##.##.",
".##..##.",
"##...##.",
"########",
".....##.",
".....##.",
".....##.",
"........",
"........"
},
{
"#######.",
"##......",
"##......",
"##.###..",
"###..##.",
"......##",
"......##",
"##....##",
".##..##.",
"..####..",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....#.",
"##......",
"##.###..",
"###..##.",
"##....##",
"##....##",
".##..##.",
"..####..",
"........",
"........"
},
{
"########",
"......##",
"......##",
".....##.",
"....##..",
"...##...",
"..##....",
".##.....",
"##......",
"##......",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....##",
".##..##.",
"..####..",
".##..##.",
"##....##",
"##....##",
".##..##.",
"..####..",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....##",
"##....##",
".##..###",
"..###.##",
"......##",
".#....##",
".##..##.",
"..####..",
"........",
"........"
}
};
private static String[][] alphas = new String[][]{
{
"........",
"........",
"........",
"..#####.",
".##...##",
"......##",
".#######",
"##....##",
"##...###",
".####.##",
"........",
"........"
},
{
"##......",
"##......",
"##......",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"###..##.",
"##.###..",
"........",
"........"
},
{
"........",
"........",
"........",
"..#####.",
".##...##",
"##......",
"##......",
"##......",
".##...##",
"..#####.",
"........",
"........"
},
{
"......##",
"......##",
"......##",
"..###.##",
".##..###",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"........",
"........"
},
{
"........",
"........",
"........",
"..####..",
".##..##.",
"##....##",
"########",
"##......",
".##...##",
"..#####.",
"........",
"........"
},
{
"...####.",
"..##..##",
"..##..##",
"..##....",
"..##....",
"######..",
"..##....",
"..##....",
"..##....",
"..##....",
"........",
"........"
},
{
"........",
"........",
"........",
".#####.#",
"##...###",
"##...##.",
"##...##.",
".#####..",
"##......",
".######.",
"##....##",
".######."
},
{
"##......",
"##......",
"##......",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
"........",
"........"
},
{
"...##...",
"...##...",
"........",
"..###...",
"...##...",
"...##...",
"...##...",
"...##...",
"...##...",
".######.",
"........",
"........"
},
{
".....##.",
".....##.",
"........",
"....###.",
".....##.",
".....##.",
".....##.",
".....##.",
".....##.",
"##...##.",
"##...##.",
".#####.."
},
{
".##.....",
".##.....",
".##.....",
".##..##.",
".##.##..",
".####...",
".####...",
".##.##..",
".##..##.",
".##...##",
"........",
"........"
},
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"........",
"........",
"........",
"#.##.##.",
"##.##.##",
"##.##.##",
"##.##.##",
"##.##.##",
"##.##.##",
"##.##.##",
"........",
"........"
},
{
"........",
"........",
"........",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
"........",
"........"
},
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"........",
"........",
"........",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"###..##.",
"##.###..",
"##......",
"##......"
},
{
"........",
"........",
"........",
"..###.##",
".##..###",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"......##",
"......##"
},
{
"........",
"........",
"........",
"##.####.",
".###..##",
".##.....",
".##.....",
".##.....",
".##.....",
".##.....",
"........",
"........"
},
{
"........",
"........",
"........",
".######.",
"##....##",
"##......",
".######.",
"......##",
"##....##",
".######.",
"........",
"........"
},
{
"........",
"..##....",
"..##....",
"######..",
"..##....",
"..##....",
"..##....",
"..##....",
"..##..##",
"...####.",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
".##..##.",
".##..##.",
"..####..",
"..####..",
"...##...",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
"##.##.##",
"##.##.##",
"##.##.##",
"########",
".##..##.",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
".##..##.",
"..####..",
"...##...",
"..####..",
".##..##.",
"##....##",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"#.....##",
".######."
},
{
"........",
"........",
"........",
".######.",
".....##.",
"....##..",
"...##...",
"..##....",
".##.....",
".######.",
"........",
"........"
}
};
}
二、动态验证码gif识别
动态验证码gif的识别和静态验证码图片的识别非常相识,两者之间唯一的区别在于gif是由多帧静态图片所构成的。所以我们处理gif的思路很简单,从特定帧的静态图片中,识别需要的验证符号。
输入验证码:
程序运行结果:
======= print and recognize captchapic =======
"..................................................................................................................................................",
"..................................................................................................................................................",
"....................#####.........................................................................................................................",
".................###.....###......................................................................................................................",
".................#.........#......................................................................................................................",
".................#..........#.....................................................................................................................",
"................#...........#.....................................................................................................................",
"................#.#######....#..........................######....................................................................................",
"................###########.#.........................##########..................................................................................",
"................#############........................###########..................................................................................",
"................##.....#####.........................##.....#####.................................................................................",
".................##.....####................................#####.................................................................................",
"...................###.####..................................####........................#######..................................................",
"......................#####.................................#######....................##########.................................................",
".....................#####..................................####....#..................###########................................................",
".................########..................................####......#.................#.....#####................................................",
".................#######..................................####.......#........................####................................................",
".................#########...............................####.........#.......................####................................................",
".....................######.............................###.#........#...................########.................................................",
"....................#######...........................####...#.......#.................##########.................................................",
"..................##...######........................####.....##..###.................####...####.................................................",
".................#.....####..#......................####.........#...................####....####.................................................",
".................#....#####..#.....................####..............................####....####.................................................",
"..............#...##.#####.##.....................####...............................####...#####.................................................",
".............##############......................#############.......................#############................................................",
".............###########.........................#############.......................######..#####................................................",
"...............#######...........................#############........................####...#####................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
".................................................................................................................................................."
<<< frame >>>
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
".................................................................................................................................#####............",
"...............................................................................................................................########...........",
"........................................................######................................................................########............",
"......................................................##########.........................................##...................####...#............",
".....................................................###########........................................#..#.................####.................",
".....................................................##.....#####.......................................#..#.................####.................",
"............................................................#####......................................#....#................####.................",
".............................................................####........................#######.......#....#..............##########.............",
"............................................................####.......................##########......#....#.............##########..............",
"............................................................####.......................###########.....#....#.............##########..............",
"...........................................................####........................#.....#####.....#....#...............####..................",
"..........................................................####................................####......#..#................####..................",
".........................................................####.................................####......#..#................####..................",
"........................................................###..............................########........##................####...................",
"......................................................####.............................##########..........................####...................",
".....................................................####.............................####...####..........................####...................",
"....................................................####......................####...####....####..........................####...................",
"...................................................####......................#....#..####....####.......####...............####...................",
"..................................................####.......................#....#..####...#####.....##....###............####...................",
".................................................#############...............#.....#.#############...#.........#..........####....................",
".................................................#############...............#....#..######..#####...#.........#..........####....................",
".................................................#############...............#....#...####...#####..#...........#.........####....................",
"..............................................................................##.#..................#...........#.................................",
"................................................................................#...................#............#................................",
"....................................................................................................#...........#.................................",
".....................................................................................................#..........#.................................",
".....................................................................................................#.........#..................................",
".....................................................................................................##.......##.................................."
recognize: 32af
以下贴出gif的分割函数,其它过程和第一部分基本相同,之后逐个解析静态子图片即可。
/**
* @param file 需要被分割的gif文件
* @throws Exception
*/
private static List<BufferedImage> splitGif(File file) throws IOException {
FileImageInputStream in = new FileImageInputStream(file);
ImageReaderSpi readerSpi = new GIFImageReaderSpi();
GIFImageReader gifReader = (GIFImageReader) readerSpi.createReaderInstance();
gifReader.setInput(in);
int num = gifReader.getNumImages(true);
ImageWriterSpi writerSpi = new GIFImageWriterSpi();
GIFImageWriter writer = (GIFImageWriter) writerSpi.createWriterInstance();
List<BufferedImage> subImgs = new ArrayList<BufferedImage>();
for (int i = 0; i < num; i++) {
File frame = File.createTempFile("mxt", ".png");
FileImageOutputStream out = new FileImageOutputStream(frame);
writer.setOutput(out);
writer.write(gifReader.read(num - i - 1));
out.close();
// 分割每一帧图片,进行识别
BufferedImage image = ImageIO.read(frame);
if (i == 1 || i == 2) {
printImage(image);
System.out.println("<<< frame >>>");
}
subImgs.add(image.getSubimage(7 + i * 36, 5, 30, 27));
}
in.close();
return subImgs;
}
参考链接
[1] https://blog.csdn.net/problc/article/details/5794460#commentBox
[2] https://blog.csdn.net/lmj623565791/article/details/23960391/
[3] https://blog.csdn.net/chwshuang/article/details/64923354
Java多线程加法计算
题意:要求开6条线程计算累加1 -> 10000000
难点:如何获取子线程的执行结果并聚合
思路一
生产者-消费者 经典模型:
- 多个生产者负责生产(累加)作业
- 生产者将生产结果存入共享仓库中
- 消费者(主线程)从共享仓库中取出结果
/**
* 多线程计算累加数
*/
public class Accumulate {
public static void main(String[] args) {
Storage storage = new Storage();
// 为多个计算器对象创建线程
Thread calThread1 = new Thread(new Calculate(1, storage), "Thread-1");
Thread calThread2 = new Thread(new Calculate(2, storage), "Thread-2");
Thread calThread3 = new Thread(new Calculate(3, storage), "Thread-3");
Thread calThread4 = new Thread(new Calculate(4, storage), "Thread-4");
Thread calThread5 = new Thread(new Calculate(5, storage), "Thread-5");
Thread calThread6 = new Thread(new Calculate(6, storage), "Thread-6");
calThread1.start();
calThread2.start();
calThread3.start();
calThread4.start();
calThread5.start();
calThread6.start();
// 打印最终结果
storage.printTotal();
}
}
/**
* 计算器对象,负责计算start -> end
*/
class Calculate implements Runnable {
private Storage storage;
private long start;
public Calculate(long start, Storage storage) {
this.start = start;
this.storage = storage;
}
@Override
public void run() {
long num = start;
long sum = 0;
while (num <= 10000000) {
System.out.println(Thread.currentThread().getName() + " add num " + num);
sum += num;
num += 6;
}
// 线程计算完毕, 调用累加器进行累加
storage.push(sum);
}
}
/**
* 仓库对象,负责累加
*/
class Storage {
private long total = 0;
private int count = 0;
public synchronized void push(long sum) {
total += sum;
count++;
notifyAll();
}
public synchronized void printTotal() {
while (count < 6) {
try {
System.out.println(Thread.currentThread().getName() + " is wait");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("storage result = " + total);
}
}
思路二
线程异步返回:
- 利用线程池并发处理多个任务
- 使用Future+Callable获取异步执行结果
- 待线程池中所有任务结束,计算累加结果
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
/**
* 线程池计算累加数
*/
public class Accumulate {
public static void main(String[] args) {
// 建立线程池 与 动态结果数组
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(6);
List<Future<Long>> resultList = new ArrayList<>();
// 定义10个任务分别负责一定范围内的元素累计
for (int i = 0; i < 10; i++) {
CalTask calTask = new CalTask(i*100000000+1, (i+1)*100000000);
Future<Long> result = executor.submit(calTask);
resultList.add(result);
}
// 每隔50毫秒遍历一遍所有动态结果,直到所有任务执行完毕
do {
System.out.printf("Main: 已经完成多少个任务: %d\n",executor.getCompletedTaskCount());
for (int i = 0; i < resultList.size(); i++) {
Future<Long> result = resultList.get(i);
System.out.printf("Main: Task %d is %s\n",i,result.isDone());
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (executor.getCompletedTaskCount() < resultList.size());
// 若所有任务执行完毕,则对执行结果进行累计
long total = 0;
for (int i = 0; i < resultList.size(); i++) {
Future<Long> result = resultList.get(i);
long sum = 0;
try {
sum = result.get();
total += sum;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.printf("total is: %d\n", total);
executor.shutdown();
}
}
class CalTask implements Callable<Long> {
private int startNum;
private int endNum;
public CalTask(int startNum, int endNum) {
this.startNum = startNum;
this.endNum = endNum;
}
@Override
public Long call() throws Exception {
long sum = 0;
for (int i = startNum; i <= endNum; i++) {
sum += i;
}
Thread.sleep(new Random().nextInt(100));
System.out.printf("%s: %d\n", Thread.currentThread().getName(), sum);
return sum;
}
}
Java识别静态验证码和动态验证码
写了一个简单java工具类,用于验证码点阵打印+自动识别。为了提升识别精度和程序性能,此工具类是针对特定类型的验证码的,若要用于其他类型的验证码识别,需要做相应调整。
文章分两部分演示了此java工具类如何识别静态验证码图片和动态验证码gif。
一、静态验证码图片识别
输入验证码:
程序运行结果:
======= print and recognize captchapic =======
"................................................................................",
"................................................................................",
"................................................................................",
"................##.##........#####..............................................",
"................##.##.......##...##.............................................",
"................##.##.............##............................................",
"............###.##.##.###........##....#####....................................",
"...........##..###.###..##.....###....##...##...................................",
"..........##....##.##....##......##........##...................................",
"..........##....##.##....##.......##..#######...................................",
"..........##....##.##....##.......##.##....##...................................",
"...........##..###.##....##.##...##..##...###...................................",
"............###.##.##....##..#####....####.##...................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................",
"................................................................................"
recognize: dh3a
相应代码如下:
package com.demo.check;
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;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class CaptchaRecognizer {
public static void main(String[] args) {
HttpClient httpClient = new HttpClient();
GetMethod getMethod = new GetMethod("https://img2020.cnblogs.com/blog/1039974/202011/1039974-20201119224011928-1654538410.png"); // 验证码链接
for (int i = 0; i < 5; i++) {
try {
// 执行get请求
int statusCode = httpClient.executeMethod(getMethod);
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + getMethod.getStatusLine());
} else {
File captcha = File.createTempFile("ybt", ".png");
OutputStream outStream = new FileOutputStream(captcha);
InputStream inputStream = getMethod.getResponseBodyAsStream();
IOUtils.copy(inputStream, outStream);
outStream.close();
BufferedImage image = ImageIO.read(captcha);
System.out.println("======= print and recognize captchapic =======");
printImage(image);
System.out.printf("recognize: %s\n", recognizeCaptcha(image));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放连接
getMethod.releaseConnection();
}
}
}
/**
* @param colorInt 像素点的RGB值
* @return
*/
private static boolean isBlack(int colorInt) {
Color color = new Color(colorInt);
if (color.getRed() + color.getGreen() + color.getBlue() <= 10) {
return true;
}
return false;
}
/**
* @param image 需要打印的图像
* @throws IOException
*/
private static void printImage(BufferedImage image) {
int h = image.getHeight();
int w = image.getWidth();
// 矩阵打印
for (int y = 0; y < h; y++) {
System.out.printf("\"");
for (int x = 0; x < w; x++) {
if (isBlack(image.getRGB(x, y))) {
System.out.print("#");
} else {
System.out.print(".");
}
}
System.out.printf("%s", y == h-1 ? "\"" : "\",");
System.out.println();
}
}
/**
* @param image 待识别的符号图片
* @return
*/
private static char recognizeSymbol(BufferedImage image) {
int h = image.getHeight();
int w = image.getWidth();
int minDiff = 999999;
char symAns = 0;
// 对于某个给定数值
for (int i = 0; i < 10; i++) {
int curDiff = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
boolean pixel1 = digitals[i][y].charAt(x) == '#';
boolean pixel2 = isBlack(image.getRGB(x, y));
if (pixel1 != pixel2) {
++curDiff;
}
}
}
if (curDiff < minDiff) {
minDiff = curDiff;
symAns = (char) ('0' + i);
}
if (minDiff == 0) {
return symAns;
}
}
// 对于某个给定字母
for (int i = 0; i < 26; i++) {
int curDiff = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
boolean pixel1 = alphas[i][y].charAt(x) == '#';
boolean pixel2 = isBlack(image.getRGB(x, y));
if (pixel1 != pixel2) {
++curDiff;
}
}
}
if (curDiff < minDiff) {
minDiff = curDiff;
symAns = (char) ('a' + i);
}
if (minDiff == 0) {
return symAns;
}
}
return symAns;
}
/**
* @param image 需要被分割的验证码
* @return
*/
private static List<BufferedImage> splitImage(BufferedImage image) {
List<BufferedImage> subImgs = new ArrayList<BufferedImage>();
subImgs.add(image.getSubimage(10, 3, 8, 12));
subImgs.add(image.getSubimage(19, 3, 8, 12));
subImgs.add(image.getSubimage(28, 3, 8, 12));
subImgs.add(image.getSubimage(37, 3, 8, 12));
return subImgs;
}
/**
* @param image 待识别的验证码
* @return
*/
public static String recognizeCaptcha(BufferedImage image) {
StringBuilder ans = new StringBuilder();
List<BufferedImage> subImgs = splitImage(image);
for (BufferedImage subImg : subImgs) {
// 依次识别子图片
ans.append(recognizeSymbol(subImg));
}
return ans.toString();
}
private static String[][] digitals = new String[][]{
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....##",
"......##",
".....##.",
"....##..",
"...##...",
"..##....",
".##.....",
"########",
"........",
"........"
},
{
".#####..",
"##...##.",
"......##",
".....##.",
"...###..",
".....##.",
"......##",
"......##",
"##...##.",
".#####..",
"........",
"........"
},
{
".....##.",
"....###.",
"...####.",
"..##.##.",
".##..##.",
"##...##.",
"########",
".....##.",
".....##.",
".....##.",
"........",
"........"
},
{
"#######.",
"##......",
"##......",
"##.###..",
"###..##.",
"......##",
"......##",
"##....##",
".##..##.",
"..####..",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....#.",
"##......",
"##.###..",
"###..##.",
"##....##",
"##....##",
".##..##.",
"..####..",
"........",
"........"
},
{
"########",
"......##",
"......##",
".....##.",
"....##..",
"...##...",
"..##....",
".##.....",
"##......",
"##......",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....##",
".##..##.",
"..####..",
".##..##.",
"##....##",
"##....##",
".##..##.",
"..####..",
"........",
"........"
},
{
"..####..",
".##..##.",
"##....##",
"##....##",
".##..###",
"..###.##",
"......##",
".#....##",
".##..##.",
"..####..",
"........",
"........"
}
};
private static String[][] alphas = new String[][]{
{
"........",
"........",
"........",
"..#####.",
".##...##",
"......##",
".#######",
"##....##",
"##...###",
".####.##",
"........",
"........"
},
{
"##......",
"##......",
"##......",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"###..##.",
"##.###..",
"........",
"........"
},
{
"........",
"........",
"........",
"..#####.",
".##...##",
"##......",
"##......",
"##......",
".##...##",
"..#####.",
"........",
"........"
},
{
"......##",
"......##",
"......##",
"..###.##",
".##..###",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"........",
"........"
},
{
"........",
"........",
"........",
"..####..",
".##..##.",
"##....##",
"########",
"##......",
".##...##",
"..#####.",
"........",
"........"
},
{
"...####.",
"..##..##",
"..##..##",
"..##....",
"..##....",
"######..",
"..##....",
"..##....",
"..##....",
"..##....",
"........",
"........"
},
{
"........",
"........",
"........",
".#####.#",
"##...###",
"##...##.",
"##...##.",
".#####..",
"##......",
".######.",
"##....##",
".######."
},
{
"##......",
"##......",
"##......",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
"........",
"........"
},
{
"...##...",
"...##...",
"........",
"..###...",
"...##...",
"...##...",
"...##...",
"...##...",
"...##...",
".######.",
"........",
"........"
},
{
".....##.",
".....##.",
"........",
"....###.",
".....##.",
".....##.",
".....##.",
".....##.",
".....##.",
"##...##.",
"##...##.",
".#####.."
},
{
".##.....",
".##.....",
".##.....",
".##..##.",
".##.##..",
".####...",
".####...",
".##.##..",
".##..##.",
".##...##",
"........",
"........"
},
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"........",
"........",
"........",
"#.##.##.",
"##.##.##",
"##.##.##",
"##.##.##",
"##.##.##",
"##.##.##",
"##.##.##",
"........",
"........"
},
{
"........",
"........",
"........",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
"........",
"........"
},
{
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........",
"........"
},
{
"........",
"........",
"........",
"##.###..",
"###..##.",
"##....##",
"##....##",
"##....##",
"###..##.",
"##.###..",
"##......",
"##......"
},
{
"........",
"........",
"........",
"..###.##",
".##..###",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"......##",
"......##"
},
{
"........",
"........",
"........",
"##.####.",
".###..##",
".##.....",
".##.....",
".##.....",
".##.....",
".##.....",
"........",
"........"
},
{
"........",
"........",
"........",
".######.",
"##....##",
"##......",
".######.",
"......##",
"##....##",
".######.",
"........",
"........"
},
{
"........",
"..##....",
"..##....",
"######..",
"..##....",
"..##....",
"..##....",
"..##....",
"..##..##",
"...####.",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
".##..##.",
".##..##.",
"..####..",
"..####..",
"...##...",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
"##.##.##",
"##.##.##",
"##.##.##",
"########",
".##..##.",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
".##..##.",
"..####..",
"...##...",
"..####..",
".##..##.",
"##....##",
"........",
"........"
},
{
"........",
"........",
"........",
"##....##",
"##....##",
"##....##",
"##....##",
"##....##",
".##..###",
"..###.##",
"#.....##",
".######."
},
{
"........",
"........",
"........",
".######.",
".....##.",
"....##..",
"...##...",
"..##....",
".##.....",
".######.",
"........",
"........"
}
};
}
二、动态验证码gif识别
动态验证码gif的识别和静态验证码图片的识别非常相识,两者之间唯一的区别在于gif是由多帧静态图片所构成的。所以我们处理gif的思路很简单,从特定帧的静态图片中,识别需要的验证符号。
输入验证码:
程序运行结果:
======= print and recognize captchapic =======
"..................................................................................................................................................",
"..................................................................................................................................................",
"....................#####.........................................................................................................................",
".................###.....###......................................................................................................................",
".................#.........#......................................................................................................................",
".................#..........#.....................................................................................................................",
"................#...........#.....................................................................................................................",
"................#.#######....#..........................######....................................................................................",
"................###########.#.........................##########..................................................................................",
"................#############........................###########..................................................................................",
"................##.....#####.........................##.....#####.................................................................................",
".................##.....####................................#####.................................................................................",
"...................###.####..................................####........................#######..................................................",
"......................#####.................................#######....................##########.................................................",
".....................#####..................................####....#..................###########................................................",
".................########..................................####......#.................#.....#####................................................",
".................#######..................................####.......#........................####................................................",
".................#########...............................####.........#.......................####................................................",
".....................######.............................###.#........#...................########.................................................",
"....................#######...........................####...#.......#.................##########.................................................",
"..................##...######........................####.....##..###.................####...####.................................................",
".................#.....####..#......................####.........#...................####....####.................................................",
".................#....#####..#.....................####..............................####....####.................................................",
"..............#...##.#####.##.....................####...............................####...#####.................................................",
".............##############......................#############.......................#############................................................",
".............###########.........................#############.......................######..#####................................................",
"...............#######...........................#############........................####...#####................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
".................................................................................................................................................."
<<< frame >>>
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
"..................................................................................................................................................",
".................................................................................................................................#####............",
"...............................................................................................................................########...........",
"........................................................######................................................................########............",
"......................................................##########.........................................##...................####...#............",
".....................................................###########........................................#..#.................####.................",
".....................................................##.....#####.......................................#..#.................####.................",
"............................................................#####......................................#....#................####.................",
".............................................................####........................#######.......#....#..............##########.............",
"............................................................####.......................##########......#....#.............##########..............",
"............................................................####.......................###########.....#....#.............##########..............",
"...........................................................####........................#.....#####.....#....#...............####..................",
"..........................................................####................................####......#..#................####..................",
".........................................................####.................................####......#..#................####..................",
"........................................................###..............................########........##................####...................",
"......................................................####.............................##########..........................####...................",
".....................................................####.............................####...####..........................####...................",
"....................................................####......................####...####....####..........................####...................",
"...................................................####......................#....#..####....####.......####...............####...................",
"..................................................####.......................#....#..####...#####.....##....###............####...................",
".................................................#############...............#.....#.#############...#.........#..........####....................",
".................................................#############...............#....#..######..#####...#.........#..........####....................",
".................................................#############...............#....#...####...#####..#...........#.........####....................",
"..............................................................................##.#..................#...........#.................................",
"................................................................................#...................#............#................................",
"....................................................................................................#...........#.................................",
".....................................................................................................#..........#.................................",
".....................................................................................................#.........#..................................",
".....................................................................................................##.......##.................................."
recognize: 32af
以下贴出gif的分割函数,其它过程和第一部分基本相同,之后逐个解析静态子图片即可。
/**
* @param file 需要被分割的gif文件
* @throws Exception
*/
private static List<BufferedImage> splitGif(File file) throws IOException {
FileImageInputStream in = new FileImageInputStream(file);
ImageReaderSpi readerSpi = new GIFImageReaderSpi();
GIFImageReader gifReader = (GIFImageReader) readerSpi.createReaderInstance();
gifReader.setInput(in);
int num = gifReader.getNumImages(true);
ImageWriterSpi writerSpi = new GIFImageWriterSpi();
GIFImageWriter writer = (GIFImageWriter) writerSpi.createWriterInstance();
List<BufferedImage> subImgs = new ArrayList<BufferedImage>();
for (int i = 0; i < num; i++) {
File frame = File.createTempFile("mxt", ".png");
FileImageOutputStream out = new FileImageOutputStream(frame);
writer.setOutput(out);
writer.write(gifReader.read(num - i - 1));
out.close();
// 分割每一帧图片,进行识别
BufferedImage image = ImageIO.read(frame);
if (i == 1 || i == 2) {
printImage(image);
System.out.println("<<< frame >>>");
}
subImgs.add(image.getSubimage(7 + i * 36, 5, 30, 27));
}
in.close();
return subImgs;
}
参考链接
[1] https://blog.csdn.net/problc/article/details/5794460#commentBox
[2] https://blog.csdn.net/lmj623565791/article/details/23960391/
[3] https://blog.csdn.net/chwshuang/article/details/64923354