1. 程式人生 > >java影象處理:灰度化,二值化,降噪,切割,裁剪,識別,找相似等

java影象處理:灰度化,二值化,降噪,切割,裁剪,識別,找相似等

前段時間做爬蟲,涉及到對圖片驗證碼的破解,這裡羅列一些常用的影象處理方法,都很簡單並沒用到什麼複雜的演算法,所以不涉及opencv,都是一些直接對rgb畫素點的操作,很簡單也很好理解,至於識別直接用的tesseract-ocr,也可以用svm。(ps:圖片的畫素值矩陣的原點在左上角,上邊是x軸,左邊是y軸)

1、灰度化和二值化,即把彩色圖片經過灰度化和二值化變成只有黑白(只有0,1的矩陣)的資料,便於後續對圖片的處理

        public static BufferedImage grayImage(BufferedImage bufferedImage) throws Exception {

		int width = bufferedImage.getWidth();
		int height = bufferedImage.getHeight();

		BufferedImage grayBufferedImage = new BufferedImage(width, height, bufferedImage.getType());
		for (int i = 0; i < bufferedImage.getWidth(); i++) {
			for (int j = 0; j < bufferedImage.getHeight(); j++) {
				final int color = bufferedImage.getRGB(i, j);
				final int r = (color >> 16) & 0xff;
				final int g = (color >> 8) & 0xff;
				final int b = color & 0xff;
				int gray = (int) (0.3 * r + 0.59 * g + 0.11 * b);
				int newPixel = colorToRGB(255, gray, gray, gray);
				grayBufferedImage.setRGB(i, j, newPixel);
			}
		}

		return grayBufferedImage;

	}

	/**
	 * 顏色分量轉換為RGB值
	 * 
	 * @param alpha
	 * @param red
	 * @param green
	 * @param blue
	 * @return
	 */
	private static int colorToRGB(int alpha, int red, int green, int blue) {

		int newPixel = 0;
		newPixel += alpha;
		newPixel = newPixel << 8;
		newPixel += red;
		newPixel = newPixel << 8;
		newPixel += green;
		newPixel = newPixel << 8;
		newPixel += blue;

		return newPixel;

	}

	public static BufferedImage binaryImage(BufferedImage image) throws Exception {
		int w = image.getWidth();  
	    int h = image.getHeight();  
	    float[] rgb = new float[3];  
	    double[][] zuobiao = new double[w][h];  
	    int black = new Color(0, 0, 0).getRGB();  
	    int white = new Color(255, 255, 255).getRGB();  
	    BufferedImage bi= new BufferedImage(w, h,  
	            BufferedImage.TYPE_BYTE_BINARY);;  
	    for (int x = 0; x < w; x++) {  
	        for (int y = 0; y < h; y++) {  
	            int pixel = image.getRGB(x, y);   
	            rgb[0] = (pixel & 0xff0000) >> 16;  
	            rgb[1] = (pixel & 0xff00) >> 8;  
	            rgb[2] = (pixel & 0xff);  
	            float avg = (rgb[0]+rgb[1]+rgb[2])/3;  
	            zuobiao[x][y] = avg;      
	              
	        }  
	    }  
            //這裡是閾值,白底黑字還是黑底白字,大多數情況下建議白底黑字,後面都以白底黑字為例
	    double SW = 192;  
	    for (int x = 0; x < w; x++) {  
	        for (int y = 0; y < h; y++) {  
	            if (zuobiao[x][y] < SW) {  
	                bi.setRGB(x, y, black);  
	            }else{  
	                bi.setRGB(x, y, white);  
	            }  
	        }             
	    }  
	    
	    
	    
	    return bi;
	}
// 自己加周圍8個灰度值再除以9,算出其相對灰度值
	public static double getGray(double[][] zuobiao, int x, int y, int w, int h) {
		double rs = zuobiao[x][y] + (x == 0 ? 255 : zuobiao[x - 1][y]) + (x == 0 || y == 0 ? 255 : zuobiao[x - 1][y - 1])
				+ (x == 0 || y == h - 1 ? 255 : zuobiao[x - 1][y + 1]) + (y == 0 ? 255 : zuobiao[x][y - 1])
				+ (y == h - 1 ? 255 : zuobiao[x][y + 1]) + (x == w - 1 ? 255 : zuobiao[x + 1][y])
				+ (x == w - 1 || y == 0 ? 255 : zuobiao[x + 1][y - 1])
				+ (x == w - 1 || y == h - 1 ? 255 : zuobiao[x + 1][y + 1]);
		return rs / 9;
	}

2、降噪(領域檢測法),針對二值化後的圖片來說(白底黑字),噪點就是圖片中一堆密集黑色畫素點中少許白色畫素點(字型裡的白點或背景裡的黑點),這時,解決方法可以遍歷畫素點,一個畫素點周圍有8個畫素點,如果這個畫素點周圍有6個以上畫素點是黑色就可以把這個畫素點也認為是黑色:

/**
	 * 降噪,以1個畫素點為單位(實際使用中可以迴圈降噪,或者把單位可以擴大為多個畫素點)
	 * @param image
	 * @return
	 */
	public static BufferedImage denoise(BufferedImage image){
		int w = image.getWidth();  
	    int h = image.getHeight();
	    int white = new Color(255, 255, 255).getRGB();  

	    if(isWhite(image.getRGB(1, 0)) && isWhite(image.getRGB(0, 1)) && isWhite(image.getRGB(1, 1))){
	    	image.setRGB(0,0,white);
        }
	    if(isWhite(image.getRGB(w-2, 0)) && isWhite(image.getRGB(w-1, 1)) && isWhite(image.getRGB(w-2, 1))){
	    	image.setRGB(w-1,0,white);
        }
	    if(isWhite(image.getRGB(0, h-2)) && isWhite(image.getRGB(1, h-1)) && isWhite(image.getRGB(1, h-2))){
	    	image.setRGB(0,h-1,white);
        }
	    if(isWhite(image.getRGB(w-2, h-1)) && isWhite(image.getRGB(w-1, h-2)) && isWhite(image.getRGB(w-2, h-2))){
	    	image.setRGB(w-1,h-1,white);
        }
	    
	    for(int x = 1; x < w-1; x++){
	    	int y = 0;
	    	if(isBlack(image.getRGB(x, y))){
            	int size = 0;
                if(isWhite(image.getRGB(x-1, y))){
                	size++;
                }
                if(isWhite(image.getRGB(x+1, y))){
                	size++;
                }
                if(isWhite(image.getRGB(x, y+1))){
                	size++;
                }
                if(isWhite(image.getRGB(x-1, y+1))){
                	size++;
                }
                if(isWhite(image.getRGB(x+1, y+1))){
                	size++;
                } 
                if(size>=5){
                	image.setRGB(x,y,white);                     
                }
            }
	    }
	    for(int x = 1; x < w-1; x++){
	    	int y = h-1;
	    	if(isBlack(image.getRGB(x, y))){
            	int size = 0;
                if(isWhite(image.getRGB(x-1, y))){
                	size++;
                }
                if(isWhite(image.getRGB(x+1, y))){
                	size++;
                }
                if(isWhite(image.getRGB(x, y-1))){
                	size++;
                }
                if(isWhite(image.getRGB(x+1, y-1))){
                	size++;
                }
                if(isWhite(image.getRGB(x-1, y-1))){
                	size++;
                }
                if(size>=5){
                	image.setRGB(x,y,white);                     
                }
            }
	    }
	    
	    for(int y = 1; y < h-1; y++){
	    	int x = 0;
	    	if(isBlack(image.getRGB(x, y))){
            	int size = 0;
                if(isWhite(image.getRGB(x+1, y))){
                	size++;
                }
                if(isWhite(image.getRGB(x, y+1))){
                	size++;
                }
                if(isWhite(image.getRGB(x, y-1))){
                	size++;
                }
                if(isWhite(image.getRGB(x+1, y-1))){
                	size++;
                }
                if(isWhite(image.getRGB(x+1, y+1))){
                	size++;
                } 
                if(size>=5){
                	image.setRGB(x,y,white);                     
                }
            }
	    }
	    
	    for(int y = 1; y < h-1; y++){
	    	int x = w - 1;
	    	if(isBlack(image.getRGB(x, y))){
            	int size = 0;
            	if(isWhite(image.getRGB(x-1, y))){
                	size++;
                }
                if(isWhite(image.getRGB(x, y+1))){
                	size++;
                }
                if(isWhite(image.getRGB(x, y-1))){
                	size++;
                }
                //斜上下為空時,去掉此點
                if(isWhite(image.getRGB(x-1, y+1))){
                	size++;
                }
                if(isWhite(image.getRGB(x-1, y-1))){
                	size++;
                }
                if(size>=5){
                	image.setRGB(x,y,white);                     
                }
            }
	    }
	    
		//降噪,以1個畫素點為單位
    	for(int y = 1; y < h-1; y++){
            for(int x = 1; x < w-1; x++){                   
                if(isBlack(image.getRGB(x, y))){
                	int size = 0;
                    //上下左右均為空時,去掉此點
                    if(isWhite(image.getRGB(x-1, y))){
                    	size++;
                    }
                    if(isWhite(image.getRGB(x+1, y))){
                    	size++;
                    }
                    //上下均為空時,去掉此點
                    if(isWhite(image.getRGB(x, y+1))){
                    	size++;
                    }
                    if(isWhite(image.getRGB(x, y-1))){
                    	size++;
                    }
                    //斜上下為空時,去掉此點
                    if(isWhite(image.getRGB(x-1, y+1))){
                    	size++;
                    }
                    if(isWhite(image.getRGB(x+1, y-1))){
                    	size++;
                    }
                    if(isWhite(image.getRGB(x+1, y+1))){
                    	size++;
                    } 
                    if(isWhite(image.getRGB(x-1, y-1))){
                    	size++;
                    }
                    if(size>=8){
                    	image.setRGB(x,y,white);                     
                    }
                }
            }
        }
	    
	    return image;
	}
	
	 public static boolean isBlack(int colorInt)  
     {  
         Color color = new Color(colorInt);  
         if (color.getRed() + color.getGreen() + color.getBlue() <= 300)  
         {  
             return true;  
         }  
         return false;  
     }  

     public static boolean isWhite(int colorInt)  
     {  
         Color color = new Color(colorInt);  
         if (color.getRed() + color.getGreen() + color.getBlue() > 300)  
         {  
             return true;  
         }  
         return false;  
     }  
     
     public static int isBlack(int colorInt, int whiteThreshold) {
 		final Color color = new Color(colorInt);
 		if (color.getRed() + color.getGreen() + color.getBlue() <= whiteThreshold) {
 			return 1;
 		}
 		return 0;
 	}

3、切割字串,比如識別驗證碼時,可能需要將每個字元給單獨切割下來進行單獨識別,準確率會高得多,如果驗證碼字元之間粘連度不高,可以使用最簡單的投影法,即,x軸上的每一列有多少個黑色畫素點,這樣形成了一個數組,針對這個陣列可以想象成一個折線圖,如果圖片沒有粘連那最理想的效果是這樣:

如果有粘連,那就是一個有波峰波谷的折線圖,只有通過演算法找到波峰波谷來切割了;同理,對y軸也可以進行投影。opencv的話,還有個常用的輪廓法,需要的可以瞭解下(吐槽:java版的opencv和c++版本的api稍有不同,這個只有看官方文件了)

4、裁剪,把上一步的畫素點區域找到(原點+寬高)即可裁剪。

5、識別,如果字型扭曲的不是很嚴重的話,推薦直接使用tesseract-ocr簡單方便,java包好像叫tess4j,也可以自己用svm;字型扭曲嚴重的話,只有自己寫演算法了,這種情況還是建議使用opencv來處理,有相應的處理方法的。

6、圖片相似度,像有些驗證碼扭曲的厲害確實破解不了的(md,難道要上神經網路喂幾萬張圖片去識別麼,拜託,我只是爬個數據而已,還是不費力氣了~~),

   

但是,我之前碰到過有些網站雖然破解不了,但是驗證碼圖片數量是固定的,比如裁判文書網,爬了幾千張下來才發現基本上都是重複的,之前的白弄了。其實可以直接hash的,但是為了擴充套件和複用,還是弄個圖片相似度,其實原理差的不多,還是圖片預處理後再進行hash,形成每張圖片獨有的指紋。

PS:簡單的可以自己處理畫素,也便於學習和加深理解,更復雜的建議還是使用opencv吧~~

這裡可以簡單說說我最開始怎麼處理裁判文書網的驗證碼的,準確率只有60%左右(大部分8,90%多的圖片能分割出來,識別就不行了);字型,背景色,干擾線,噪點,顏色基本都不一樣,通過某些演算法區分這幾個區域(分類演算法很多,kmeans最簡單效果也行),然後挨著邊緣的是干擾線先去掉(需要與二值化後的進行對比確認干擾線),中間區域分類顏色最多的是字型,然後去掉其他區域,再二值化分割判斷。缺點:有些圖片干擾線和字型顏色很接近分不出來,去掉干擾線把字型的一部分也除掉了。大家還有沒有什麼好的方法

程式碼下載

相關推薦

java影象處理切割裁剪識別相似

前段時間做爬蟲,涉及到對圖片驗證碼的破解,這裡羅列一些常用的影象處理方法,都很簡單並沒用到什麼複雜的演算法,所以不涉及opencv,都是一些直接對rgb畫素點的操作,很簡單也很好理解,至於識別直接用的tesseract-ocr,也可以用svm。(ps:圖片的畫素值矩陣的原點在

影象處理 反色

灰度化 (grayscale) 將彩色影象轉化為灰度影象的過程稱為影象灰度化。彩色影象中的畫素值由RGB三個分量決定,每個分量都有0-255(256種)選擇,這樣一個畫素點的畫素值可以有1600萬種可能(256*256*256),而灰度圖的畫素點的畫素值是RGB三個分量值相

bmp點陣圖檔案讀取、寫入、24位真彩轉8位圖的

影象的二值化處理就是講影象上的點的灰度置為0或255,也就是講整個影象呈現出明顯的黑白效果。即將256個亮度等級的灰度影象通過適當的閥值選取而獲得仍然可以反映影象整體和區域性特徵的二值化影象。在數字影象處理中,二值影象佔有非常重要的地位,特別是在實用的影象處理中,以二值影象處理實現而構成的系統是很多的,要進行

影象變換、、直方圖

1、灰度變換 1)灰度圖的線性變換 Gnew = Fa * Gold + Fb。 Fa為斜線的斜率,Fb為y軸上的截距。 Fa>1 輸出影象的對比度變大,否則變小。 Fa=1 Fb≠0時,影象的灰度上移或下移,效果為影象變亮或變暗。 Fa=-1,Fb=255時,發生影象反轉。 注意:線性變換會出現亮度飽

【OpenCV_09】平滑/模糊圖片 Smooth / Blur Images及 彩色圖轉 圖和

OpenCV 程式碼下面的OpenCV 的程式碼中,核大小從1x1增加到29x29.可以觀察到影象平滑程度隨著核增大的變化程度。平滑影象的核的大小顯示在被平滑影象上。///////////////////////////////////////////////////////////////////////

【數字影象】C++8位和24位BMP點陣圖的平滑、銳處理以及24位真彩圖的

BMP標頭檔案: #ifndef BMP_H//前處理器 #define BMP_H typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; typedef

java影象處理---處理

java實現圖片灰度化(二值化) 此函式功能: 1. 讀圖 2. 建立緩衝區 3. 將圖片畫素複製到緩衝區的相應位置 4. 輸出比較 輸入: RGB

Matlab影象處理繪製直方圖直方圖均衡化

1.imread() MATLAB中影象讀取函式與OpenCV一樣是imread,可以開啟指定路徑圖片,其路徑表示方式與OpenCV中有些許不同如: srcImage=imread('E:\MatlabWorkSpace\實驗一\實驗一圖一.png'); 路徑符號為單"\"

opencv 圖片基本處理反色膨脹腐蝕以及ROI的copy

基於護照的識別和特徵提取,使用opencv2.4.9在VS2012裡做的。直接上程式碼: #include <cv.h> #include <highgui.h> #include <string> using namespace cv;

【數字影象處理直方圖、直方圖均衡化、直方圖規定

    灰度直方圖   一幅影象由不同灰度值的畫素組成,影象中灰度的分佈情況是該影象的一個重要特徵。影象的灰度直方圖就描述了影象中灰度分佈情況,能夠很直觀的展示出影象中各個灰度級所佔的多少。影象的灰度直方圖是灰度級的函式,描述的是影象中具有該灰度級的畫素的個數:其中,橫座標是灰度級,

影象處理-python實現影象處理(消直方圖均衡化形態學)

1、選用合適的影象增強方法對以下給定影象進行增強操作以獲取清晰影象; 2、對增強後的影象進行閾值處理,獲得二值影象; 3、對二值影象進行形態學分析,提取有用資訊區域(即只剩下字母和數字區域);   python程式:     import c

【數字影象處理變換函式(對數變換、反對數變換、冪次變換)

// 對比度增強.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <opencv2/opencv.hpp> #include <math.h> #include <iostream&g

影象驗證碼識別(四)——

一、灰度化 灰度化應用很廣,而且也比較簡單。灰度圖就是將白與黑中間的顏色等分為若干等級,絕大多數位256階。在RGB模型種,黑色(R=G=B=0)與白色(R=G=B=255),那麼256階的灰度劃分就是R=G=B=i,其中i取0到255. 從前面可以知道,OpenCV

影象處理opencv2-直方圖以及直方圖均衡化

1灰度直方圖        1.1 概念 灰度直方圖是關於灰度級分佈的函式,是對影象中灰度級分佈的統計。 灰度直方圖是將數字影象中的所有畫素,按照灰度值的大小,統計其出現的頻率。 灰度直方圖是灰度級的函式,它表示影象中具有某種灰度級的畫素的個數,反映了影象中某種灰度出現的

影象處理模糊影象與彩色清晰影象的變換

  針對模糊影象的處理,個人覺得主要分兩條路,一種是自我激發型,另外一種屬於外部學習型。接下來我們一起學習這兩條路的具體方式。 第一種 自我激發型   基於影象處理的方法,如影象增強和影象復原,以及曾經很火的超解析度演算法。都是在不增加額外資訊的前提下的實現

Matlab影象處理變換函式

首先明確幾個概念 1,灰度:對於通常所謂的黑白影象,把黑色和白色之間按對數關係分為若干等級稱為灰度。灰度分為256階,用灰度表示的影象稱作灰度圖.在影象中用0~255表示,0是全黑,255是全白 2.對比度:對比度值一幅影象中敏感區域最亮的白和最暗的黑之間的不同亮度層級的測

例項說明影象的區別

首先我們還是得了解一下定義(搬運工): 灰度化:在RGB模型中,如果R=G=B時,則彩色表示一種灰度顏色,其中R=G=B的值叫灰度值,因此,灰度影象每個畫素只需一個位元組存放灰度值(又稱強度值、亮度值),灰度範圍為0-255。一般常用的是加權平均法來獲取每個畫素點的灰度值。

JAVA圖片如此簡單方便

package image; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; pub

C#下用Emgucv對圖片進行、邊緣檢測、膨脹腐蝕運算、霍夫變換進行表格識別

 其中每個部分的原理相信在各種書籍和網站上都容易找到,這裡是C#下用Emgucv實現以上相關操作的原始碼全部,轉載請註明http://write.blog.csdn.net/postlist http://blog.csdn.net/yimingsilence/ar

掃描儀掃描文件處理-ABBYY生成小體積黑白PDF

禁止 ima 技術 clas .com image 文件處理 -a src 禁止所有預處理選項: PDF保存選項: 保存提示(選擇“保存為僅圖像PDF”): 掃描儀掃描文件處理-ABBYY生成小體積黑白二值化PDF