⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 watershed.cpp

📁 将数字图像处理的一般算法都集中在一个MFC的框架中
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#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 + -