1. 程式人生 > >去驗證碼干擾線

去驗證碼干擾線

首先看看去幹擾線的結果(java)

原始圖片 這裡寫圖片描述 這裡寫圖片描述 這裡寫圖片描述 這裡寫圖片描述

去掉干擾線以後的效果 這裡寫圖片描述 這裡寫圖片描述 這裡寫圖片描述 這裡寫圖片描述

這裡說下開發過程中遇到的問題 1.在網上使用了各種java型別的演算法,直接對BufferedImage進行操作,但是都不理想 2.在使用Tesseract工具進行ocr識別的時候識別率也不高

解決第一個問題,我結合了網上的去幹擾線演算法,以及使用了opencv演算法。使用的opencv也是借鑑一篇網上的部落格。 解決第二個問題,是實用Tesseract工具針對我要識別的驗證碼進行獨立的訓練,而不是使用原始的訓練資料進行識別,這樣子可以明顯的提升識別率。

原始碼

// 這裡是呼叫的核心方法
public class ImageCleanPlanOpencv implements ImageClean{ Logger logger = LoggerFactory.getLogger(ImageCleanPlanOpencv.class); public BufferedImage clean(BufferedImage oriBufferedImage) { try { BufferedImage cleanedBufferedImage = null; //這裡可以看到去燥的方法反覆呼叫了幾次,是為了得更好的去幹擾線結果,這裡可以根據自己的驗證碼情況來編寫呼叫的次數,必須是偶數次,因為opencv的api會進行影象反色
cleanedBufferedImage = cleanLinesInImage(oriBufferedImage); cleanedBufferedImage=cleanLinesInImage(cleanedBufferedImage); cleanedBufferedImage=cleanLinesInImage(cleanedBufferedImage); cleanedBufferedImage=cleanLinesInImage(cleanedBufferedImage); // try {
// ImageUtil.generateImage(cleanedBufferedImage, ImageConstant.url,"new_",""); // } catch (IOException e) { // e.printStackTrace(); // } return cleanedBufferedImage; } catch (IOException e) { logger.error("去噪過程異常",e); e.printStackTrace(); } return null; } /** * * @param oriBufferedImage 需要去噪的影象 * @throws IOException */ public BufferedImage cleanLinesInImage(BufferedImage oriBufferedImage) throws IOException{ BufferedImage bufferedImage = oriBufferedImage; 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]); } } //這裡開始是利用opencv的api進行處理 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); Mat mat = bufferedImageToMat(binaryBufferedImage); Mat kelner = Imgproc.getStructuringElement(MORPH_RECT, new Size(4, 4), new Point(-1, -1)); //腐蝕 Imgproc.erode(mat,mat,kelner); //膨脹 Imgproc.dilate(mat,mat,kelner); //影象反色 Core.bitwise_not(mat,mat); //去噪點 // Imgproc.morphologyEx(mat,mat, MORPH_OPEN, kelner,new Point(-1,-1),1); binaryBufferedImage = mat2BufImg(mat,".png"); cleanImage(binaryBufferedImage,h,w ); return binaryBufferedImage; } public void cleanImage(BufferedImage binaryBufferedImage,int h ,int w ){ //去除干擾線條 for(int y = 1; y < h-1; y++){ for(int x = 1; x < w-1; x++){ boolean flag = false ; if(isBlack(binaryBufferedImage.getRGB(x, y))){ //左右均為空時,去掉此點 if(isWhite(binaryBufferedImage.getRGB(x-1, y)) && isWhite(binaryBufferedImage.getRGB(x+1, y))){ flag = true; } //上下均為空時,去掉此點 if(isWhite(binaryBufferedImage.getRGB(x, y+1)) && isWhite(binaryBufferedImage.getRGB(x, y-1))){ flag = true; } //斜上下為空時,去掉此點 if(isWhite(binaryBufferedImage.getRGB(x-1, y+1)) && isWhite(binaryBufferedImage.getRGB(x+1, y-1))){ flag = true; } if(isWhite(binaryBufferedImage.getRGB(x+1, y+1)) && isWhite(binaryBufferedImage.getRGB(x-1, y-1))){ flag = true; } if(flag){ binaryBufferedImage.setRGB(x,y,-1); } } } } } public Mat bufferedImageToMat(BufferedImage bi) { Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC1); byte[] white = new byte[] { (byte) 255 }; byte[] black = new byte[] { (byte) 0 }; for (int x=0; x<bi.getWidth(); x++) { for (int y=0; y<bi.getHeight(); y++) { if (bi.getRGB(x, y) == Color.BLACK.getRGB()) { mat.put(y, x, black); } else { mat.put(y, x, white); } } } return mat; } /** * Mat轉換成BufferedImage * * @param matrix * 要轉換的Mat * @param fileExtension * 格式為 ".jpg", ".png", etc * @return */ public BufferedImage mat2BufImg (Mat matrix, String fileExtension) { // convert the matrix into a matrix of bytes appropriate for // this file extension MatOfByte mob = new MatOfByte(); Imgcodecs.imencode(fileExtension, matrix, mob); // convert the "matrix of bytes" into a byte array byte[] byteArray = mob.toArray(); BufferedImage bufImage = null; try { InputStream in = new ByteArrayInputStream(byteArray); bufImage = ImageIO.read(in); } catch (Exception e) { e.printStackTrace(); } return bufImage; } public boolean isBlack(int colorInt) { Color color = new Color(colorInt); if (color.getRed() + color.getGreen() + color.getBlue() <= 300) { return true; } return false; } public boolean isWhite(int colorInt) { Color color = new Color(colorInt); if (color.getRed() + color.getGreen() + color.getBlue() > 300) { return true; } return false; } public int isBlackOrWhite(int colorInt) { if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730) { return 1; } return 0; } public int getColorBright(int colorInt) { Color color = new Color(colorInt); return color.getRed() + color.getGreen() + color.getBlue(); } public 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; } }

這段程式碼除開opencv那段是我個人編寫的,其他的也是借鑑網上的原始碼。如果有編寫不對,或者可以修改的更好的建議請指出。