📄 watershed.cpp
字号:
#include "stdafx.h"
#include "Watershed.h"
#include <math.h>
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/***********************************************************************
* 函数名称:
* Watershed()
*
*说明:无参数的构造函数,对成员变量进行初始化
***********************************************************************/
Watershed::Watershed()
{
m_pImgDataOut=NULL;//输出图像位图数据指针为空
m_lpColorTableOut=NULL;//输出图像颜色表指针为空
m_nColorTableLengthOut=0;//输出图像颜色表长度为0
m_nBitCountOut=0;//输出图像每像素位数为0
m_imgWidthOut=0;//输出图像的宽为0
m_imgHeightOut=0;//输出图像的高为0
//队列缓冲区长度,没调用watershed前不申请队列缓冲区
queueLng=0;
objectCount=0;//分类目标数置0
}
/***********************************************************************
* 函数名称:
* Watershed()
*
*函数参数:
* CSize size -图像大小(宽、高)
* int nBitCount -每像素所占位数
* LPRGBQUAD lpColorTable -颜色表指针
* unsigned char *pImgData -位图数据指针
*
*返回值:
* 无
*
*说明:本函数为带参数的构造函数,给定位图的大小、每像素位数、颜色表
* 及位图数据,调用ImgCenterDib()对基类成员初始化,并初始化派生类的
* 数据成员
***********************************************************************/
Watershed::Watershed(CSize size, int nBitCount, LPRGBQUAD lpColorTable,
unsigned char *pImgData):
ImgCenterDib(size, nBitCount, lpColorTable, pImgData)
{
m_pImgDataOut=NULL;//输出图像位图数据指针为空
m_lpColorTableOut=NULL;//输出图像颜色表指针为空
m_nColorTableLengthOut=0;//输出图像颜色表长度为0
m_nBitCountOut=0;//输出图像每像素位数为0
m_imgWidthOut=0;//输出图像的宽为0
m_imgHeightOut=0;//输出图像的高为0
//队列缓冲区长度,没调用watershed前不申请队列缓冲区
queueLng=0;
objectCount=0;//分类目标数置0
}
/***********************************************************************
* 函数名称:
* ~Watershed()
*
*说明:析构函数,释放资源
***********************************************************************/
Watershed::~Watershed()
{
//释放输出图像及其颜色表缓冲区
if(m_pImgDataOut!=NULL){
delete []m_pImgDataOut;
m_pImgDataOut=NULL;
}
if(m_lpColorTableOut==NULL){
delete []m_lpColorTableOut;
m_lpColorTableOut=NULL;
}
//释放队列缓冲区
if(queueLng!=0){
//循环变量,数组下标
int i,j;
//清除队列缓冲区
for(i=0; i<256;i++){
for(j=0;j<4;j++){
delete []queue[i][j];
}
}
}
}
/***********************************************************************
* 函数名称:
* GetDimensions()
*
*函数参数:
* 无
*
*返回值:
* 图像的尺寸,用CSize类型表达
*
*说明:返回输出图像的宽和高
***********************************************************************/
CSize Watershed::GetDimensions()
{
if(m_pImgDataOut == NULL) return CSize(0, 0);
return CSize(m_imgWidthOut, m_imgHeightOut);
}
/***********************************************************************
* 函数名称:
* Pop()
*
*函数参数:
* int gradient -出队元素的灰度值,gradient行的队列
* int mark -出队元素的标记,mark列的队列
* CPoint* pPopPoint -出队元素的坐标指针
*
*返回值:
* 无
*
*说明:一共有256*4个队列,队列中每一个元素是一个CPoint类型的量,用来存放
* 图像像素的坐标,该函数使第gradient行mark列的队列出队一个元素,元素坐标
* 在指针pPopPoint中返回
***********************************************************************/
void Watershed::Pop(int gradient,int mark,CPoint* pPopPoint)
{
//第gradient灰度级标记为mark的队列的队头
int top=headPointer[gradient][mark];
//第gradient灰度级标记为mark的队列的队头出队
pPopPoint->x=(queue[gradient][mark]+top)->x;
pPopPoint->y=(queue[gradient][mark]+top)->y;
//第gradient灰度级标记为mark的队列的队尾
int tail=tailPointer[gradient][mark];
//如果队头指针和队尾相遇,则队列空
if(top==tail){
headPointer[gradient][mark]=0;
tailPointer[gradient][mark]=-1;
}
else{//否则,队头指针累加
headPointer[gradient][mark] += 1;
//循环队列,每次进队要作求模处理
headPointer[gradient][mark] = headPointer[gradient][mark]%queueLng;
}
}
/***********************************************************************
* 函数名称:
* Push()
*
*函数参数:
* int gradient -进队元素的灰度值,gradient行的队列
* int mark -进队元素的标记,mark列的队列
* CPoint pushPoint -进队元素的坐标
*
*返回值:
* 无
*
*说明:一共有256*4个队列,队列中每一个元素是一个CPoint类型的量,用来存放
* 图像像素的坐标,该函数使第gradient行mark列的队列进队一个元素,元素坐标
* 为pushPoint的值
***********************************************************************/
void Watershed::Push(int gradient,int mark,CPoint pushPoint)
{
//队尾指针加1
tailPointer[gradient][mark] +=1;
//对该队列求模处理
tailPointer[gradient][mark]=tailPointer[gradient][mark]%queueLng;
//中间变量,队尾指针
int tail=tailPointer[gradient][mark];
//新元素进队
(queue[gradient][mark]+tail)->x=pushPoint.x;
(queue[gradient][mark]+tail)->y=pushPoint.y;
}
/***********************************************************************
* 函数名称:
* IsEmpty()
*
*函数参数:
* int gradient -gradient行的队列
* int mark -mark列的队列
*
*返回值:
* 1代表真,0代表假
*
*说明:判断第gradient行mark列的队列是否为空,若返回值为1则队列空,否则不空
***********************************************************************/
bool Watershed::IsEmpty(int gradient,int mark)
{
if(tailPointer[gradient][mark]==-1)
return true;
else return false;
}
/***********************************************************************
* 函数名称:
* IsOverflow()
*
*函数参数:
* int gradient -gradient行的队列
* int mark -mark列的队列
*
*返回值:
* 1代表真,0代表假
*
*说明:判断第gradient行mark列的队列是否满,若返回值为1则队列满,否则不满
***********************************************************************/
bool Watershed::IsOverflow(int gradient,int mark)
{
//队头指针
int head=headPointer[gradient][mark];
//队尾元素指针加1
int tail=(tailPointer[gradient][mark]+1)%queueLng;
if(tailPointer[gradient][mark]!=-1 && tail==head)
return true;
else return false;
}
/***********************************************************************
* 函数名称:
* InitQueue()
*
*函数参数:
* unsigned char* pGradient -图像的梯度图
* unsigned char* pMarker -图像的标记图
* int width -图像的宽
* int height -图像的高
*
*返回值:
* 无
*
*说明:给定梯度图和标记图,对队列进行初始化
***********************************************************************/
void Watershed::InitQueue(unsigned char* pGradient, unsigned char* pMarker,
int width,int height)
{
//每行像素字节数
int linebyte=(width+3)/4*4;
//循环变量
int i,j,k;
//二维数组direct代表8邻域坐标与中心像素点在x和y方向上的偏移,
//其中第一列为x方向的偏移,第二列为y方向的偏移
int direct[8][2]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
//中间变量,灰度值和标记
int gradient, mark;
//要进队的元素
CPoint pushPoint;
//初始化队头和队尾指针
for(i=0;i<256;i++){
for(j=0;j<=objectCount;j++){
tailPointer[i][j]=-1;
headPointer[i][j]=0;
}
}
//当前处理像素的邻域点
CPoint neighborPoint;
for(i=0;i<height;i++){//图像边缘不处理
for(j=0;j<width;j++){
mark=pMarker[i*linebyte+j];
if(mark!=0){//找到一个标记点
for(k=0;k<8;k++){
neighborPoint.x=j+direct[k][0];
neighborPoint.y=i+direct[k][1];
//不在图像范围内的点,跳过
if(neighborPoint.x<0||neighborPoint.x>width-1
||neighborPoint.y<0||neighborPoint.y>height-1)
continue;
//该标记点是该区域的边缘点,则进队
if(*(pMarker+ neighborPoint.y*linebyte+neighborPoint.x)==0||
*(pMarker+ neighborPoint.y*linebyte+neighborPoint.x)!=mark){
gradient=*(pGradient+ i*linebyte+j);
if(IsOverflow(gradient,mark)){
CString str;
str.Format("%d",gradient);
CString str1="第"+ str + "个队溢出!";
::MessageBox(0,str1,MB_OK,0);
return;
}
else {
pushPoint.x=j;
pushPoint.y=i;
Push(gradient,mark,pushPoint);
}
break;
}
}
}//if end
}//for(j) end
}//for(i) end
}
/***********************************************************************
* 函数名称:
* WatershedTrans()
*
*函数参数:
* unsigned char* pGradient -图像的梯度图
* unsigned char* pMarker -图像的标记图
* int width -图像的宽
* int height -图像的高
* bool flag_contour -标志变量,1代表在不同类目标间加上分水岭线(叠坝),0代表不加
*
*返回值:
* 无
*
*说明:给定梯度图和标记图,对图像进行水域生长,生长结果存入标记图pMarker中
***********************************************************************/
void Watershed::WatershedTrans(unsigned char* pGradient, unsigned char* pMarker,
int width,int height,bool flag_contour)
{
//每行像素字节数
int linebyte=(width+3)/4*4;
//循环变量,图像的坐标
int i,j;
//二维数组direct代表8邻域坐标与中心像素点在x和y方向上的偏移,
//其中第一列为x方向的偏移,第二列为y方向的偏移
int direct[8][2]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
// 循环变量,direct数组8邻域下标(第1维)
int k;
//进队点、出队点和当前处理像素的邻域点
CPoint pushPoint,popPoint, neighborPoint;
//标志变量,1代表当前像素点是目标的轮廓点,否则不是
bool contourFlg;
//标志变量,1代表当前像素点是所处生长区域的边缘但不一定是所在目标的轮廓,
//否则不是
bool edgeFlg;
//初始化队列
InitQueue(pGradient,pMarker,width,height);
//像素的灰度值和标记
int gradient, mark;
//记录当前找到的要进队的点灰值
int minGradient;
//水域生长
for(i=0;i<256;i++){
for(j=0;j<objectCount+1;j++){
while(!IsEmpty(i,j)){
//出队一个元素
Pop(i,j,&popPoint);
minGradient=256;
pushPoint.x=-1;
pushPoint.y=-1;
for(k=0;k<8;k++){
neighborPoint.x=popPoint.x+direct[k][0];
neighborPoint.y=popPoint.y+direct[k][1];
//邻域点不在图像内,则跳过
if(neighborPoint.y<0||neighborPoint.y>height-1
||neighborPoint.x<0||neighborPoint.x>width-1)
continue;
mark=*(pMarker+neighborPoint.y*linebyte+neighborPoint.x);
if(mark==0){
gradient=*(pGradient+neighborPoint.y*linebyte+neighborPoint.x);
if(gradient<minGradient){
minGradient=gradient;
pushPoint.x=neighborPoint.x;
pushPoint.y=neighborPoint.y;
}
}
} //for(k) end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -