最近被圖像分割整的天昏地暗的,在此感謝老朋友周洋給我關於分水嶺算法的指點!本來打算等彩色圖像分割有個完滿的結果再寫這篇文章,但是考慮到到了這一步也算是一個階段,所以打算對圖像分割做一個系列的博文,於是先寫這篇。
囉嗦了這麼多!先看效果:
效果一般,存在着很多過分割現象,但比沒使用濾波之前的效果好很多,過分割是分水嶺算法的通病。這個後續博文會繼續解決。
本文用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