java識別驗證碼

  之前在做數據覈對部分工作,需要獲取廠商的數據,有的廠商提供了api,可以直接通過api拿到數據;有的就沒api,這部分,只能去它們後臺獲取了,那就需要爬蟲,但是,過程中,又碰到登陸的驗證碼。這裏記錄一下識別驗證碼的過程。

使用tess4j

1.下載tessdata和訓練語言包

  在tessract的github直接下載即可,下載地址戳我(只需要項目的 tessdata文件夾 )。這裏,我下載後放在 D:\tesseract\tessdata文件夾。

  訓練語言包:tessdata支持多語言,每個語言不同,比如,英文數字類型的驗證碼,對應的是 eng.traineddata

  訓練語言包,下載地址戳我

下載完,需要把文件放到步驟一的tessdata文件夾下面。我的是放在 D:\tesseract\tessdata下面。

2.加入maven依賴

<dependencies>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>net.sourceforge.tess4j</groupId>
        <artifactId>tess4j</artifactId>
        <version>4.1.1</version>
        <exclusions>
            <exclusion>
                <groupId>com.sun.jna</groupId>
                <artifactId>jna</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

3.編寫代碼

public class TestImgV1 {
    /** tessdata 路徑 */
    private static final String TESSDATA_PATH = "D:\\tesseract\\tessdata";
    /** 驗證碼圖片地址 */
    private static final String url = "http://abc.com/validateCodeForIndex.do";

    public static void main(String[] args) throws Exception {
        BufferedImage codeImage = ImageIO.read(new URL(url));

        // 本地做個備份,好對比
        write2disk(codeImage);

        Tesseract tessreact = new Tesseract();
        tessreact.setDatapath(TESSDATA_PATH);

        String result = tessreact.doOCR(codeImage);
        System.out.println("測驗結果:[" + result.replace(" ", "").trim() + "]");
    }

    private static void write2disk(BufferedImage image) throws IOException {
        File file = new File("d:\\tesseract\\code.jpg");
        ImageIO.write(image, "jpg", file);
    }
}

4.驗證結果

  運行main方法,可以看到,已經正確解析出來了。

  如下圖,左側是檢驗結果,右邊的是驗證碼原圖。

  我隨便試了10次,識別出了6次。但是,如果拿那種1和l、g和q、0和o這種相似度比較高的,識別度驟降。

  有沒有提高識別率的方案?有的,可以使用tesseract-ocr

使用tesseract-ocr

  tesseract-ocr在tess4j的基礎上,增加了對驗證碼去噪點、二值化等操作。要想使用tesseract-ocr,具體步驟如下。

1.安裝tesseract-ocr

  我是windows,下載的是exe安裝文件,官網下載地址戳我

  下載完成,需要加入系統環境變量 Path 和 TESSDATA_PREFIX

  在cmd裏,執行 tesseract –version ,如果能看到輸出的版本號,那配置就沒問題

  執行 tesseract code.jpg result ,它會解析當前目錄下的 code.jpg 驗證碼圖片,把解析結果寫入到 result.txt 文件(txt後綴是它自動加上的)

  詳細安裝步驟,可以參考這篇文章 Windows安裝Tesseract-OCR 4.00並配置環境變量

2.加入maven依賴

<dependencies>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>net.sourceforge.tess4j</groupId>
        <artifactId>tess4j</artifactId>
        <version>4.1.1</version>
        <exclusions>
            <exclusion>
                <groupId>com.sun.jna</groupId>
                <artifactId>jna</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.openpnp</groupId>
        <artifactId>opencv</artifactId>
        <version>3.2.0-0</version>
    </dependency>
</dependencies>

3.編寫代碼

public class TestImgV2 {
    /**tessdata 路徑*/
    private static final String TESSDATA_PATH = "D:\\tesseract\\tesseract-ocr\\tessdata";
    /** 驗證碼路徑*/
    private static final String IMAGE_CODE_PATH = "d:\\tesseract\\code.jpg";

    /** 用來調用OpenCV庫文件,必須添加 */
    static {
        nu.pattern.OpenCV.loadShared();
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    public static void main(String[] args) {
        // 驗證碼圖片
        File imageFile = new File(IMAGE_CODE_PATH);

        // 去噪點、二值化
        filterPic(imageFile);

        imageFile = new File(IMAGE_CODE_PATH);

        String result = getResult(imageFile);
        System.out.println("測驗結果:[" + result.replace(" ", "").trim() + "]");
    }

    // 圖片處理及處理後的圖片儲存
    public static void filterPic(File imageFile) {
        // 圖片去噪
        Mat src = Imgcodecs.imread(imageFile.getAbsolutePath(), Imgcodecs.IMREAD_UNCHANGED);

        Mat dst = new Mat(src.width(), src.height(), CvType.CV_8UC1);

        if (src.empty()) {
            System.out.println("圖片不存在");
            return;
        }

        Imgproc.boxFilter(src, dst, src.depth(), new Size(3.2, 3.2));
        Imgcodecs.imwrite(imageFile.getAbsolutePath(), dst);

        // 圖片閾值處理,二值化
        Mat src1 = Imgcodecs.imread(imageFile.getAbsolutePath(), Imgcodecs.IMREAD_UNCHANGED);
        Mat dst1 = new Mat(src1.width(), src1.height(), CvType.CV_8UC1);

        Imgproc.threshold(src1, dst1, 165, 200, Imgproc.THRESH_TRUNC);
        Imgcodecs.imwrite(imageFile.getAbsolutePath(), dst1);

        // 圖片截取
        Mat src2 = Imgcodecs.imread(imageFile.getAbsolutePath(), Imgcodecs.IMREAD_UNCHANGED);
        Rect roi = new Rect(4, 2, src2.cols() - 7, src2.rows() - 4); // 參數:x座標,y座標,截取的長度,截取的寬度
        Mat dst2 = new Mat(src2, roi);

        Imgcodecs.imwrite(imageFile.getAbsolutePath(), dst2);
    }

    // 獲取解析結果
    public static String getResult(File imageFile) {
        if (!imageFile.exists()) {
            System.out.println("圖片不存在");
        }
        Tesseract tessreact = new Tesseract();
        tessreact.setDatapath(TESSDATA_PATH);

        String result;
        try {
            result = tessreact.doOCR(imageFile);
        } catch (TesseractException e) {
            e.printStackTrace();
            return null;
        }
        return result;
    }
}

4.驗證結果

  在tess4j的基礎上,增加了去噪、二值化,解析效果確實比tess4j高一點,但是,字符之間的間距很小或者存在局部重疊的情況,那基本是解析錯誤。

  不過,如果只是用來識別管理後臺的驗證碼,用tess4j就已經差不多夠用了。

  如果要更進一步,那就要使用 JTessBoxEditorFX 提高識別率,或者,針對性的生成自己的訓練庫了。有興趣的可以參考這個大佬的文章 利用jTessBoxEditor工具進行Tesseract3.02.02樣本訓練,提高驗證碼識別率

發佈了157 篇原創文章 · 獲贊 191 · 訪問量 147萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章