1. 程式人生 > >Tesseract做圖片驗證碼識別

Tesseract做圖片驗證碼識別

linux下的安裝 [ 參考這裡 ]

環境準備

yum -y update
yum -y install libstdc++ autoconf automake libtool autoconf-archive pkg-config gcc gcc-c++ make libjpeg-devel libpng-devel libtiff-devel zlib-devel

安裝leptonica[ 這裡下載 ]

tar -zvxf leptonica-1.74.4.tar.gz
cd leptonica-1.74.4
./autobuild
./configure
make
make install

安裝tesseract [ 這裡下載 ]

unzip tesseract-master.zip
cd tesseract-master
(1)./autogen.sh
(2)PKG_CONFIG_PATH=/usr/local/lib/pkgconfig LIBLEPT_HEADERSDIR=/usr/local/include ./configure –with-extra-includes=/usr/local/include –with-extra-libraries=/usr/local/lib
(3)LDFLAGS=”-L/usr/local/lib” CFLAGS=”-I/usr/local/include” make
(4)make install

cd /usr/local/share/
上傳eng.traineddata

到此就安裝完成了。

Windows下的安裝

windows上的安裝就不介紹了,注意安裝好了以後要新增環境變數:
path中新增:D:\Program Files (x86)\Tesseract-OCR\tessdata
新建TESSDATA_PREFIX:D:\Program Files (x86)\Tesseract-OCR\tessdata

使用

tesseract image1.jpg out –psm 7 -l eng

image1.jpg:是輸入檔名
out:識別出來的文字存放在out.txt這個檔案中
-l:代表文字的型別,eng就是英文。
–psm:代表不同的切割方式

  • 0 Orientation and script detection (OSD) only.
  • 1 Automatic page segmentation with OSD.
  • 2 Automatic page segmentation, but no OSD, or OCR.
  • 3 Fully automatic page segmentation, but no OSD. (Default)
  • 4 Assume a single column of text of variable sizes.
  • 5 Assume a single uniform block of vertically aligned text.
  • 6 Assume a single uniform block of text.
  • 7 Treat the image as a single text line.
  • 8 Treat the image as a single word.
  • 9 Treat the image as a single word in a circle.
  • 10 Treat the image as a single character.
  • 11 Sparse text. Find as much text as possible in no particular order.
  • 12 Sparse text with OSD.
  • 13 Raw line. Treat the image as a single text line, bypassing hacks that are Tesseract-specific.

為了提高識別率可以做灰度化二值化等處理.

JAVA程式碼如下:


public class OCRUtil {
    private static final String EOL = System.getProperty("line.separator");
    public static String recognizeText(byte[] image) throws Exception {
        //圖片預處理,灰度化+二值化
        image = preHandleImage(image);
        //把位元組陣列儲存到臨時目錄
        String tempDir=System.getProperty("java.io.tmpdir");
        String uuid = UUIDUtil.uuid();
        String tempFileName = uuid +".jpg";
        String resultFileName = uuid;
        File tempFile = new File(tempDir, tempFileName);
        File resultFile = new File(tempDir, resultFileName);
        IOUtil.saveInputStream(new ByteArrayInputStream(image), new FileOutputStream(tempFile));
        //生成作業系統命令
        List<String> cmd = new ArrayList<String>();
        if(OSUtil.isUnixLikeSystem()) {
            cmd.add("tesseract");
        }else {
            cmd.add("cmd");
            cmd.add("/c");
            cmd.add("tesseract.exe");
        }
        cmd.add(tempFile.getAbsolutePath());
        cmd.add(resultFile.getAbsolutePath());
        cmd.add("-l");
        cmd.add("eng");
        cmd.add("--psm");
        cmd.add("7");
        FileInputStream fin = null;
        BufferedReader in = null;
        try {
            //呼叫作業系統命令
            StringBuffer sb = new StringBuffer();
            ProcessBuilder pb = new ProcessBuilder();
            pb.directory(new File(tempDir));
            pb.command(cmd);
            pb.redirectErrorStream(true);
            Process process = pb.start();
            int w = process.waitFor();
            if (w == 0){// 0代表正常退出
                fin = new FileInputStream(resultFile.getAbsolutePath() + ".txt");
                in = new BufferedReader(new InputStreamReader(fin, "UTF-8"));
                String str = null;
                while ((str = in.readLine()) != null) {
                    sb.append(str).append(EOL);
                }
                return sb.toString().replaceAll("(?is)\\s+", "");
            } 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);
            }
        }finally {
            IOUtil.close(in,fin);
            if(tempFile != null) {
                tempFile.delete();
            }
            if(resultFile != null) {
                resultFile.delete();
                File file = new File(resultFile.getAbsolutePath()+".txt");
                if(file!=null && file.exists()) {
                    file.delete();
                }
            }
        }
    }
    public static byte[] preHandleImage(byte[] imgBytes) throws IOException {
        if(imgBytes == null) {
            return null;
        }
        BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imgBytes));
        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]);
            }
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(binaryBufferedImage, "jpg", out);
        out.close();
        return out.toByteArray();
    }
    private 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;
    }
}