JAVA爬蟲---驗證碼識別技術(一)
阿新 • • 發佈:2018-12-21
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; } }
處理到這裡我們就可以得到一個二值化後的圖片了。
然後我們就要開始對二值化後的圖進行等分,然後和我們樣本庫中的圖片進行一次畫素比對。