zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ",executor.getCompletedTaskCount());
                for (int i = 0; i < resultList.size(); i++) {
                    Future<Long> result = resultList.get(i);
                    System.out.printf("Main: Task %d is %s
    ",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
    ", 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
    ", Thread.currentThread().getName(), sum);
            return sum;
        }
    }
    
    
     

    写了一个简单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
    ", 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

  • 相关阅读:
    2016总结
    centos7安装后的防火墙问题
    推荐一个静态页面生成工具-mkdocs
    shell中单引号、双引号、反引号的区别
    git 出现502错误后用depth一步一步来
    ./test.sh . ./test.sh source ./test.sh的区别
    终端内容输出的同时保存到文件 tee
    nginx出现的403错误
    ubuntu下wine操作usb串口
    tmux的使用
  • 原文地址:https://www.cnblogs.com/xinxihua/p/14353502.html
Copyright © 2011-2022 走看看