//Image Watershed Segmentation
//This is the implementation of the algorithm based on immersion model.
// ===========================================================================
// ===== Module: Watershed.cpp
// ===== -------------------------------------------------------------- ======
// ===== Version 01 Date: 04/21/2003
// ===== -------------------------------------------------------------- ======
// ===========================================================================
// ===== Written by [email protected]
// ===== e-mail: [email protected]
// ===========================================================================
// Permission to use, copy, or modify this software and its documentation
// for educational and research purposes only is hereby granted without
// fee, provided that this copyright notice appear on all copies and
// related documentation. For any other uses of this software, in original
// or modified form, including but not limited to distribution in whole
// or in part, specific prior permission must be obtained from
// the author(s).
//
// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL RUTGERS UNIVERSITY BE LIABLE FOR ANY SPECIAL,
// INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
// THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
// OR PERFORMANCE OF THIS SOFTWARE.
// ===========================================================================
#include <queue>
#include <vector>
#include <windows.h>
/*====================================================================
函數名 : Watershed
功能 : 用標記-分水嶺算法對輸入圖像進行分割
算法實現 : 無
輸入參數說明 : OriginalImage --輸入圖像(灰度圖,0~255)
SeedImage --標記圖像(二值圖,0-非標記,1-標記)
LabelImage --輸出圖像(1-第一個分割區域,2-第二個分割區域,...)
row --圖像行數
col --圖像列數
返回值說明 : 無
====================================================================*/
void Watershed(const int **OriginalImage, char** SeedImage, int **LabelImage, int row, int col)
{
using namespace std;
//標記區域標識號,從1開始
int Num=0;
int i,j;
//保存每個隊列種子個數的數組
vector<int*> SeedCounts;
//臨時種子隊列
queue<POINT> que;
//保存所有標記區域種子隊列的數組
vector<queue<POINT>* > qu;
int* array;
queue<POINT> *uu;
POINT temp;
for(i=0;i<row;i++)
for(j=0;j<col;j++)
LabelImage[j]=0;
int m,n,k=0;
int up,down,right,left,upleft,upright,downleft,downright;
//預處理,提取區分每個標記區域,並初始化每個標記的種子隊列
//種子是指標記區域邊緣的點,他們可以在水位上升時向外淹沒(或者說生長)
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
//如果找到一個標記區域
if(SeedImage[j]==1)
{
//區域的標識號加一
Num++;
//分配數組並初始化爲零
array=new int[256];
ZeroMemory(array,256*sizeof(int));
//
SeedCounts.push_back(array);
//分配本標記的優先隊列
uu=new queue<POINT>[256];
//加入到隊列數組中
qu.push_back(uu);
//當前點放入本標記區域的臨時種子隊列中
temp.x=i;
temp.y=j;
que.push(temp);
//當前點標記爲已處理
LabelImage[j]=Num;
SeedImage[j]=127;
//讓種子隊列中的種子進行生長直到所有的種子都生長完畢
while(!que.empty())
{
up=down=right=left=0;
upleft=upright=downleft=downright=0;
//隊列中取出一個種子
temp=que.front();
m=temp.x;
n=temp.y;
que.pop();
if(m>0)
{
//上方若爲可生長點則加爲新種子
if(SeedImage[m-1][n]==1)
{
temp.x=m-1;
temp.y=n;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m-1][n]=Num;
SeedImage[m-1][n]=127;
}else//否則上方爲不可生長
{
up=1;
}
}
if(m>0&&n>0)
{
if(SeedImage[m-1][n-1]==1)//左上方若爲可生長點則加爲新種子
{
temp.x=m-1;
temp.y=n-1;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m-1][n-1]=Num;
SeedImage[m-1][n-1]=127;
}else//否則左上方爲不可生長
{
upleft=1;
}
}
if(m<row-1)
{
if(SeedImage[m+1][n]==1)//下方若爲可生長點則加爲新種子
{
temp.x=m+1;
temp.y=n;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m+1][n]=Num;
SeedImage[m+1][n]=127;
}else//否則下方爲不可生長
{
down=1;
}
}
if(m<(row-1)&&n<(col-1))
{
if(SeedImage[m+1][n+1]==1)//下方若爲可生長點則加爲新種子
{
temp.x=m+1;
temp.y=n+1;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m+1][n+1]=Num;
SeedImage[m+1][n+1]=127;
}else//否則下方爲不可生長
{
downright=1;
}
}
if(n<col-1)
{
if(SeedImage[m][n+1]==1)//右方若爲可生長點則加爲新種子
{
temp.x=m;
temp.y=n+1;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m][n+1]=Num;
SeedImage[m][n+1]=127;
}else//否則右方爲不可生長
{
right=1;
}
}
if(m>0&&n<(col-1))
{
if(SeedImage[m-1][n+1]==1)//右上方若爲可生長點則加爲新種子
{
temp.x=m-1;
temp.y=n+1;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m-1][n+1]=Num;
SeedImage[m-1][n+1]=127;
}else//否則右上方爲不可生長
{
upright=1;
}
}
if(n>0)
{
if(SeedImage[m][n-1]==1)//左方若爲可生長點則加爲新種子
{
temp.x=m;
temp.y=n-1;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m][n-1]=Num;
SeedImage[m][n-1]=127;
}else//否則左方爲不可生長
{
left=1;
}
}
if(m<(row-1)&&n>0)
{
if(SeedImage[m+1][n-1]==1)//左下方若爲可生長點則加爲新種子
{
temp.x=m+1;
temp.y=n-1;
que.push(temp);
//新種子點標記爲已淹沒區域
LabelImage[m+1][n-1]=Num;
SeedImage[m+1][n-1]=127;
}else//否則左方爲不可生長
{
downleft=1;
}
}
//上下左右只要有一點不可生長,那麼本點爲初始種子隊列中的一個
if(up||down||right||left||
upleft||downleft||upright||downright)
{
temp.x=m;
temp.y=n;
qu[Num-1][OriginalImage[m][n]].push(temp);
SeedCounts[Num-1][OriginalImage[m][n]]++;
}
}//while結束
}
}
}
bool actives;//在某一水位處,所有標記的種子生長完的標誌
int WaterLevel;
//淹沒過程開始,水位從零開始上升
for(WaterLevel=0;WaterLevel<256;WaterLevel++)
{
actives=true;
while(actives)
{
actives=false;
//依次處理每個標記區域
for(i=0;i<Num;i++)
{
if(!qu[WaterLevel].empty())
{
actives=true;
while(SeedCounts[WaterLevel]>0)
{
SeedCounts[WaterLevel]--;
temp=qu[WaterLevel].front();
qu[WaterLevel].pop();
m = temp.x;
n = temp.y;//當前種子的座標
if(m>0)
{
if(!LabelImage[m-1][n])//上方若未處理
{
temp.x=m-1;
temp.y=n;
LabelImage[m-1][n]=i+1;//上方點標記爲已淹沒區域
if(OriginalImage[m-1][n]<=WaterLevel)//上方若爲可生長點則加入當前隊列
{
qu[WaterLevel].push(temp);
}
else//否則加入OriginalImage[m-1][n]級隊列
{
qu[OriginalImage[m-1][n]].push(temp);
SeedCounts[OriginalImage[m-1][n]]++;
}
}
}
if(m<row-1)
{
if(!LabelImage[m+1][n])//下方若未處理
{
temp.x=m+1;
temp.y=n;
LabelImage[m+1][n]=i+1;//下方點標記爲已淹沒區域
if(OriginalImage[m+1][n]<=WaterLevel)//下方若爲可生長點則加入當前隊列
{
qu[WaterLevel].push(temp);
}
else//否則加入OriginalImage[m+1][n]級隊列
{
qu[OriginalImage[m+1][n]].push(temp);
SeedCounts[OriginalImage[m+1][n]]++;
}
}
}
if(n<col-1)
{
if(!LabelImage[m][n+1])//右邊若未處理
{
temp.x=m;
temp.y=n+1;
LabelImage[m][n+1]=i+1;//右邊點標記爲已淹沒區域
if(OriginalImage[m][n+1]<=WaterLevel)//右邊若爲可生長點則加入當前隊列
{
qu[WaterLevel].push(temp);
}
else//否則加入OriginalImage[m][n+1]級隊列
{
qu[OriginalImage[m][n+1]].push(temp);
SeedCounts[OriginalImage[m][n+1]]++;
}
}
}
if(n>0)
{
if(!LabelImage[m][n-1])//左邊若未處理
{
temp.x=m;
temp.y=n-1;
LabelImage[m][n-1]=i+1;//左邊點標記爲已淹沒區域
if(OriginalImage[m][n-1]<=WaterLevel)//左邊若爲可生長點則加入當前隊列
{
qu[WaterLevel].push(temp);
}
else//否則加入OriginalImage[m][n-1]級隊列
{
qu[OriginalImage[m][n-1]].push(temp);
SeedCounts[OriginalImage[m][n-1]]++;
}
}
}
}//while循環結束
SeedCounts[WaterLevel]=qu[WaterLevel].size();
}//if結束
}//for循環結束
}//while循環結束
}//for循環結束
while(!qu.empty())
{
uu=qu.back();
delete[] uu;
qu.pop_back();
}
while(!SeedCounts.empty())
{
array=SeedCounts.back();
delete[] array;
SeedCounts.pop_back();
}
}