新手學,java使用分水嶺算法進行圖像分割(一)

最近被圖像分割整的天昏地暗的,在此感謝老朋友周洋給我關於分水嶺算法的指點!本來打算等彩色圖像分割有個完滿的結果再寫這篇文章,但是考慮到到了這一步也算是一個階段,所以打算對圖像分割做一個系列的博文,於是先寫這篇。

囉嗦了這麼多!先看效果:

 

效果一般,存在着很多過分割現象,但比沒使用濾波之前的效果好很多,過分割是分水嶺算法的通病。這個後續博文會繼續解決。 

本文用java實現的是基於自動種子區域的分水嶺算法,注意本文是基於單色的分割,所以將輸入圖片首先進行灰度化處理,這個比較簡單,不多提了;因此,對於彩色圖像,會存在一些偏差,這個在後續博文裏我會去解決。關於分水嶺算法的概念,請自行百度,本系列主講如何實現以及實現效果。

算法大致分爲四步:圖像預處理、 種子區域獲取、浸水過程(區域增長)、分割結果的合併處理。另外,算法在分水嶺過程中的區域表示上,採用並查集的數據結構表示區域塊,這樣做的好處在於簡化生長過程中的合併處理,關於並查集,參見我這篇博文: http://blog.csdn.net/abcd_d_/article/details/40316455

1、圖像預處理過程:

本文采用二維高斯濾波進行圖像(sigma=3.0)的平滑操作,經驗證去操平滑效果好於中值濾波,讀者可以自己實驗其它的濾波。另外,爲了簡化操作,二維高斯模板可近似爲兩個一維的高斯模板,也就是在下圖中,左邊的濾波過程近似爲右邊的濾波過程。

 

核心代碼爲:

/**
	 * * 將圖像進行高斯模糊:先利用模糊函數計算高斯模板矩陣,然後進行卷積運算。
	 *  
	 *	@高斯模糊 :高斯模糊是一種圖像濾波器,它使用正態分佈(高斯函數)計算模糊模板,並使用該模板與原圖像做卷積運算,達到模糊圖像的目的。
	 *	在實際應用中,在計算高斯函數的離散近似時,在大概3σ距離之外的像素都可以看作不起作用,這些像素的計算也就可以忽略。
	 *	通常,圖像處理程序只需要計算的矩陣就可以保證相關像素影響。
	 *  
	 * @param source
	 * @param index 表示不同的sigma對應的模板
	 * @return double[][] 模糊後的圖像信息矩陣
	 */
	public static double[][] gaussTran(double[][] source,int index){
		
		int height=source.length;
		int width=source[0].length;
		///保存高斯過濾後的結果
		double[][] result=new double[height][width];
		
		double[] template=GaussTemplate1D.gettemplateX_Y(index);
		int tWH=template.length;///模板維數
		
		for(int i=0;i<height;i++){
			for(int j=0;j<width;j++){
				
				///進行模糊處理——————卷積運算
				double sum=0.0;///卷積結果
				for(int m=0;m<tWH;m++){
						///計算與模板對應的圖像上的位置
						int x=j-(int)tWH/2+m;
						int y=i;//-(int)tWH/2+m;
						
						//如果模板數據沒有超過邊界
						if(x>=0&&x<width){
							sum=sum+source[y][x]*template[m];
						}
				}
				
				for(int m=0;m<tWH;m++){
					///計算與模板對應的圖像上的位置
					int x=j;
					int y=i-(int)tWH/2+m;//-(int)tWH/2+m;
					
					//如果模板數據沒有超過邊界
					if(y>=0&&y<height){
						sum=sum+source[y][x]*template[m];
					}
				}
				result[i][j]=sum/2;
				
			}
		}
		int i=0;
		i++;
		return result;
	}

效果爲(左邊是原圖):


2、種子區域選取:

首先,獲取梯度圖像:高斯濾波圖像使用sobel算子求取梯度圖像。

然後,種子區域獲取以及標記:梯度圖像中,將梯度值小於預先設置的閾值THRESHOLD的像素點的灰度值設置爲0,而其他像素點的灰度值等於其梯度值。這樣每個像素都標記之後就開始進行區域增長,採用同一區域屬於一個並查集的方法,將灰度值爲0的區域進行分類標記(這些信息存儲在blockData裏)。如圖,每一個黑色塊屬於一個類(也就是一個種子區域)。



3、浸水過程(也就是區域生長過程):

參照周洋告訴我的方法:三層循環,第一層是梯度值從閾值到最大值,裏面兩層是二維圖像數據的遍歷。採用八領域的判斷方法,如果某個未被標記爲0(未知)的點周圍只有一個被標記爲零的點(種子),則該點歸併到該種子區域中,如果有兩個以上被標記的點,並且屬於不同的區域,那麼該點標記爲山脊(輪廓線)。對於外層循環的每一個梯度值,區域生長的停止條件:沒有新的點被併入到某個區域。這樣其實就有四層循環,因爲需要一層來判斷是否有新點被併入到種子區域。

效果圖如下:


可以看出,分水嶺算法的好處在於可以得到一個個封閉區域,這個一般的二值化的輪廓圖像是得不到的。

另外,經過對比發現,高斯濾波對減少過分割有着比較理想的作用,但是也不能消除過分割,因此需要有第四步——區域合併。這部分在後續博文中我會繼續講。

因爲還未寫完,所以代碼可能顯得比較亂,比如程序中有個map成員變量,實際沒多大意義,但考慮到測試用,還望見諒!

附上第一版程序的源碼:http://download.csdn.net/detail/abcd_d_/8169869






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章