JAVA爬蟲---驗證碼識別技術(一)


        Python中有專門的圖像處理技術比如說PIL,可以對驗證碼一類的圖片進行二值化處理,然后對圖片進行分割,進行像素點比較得到圖片中的數字。這種方案對驗證碼的處理相對較少,運用相對普遍,很多驗證碼圖片可以通過這個方式得到識別,當然還需要一部分的降噪處理。

        什么是圖片二值化處理:簡單也就是把一張五顏六色的驗證碼處理成一張只由黑白構成的驗證碼,這個是為了方便后期我們和保存的黑白單一數字、字母進行像素點比較。

        什么是降噪處理:簡單的解釋就是把驗證碼中的干擾去掉一部分,降噪不可能完全降,但是可以處理一大部分就是對識別的一種進步,畢竟如果降噪處理不行,對后期的像素點比較和結果值影響比較大。

        今天我們用圖片的RGB的色彩比對技術,用JAVA對圖片進行一次二值化處理,然后識別。

   原圖片:     

二值化后圖片:

我們針對這個網頁的驗證碼需要在自己庫中保存的模板類型:.....這一類是用於后期像素點比較得到圖片本身數值的准備。

那么基本流程我們知道了,我們就開始

第一步:圖片下載:

網頁的抓取有時候會有驗證碼的識別,這樣我們就需要對http請求的包進行解析,有的驗證碼可以在js中解析得到,有的是直接返回該網頁頁面,反正可以找到這個img圖片進行下載到本地就行,此處不一一贅述。

第二部:對下載到本地的圖片進行二值化處理:

在這里我自己寫了一個腳本,供大家使用和參考:


public class MyImgDel  {
    //todo splitNums可以根據你給到的圖片色差進行調整,在你自己使用時,可以針對splitNums做一個循環,每次加多少,得到不同的色差比的二值化后的圖片,因為不同的圖片可能干擾線、干擾點顏色原因,二值化后會有差異
    //todo splitWidthNum:把圖片根據長度切分的分數,這個可以根據你圖片中的數字個數進行切分
    public static final int splitNums=4000000;
    public static final int splitWidthNum=5;
    public static void main(String[] args) {
        String path="F://test1.png";
        try{
            BufferedImage img=removeBackgroud(path);
            ImageIO.write(img, "PNG", new File("F://test1-1.png"));
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public static BufferedImage removeBackgroud(String picFile)
            throws Exception {
        BufferedImage img = ImageIO.read(new File(picFile));

        img = img.getSubimage(1, 1, img.getWidth()-2, img.getHeight()-2);
        int width = img.getWidth();
        int height = img.getHeight();
        double subWidth = (double) width/(splitWidthNum+0.0);
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < splitWidthNum; i++) {

            //todo 以下是對圖片進行二值化處理,在這里我的思路是規定,色差范圍在splitNums到負splitNums之間的,算是同色,放入同一個色值,放入一個map中,map中的Key放色值,value放這個色值得個數,后期就根據這個色值來對驗證碼進行二值化
            for (int x = (int) (1 + i * subWidth); x < (i + 1) * subWidth && x < width - 1; ++x) {
                for (int y = 0; y < height; ++y) {
                    if (isWhite(img.getRGB(x, y)) == 1){
                        continue;
                    }
                    Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
                    for (Integer color : map.keySet()) {
                        map2.put(color,map.get(color));
                    }

                    for (Integer color : map2.keySet()) {
                        System.out.println(Math.abs(color)-Math.abs(img.getRGB(x, y)));
                        if (Math.abs(color)-Math.abs(img.getRGB(x, y))<splitNums&&Math.abs(color)-Math.abs(img.getRGB(x, y))>-splitNums){
                            map.put(color, map.get(color) + 1);
                        }else{
                            map.put(img.getRGB(x, y), 1);
                        }
                    }
                    if (map.isEmpty()){
                        map.put(img.getRGB(x, y), 1);
                    }
                }
            }
            System.out.println("==============================");

            int max = 0;
            int colorMax = 0;
            for (Integer color : map.keySet()) {
                if (max < map.get(color)) {
                    max = map.get(color);
                    colorMax = color;
                }
            }

            for (int x = (int) (1 + i * subWidth); x < (i + 1) * subWidth&& x < width - 1; ++x) {
                for (int y = 0; y < height; ++y) {
                    int ress=Math.abs(img.getRGB(x, y))-Math.abs(colorMax);
                    if (ress<splitNums&&ress>-splitNums) {
                        img.setRGB(x, y, Color.WHITE.getRGB());
                    } else {
                        img.setRGB(x, y, Color.BLACK.getRGB());
                    }
                }
            }
        }
        return img;
    }

    //todo 判斷是否為白色的方法
    public static int isWhite(int colorInt) {
        Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue()>600) {
            return 1;
        }
        return 0;
    }

}

處理到這里我們就可以得到一個二值化后的圖片了。

然后我們就要開始對二值化后的圖進行等分,然后和我們樣本庫中的圖片進行一次像素比對。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM