分水岭算法主要的分割目的在于找到图像的连通区域。利用梯度信息作为输入图像,会有一个矛盾点,如果对原始图像进行梯度计算时不作滤波平滑处理,很容易将 物体分割成多个物体,那是因为噪声的影响;而如果进行滤波处理,又容易造成将某些原本几个的物体合成一个物体。当然这里的物体主要还是指图像变化不大或者 说是灰度值相近的目标区域。
/******** 标记-分水岭算法对输入图像进行分割
输入参数:
OriginalImage - 输入图像(灰度图,0~255)
SeedImage - 标记图像(二值图像,0非标记,1标记)
LabelImage - 输出图像(1第一个分割区域;2第二个分割区域;3...)
row,col - 图像行列数目
返回值:
分割区域数目
*/
int Watershed(uchar **OriginalImage, uchar** SeedImage, uchar **LabelImage, int row, int col)
{
using namespace std;
int Num = 0; //标志区域号,从1开始
int i, j;
vector SeedCounts; //保存每个队列种子个数容器
queue que; //临时种子队列
vector* > qu; //保存所有标记区域种子队列的数组
int* array;
queue *uu; //指向种子队列的指针
POINT temp;
for (i = 0; i < row; i++)
for (j = 0; j < col; j++)
LabelImage[i][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[i][j] == 1 || SeedImage[i][j] == 255) //找到一个标记区域
{
Num++; //标志号加1
array = new int[256];
ZeroMemory(array, 256 * sizeof(int));
//
SeedCounts.push_back(array);
uu = new queue[256];
qu.push_back(uu);
temp.x = i;
temp.y = j;
que.push(temp);
LabelImage[i][j] = Num;
SeedImage[i][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]]++;
}
}
}
}
}
bool actives; //某一水位,所有标记种子生长完的标志
int WaterLevel;
//淹没过程开始,水位从零上升,水位对应灰度级,采用四联通法
for (WaterLevel = 1; WaterLevel < 255; WaterLevel++)
{
actives = true;
while (actives)
{
actives = false;
for (i = 0; i0)
{
SeedCounts[i][WaterLevel]--;
temp = qu[i][WaterLevel].front();
qu[i][WaterLevel].pop();
m = temp.x;
n = temp.y;
if (m > 0)
{
if (!LabelImage[m - 1][n])
{
temp.x = m - 1;
temp.y = n;
lImage[m - 1][n] = i + 1;
//上方点标记为已淹没区域。这个标记与扫描点区域号相同,一定在标号所在区域。
if (OriginalImage[m - 1][n] <= WaterLevel)
{
qu[i][WaterLevel].push(temp);
}
else
{
qu[i][OriginalImage[m - 1][n]].push(temp);
SeedCounts[i][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[i][WaterLevel].push(temp);
}
else
{
qu[i][OriginalImage[m + 1][n]].push(temp);
SeedCounts[i][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[i][WaterLevel].push(temp);
}
else
{
qu[i][OriginalImage[m][n + 1]].push(temp);
SeedCounts[i][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[i][WaterLevel].push(temp);
}
else
{
qu[i][OriginalImage[m][n - 1]].push(temp);
SeedCounts[i][OriginalImage[m][n - 1]]++;
}
}
}
}
SeedCounts[i][WaterLevel] = (int)qu[i][WaterLevel].size();
}
}
}
}
while (!qu.empty())
{
uu = qu.back();
delete[] uu;
qu.pop_back();
}
while (!SeedCounts.empty())
{
array = SeedCounts.back();
delete[] array;
SeedCounts.pop_back();
}
return Num;
}
int ROW = Img->height;
int COL = Img->width;
uchar **arrDist;
uchar **arrSeed;
uchar **arrLabel;
arrDist = (uchar **)malloc(ROW * sizeof(uchar*));
arrSeed = (uchar **)malloc(ROW * sizeof(uchar*));
arrLabel = (uchar **)malloc(ROW * sizeof(uchar*));
for (int i = 0; i < ROW; i++)
{
arrDist[i] = (uchar*)malloc(COL * sizeof(uchar));
for (int i = 0; i < ROW; i++)
{
memcpy(arrDist[i], imgMat.ptr(i), COL* sizeof(uchar));
for (int j = 0; j < COL; j++)
arrDist[i][j] = 255 - arrDist[i][j];
}
}
for (int i = 0; i< ROW; i++)
memcpy(arrSeed[i], imgMat2.ptr(i), COL* sizeof(uchar));
int num = Watershed(arrDist, arrSeed, arrLabel, ROW, COL);
http://www.360doc.com/content/10/0512/21/1217721_27287483.shtml#
http://blog.csdn.net/augusdi/article/details/9022509
http://blog.csdn.net/nagao_kagetora/article/details/5995925