tesseract-OCR图片识别

package com.timeschedule.timeschedule.utils;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;
public class OCR {
        public static void main(String[] args) throws Exception {
            for(int i=0;i<10;i++){
                String fileName = "verifyCode"+(i+1)+".jpg";
                //File testDataDir = new File("J:\\check\\old\\"+fileName);
                //(testDataDir, "J:\\check\\cleanImage",440,160);
                String result = recognizeText(new File("J:\\check\\cleanImage\\"+fileName));
                System.out.println("识别结果为: "+result);
            }
        }

    public static String recognizeText(File imageFile) throws IOException, InterruptedException {
            // 将识别出的内容保存在txt临时文本中,目录与图片在同一级,读取万临时文件内容后会删除该文件
            File tempFile = new File("J:\\check\\cleanImage", "temp");
            StringBuffer result = new StringBuffer(); // 接收识别结果
            // cmd 输出格式[C:\Program Files (x86)\Tesseract-OCR\tesseract, 1.png,
            // output,-l, chi_sim]
            List<String> cmd = new ArrayList<String>();
            // 注意: D:\Tesseract\是你的tesseract-OCR的安装目录
            // 我这里是默认安装目录
            cmd.add("D:\\Tesseract\\tesseract");
            cmd.add("");
            cmd.add(tempFile.getName()); // 指定识别出内容保存位置
            cmd.add("-l"); // 语言参数标志 注意 :这里是字母l 不是数字1
            cmd.add("");
            //cmd.add("verifyCode");
            //cmd.add("eng");
            cmd.add("chi_sim");
            cmd.add("");
           /* if (flag) { // 设置语言库 中文 chi_sim 英文 eng
                cmd.add("chi_sim");
            } else {
                cmd.add("eng");
            }*/
            ProcessBuilder pb = new ProcessBuilder();
            pb.directory(imageFile.getParentFile()); // 设置进程工作目录
            cmd.set(1, imageFile.getName());
            pb.command(cmd);
            pb.redirectErrorStream(true);

            Process process = pb.start();
            int w = process.waitFor(); // 进程等待
            if (w == 0)// 0代表正常退出
            {
                BufferedReader in = new BufferedReader(
                        new InputStreamReader(new FileInputStream(tempFile.getAbsolutePath() + ".txt"), "UTF-8"));
                String str;

                while ((str = in.readLine()) != null) { // 读取识别结果
                    result.append(str);
                }
                in.close();
            } else {
                String msg;
                switch (w) {
                    case 1:
                        msg = "Errors accessing files. There may be spaces in your image's filename.";
                        break;
                    case 29:
                        msg = "Cannot recognize the image or its selected region.";
                        break;
                    case 31:
                        msg = "Unsupported image format.";
                        break;
                    default:
                        msg = "Errors occurred.";
                }
                throw new RuntimeException(msg);
            }
            new File(tempFile.getAbsolutePath() + ".txt").delete(); // 删除临时生成的txt文件
            return result.toString();
        }

        /**
         *
         * @param sfile
         *            需要去噪的图像
         * @param destDir
         *            去噪后的图像保存地址
         * @throws IOException
         */
        public static void cleanImage(File sfile, String destDir,int width,int height)
                throws Exception
        {
            File destF = new File(destDir);
            if (!destF.exists())
            {
                destF.mkdirs();
            }
            BufferedImage bufferedImage = null;
            try{
                 bufferedImage = ImageIO.read(sfile);
                 bufferedImage = resizeBufferedImage(bufferedImage,width,height,true);
            }catch (Exception ex){
                System.out.println(sfile.getName());
            }
            int h = bufferedImage.getHeight();
            int w = bufferedImage.getWidth();
            // 灰度化
            int[][] gray = new int[w][h];
            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    int argb = bufferedImage.getRGB(x, y);
                    // 图像加亮(调整亮度识别率非常高)
                    int r = (int) (((argb >> 16) & 0xFF) * 1.1 + 30);
                    int g = (int) (((argb >> 8) & 0xFF) * 1.1 + 30);
                    int b = (int) (((argb >> 0) & 0xFF) * 1.1 + 30);
                    if (r >= 255)
                    {
                        r = 255;
                    }
                    if (g >= 255)
                    {
                        g = 255;
                    }
                    if (b >= 255)
                    {
                        b = 255;
                    }
                    gray[x][y] = (int) Math
                            .pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2)
                                    * 0.6274 + Math.pow(b, 2.2) * 0.0753), 1 / 2.2);
                }
            }

            // 二值化
            int threshold = ostu(gray, w, h);
            BufferedImage binaryBufferedImage = new BufferedImage(w, h,
                    BufferedImage.TYPE_BYTE_BINARY);
            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    if (gray[x][y] > threshold)
                    {
                        gray[x][y] |= 0x00FFFF;
                    } else
                    {
                        gray[x][y] &= 0xFF0000;
                    }
                    binaryBufferedImage.setRGB(x, y, gray[x][y]);
                }
            }

            // 矩阵打印
            /*for (int y = 0; y < h; y++)
            {
                for (int x = 0; x < w; x++)
                {
                    if (isBlack(binaryBufferedImage.getRGB(x, y)))
                    {
                        System.out.print("*");
                    } else
                    {
                        System.out.print(" ");
                    }
                }
                System.out.println();
            }*/
            //saveImageAsJpg(binaryBufferedImage,new File(destDir, sfile.getName()).getPath(),160,440,true);
            ImageIO.write(binaryBufferedImage, "jpg", new File(destDir, sfile
                    .getName()));
        }


    /**
     * 调整bufferedimage大小
     * @param source BufferedImage 原始image
     * @param targetW int  目标宽
     * @param targetH int  目标高
     * @param flag boolean 是否同比例调整
     * @return BufferedImage  返回新image
     */
    private static BufferedImage resizeBufferedImage(BufferedImage source, int targetW, int targetH, boolean flag) {
        int type = source.getType();
        BufferedImage target = null;
        double sx = (double) targetW / source.getWidth();
        double sy = (double) targetH / source.getHeight();
        /*if (flag && sx > sy) {
            sx = sy;
            targetW = (int) (sx * source.getWidth());
        } else if(flag && sx <= sy){
            sy = sx;
            targetH = (int) (sy * source.getHeight());
        }*/
        if (type == BufferedImage.TYPE_CUSTOM) { // handmade
            ColorModel cm = source.getColorModel();
            WritableRaster raster = cm.createCompatibleWritableRaster(targetW, targetH);
            boolean alphaPremultiplied = cm.isAlphaPremultiplied();
            target = new BufferedImage(cm, raster, alphaPremultiplied, null);
        } else {
            target = new BufferedImage(targetW, targetH, type);
        }
        Graphics2D g = target.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
        g.dispose();
        return target;
    }

    /**
     * @describe 等比缩小
     * @param srcImage
     * @param outFilePath
     * @param width
     * @param hight
     * @param proportion
     * @throws Exception
     */

    public static void saveImageAsJpg(BufferedImage srcImage, String outFilePath,
                                      int width, int hight, boolean proportion)throws Exception {
        File saveFile = new File(outFilePath);
        if (width > 0 || hight > 0) {
            // 原图的大小
            int sw = srcImage.getWidth();
            int sh = srcImage.getHeight();
            // 如果原图像的大小小于要缩放的图像大小,直接将要缩放的图像复制过去
            if (sw > width && sh > hight) {
                srcImage = resize(srcImage, width, hight);
            } else {
                String fileName = saveFile.getName();
                String formatName = fileName.substring(fileName
                        .lastIndexOf('.') + 1);
                ImageIO.write(srcImage, formatName, saveFile);
                return;
            }
        }
        // 缩放后的图像的宽和高
        int w = srcImage.getWidth();
        int h = srcImage.getHeight();
        // 如果缩放后的图像和要求的图像宽度一样,就对缩放的图像的高度进行截取
        if (w == width) {
            // 计算X轴坐标
            int x = 0;
            int y = h / 2 - hight / 2;
            saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
        }
        // 否则如果是缩放后的图像的高度和要求的图像高度一样,就对缩放后的图像的宽度进行截取
        else if (h == hight) {
            // 计算X轴坐标
            int x = w / 2 - width / 2;
            int y = 0;
            saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
        }
    }
    /**
     * 实现缩放后的截图
     * @param image 缩放后的图像
     * @param subImageBounds 要截取的子图的范围
     * @param subImageFile 要保存的文件
     * @throws IOException
     */
    private static void saveSubImage(BufferedImage image,
                                     Rectangle subImageBounds, File subImageFile) throws IOException {
        if (subImageBounds.x < 0 || subImageBounds.y < 0
                || subImageBounds.width - subImageBounds.x > image.getWidth()
                || subImageBounds.height - subImageBounds.y > image.getHeight()) {
            System.out.println("Bad   subimage   bounds");
            return;
        }
        BufferedImage subImage = image.getSubimage(subImageBounds.x,subImageBounds.y, subImageBounds.width, subImageBounds.height);
        String fileName = subImageFile.getName();
        String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
        ImageIO.write(subImage, formatName, subImageFile);
    }

    /**
     * 实现图像的等比缩放
     * @param source
     * @param targetW
     * @param targetH
     * @return
     */
    private static BufferedImage resize(BufferedImage source, int targetW,
                                        int targetH) {
        // targetW,targetH分别表示目标长和宽
        int type = source.getType();
        BufferedImage target = null;
        double sx = (double) targetW / source.getWidth();
        double sy = (double) targetH / source.getHeight();
        // 这里想实现在targetW,targetH范围内实现等比缩放。如果不需要等比缩放
        // 则将下面的if else语句注释即可
        if (sx < sy) {
            sx = sy;
            targetW = (int) (sx * source.getWidth());
        } else {
            sy = sx;
            targetH = (int) (sy * source.getHeight());
        }
        if (type == BufferedImage.TYPE_CUSTOM) { // handmade
            ColorModel cm = source.getColorModel();
            WritableRaster raster = cm.createCompatibleWritableRaster(targetW,
                    targetH);
            boolean alphaPremultiplied = cm.isAlphaPremultiplied();
            target = new BufferedImage(cm, raster, alphaPremultiplied, null);
        } else
            target = new BufferedImage(targetW, targetH, type);
        Graphics2D g = target.createGraphics();
        // smoother than exlax:
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
        g.dispose();
        return target;
    }


    public static boolean isBlack(int colorInt)
        {
            Color color = new Color(colorInt);
            if (color.getRed() + color.getGreen() + color.getBlue() <= 300)
            {
                return true;
            }
            return false;
        }

        public static boolean isWhite(int colorInt)
        {
            Color color = new Color(colorInt);
            if (color.getRed() + color.getGreen() + color.getBlue() > 300)
            {
                return true;
            }
            return false;
        }

        public static int isBlackOrWhite(int colorInt)
        {
            if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730)
            {
                return 1;
            }
            return 0;
        }

        public static int getColorBright(int colorInt)
        {
            Color color = new Color(colorInt);
            return color.getRed() + color.getGreen() + color.getBlue();
        }

        public static int ostu(int[][] gray, int w, int h)
        {
            int[] histData = new int[w * h];
            // Calculate histogram
            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    int red = 0xFF & gray[x][y];
                    histData[red]++;
                }
            }

            // Total number of pixels
            int total = w * h;

            float sum = 0;
            for (int t = 0; t < 256; t++)
                sum += t * histData[t];

            float sumB = 0;
            int wB = 0;
            int wF = 0;

            float varMax = 0;
            int threshold = 0;

            for (int t = 0; t < 256; t++)
            {
                wB += histData[t]; // Weight Background
                if (wB == 0)
                    continue;

                wF = total - wB; // Weight Foreground
                if (wF == 0)
                    break;

                sumB += (float) (t * histData[t]);

                float mB = sumB / wB; // Mean Background
                float mF = (sum - sumB) / wF; // Mean Foreground

                // Calculate Between Class Variance
                float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);

                // Check if new maximum found
                if (varBetween > varMax)
                {
                    varMax = varBetween;
                    threshold = t;
                }
            }

            return threshold;
        }
}

 

posted @ 2021-01-26 09:41  DreamCatt  阅读(187)  评论(0)    收藏  举报