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

难点:如何获取子线程的执行结果并聚合

思路一

生产者-消费者 经典模型:

  1. 多个生产者负责生产(累加)作业
  2. 生产者将生产结果存入共享仓库中
  3. 消费者(主线程)从共享仓库中取出结果
/**
 * 多线程计算累加数
 */
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);
    }
}

思路二

线程异步返回:

  1. 利用线程池并发处理多个任务
  2. 使用Future+Callable获取异步执行结果
  3. 待线程池中所有任务结束,计算累加结果
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

posted on 2021-01-31 18:42  shuzihua  阅读(108)  评论(0编辑  收藏  举报

导航