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

📄 watershed.cpp

📁 将数字图像处理的一般算法都集中在一个MFC的框架中
💻 CPP
📖 第 1 页 / 共 2 页
字号:
				//处理待进队的新点
				if(pushPoint.x!=-1&&pushPoint.y!=-1){
					*(pMarker+pushPoint.y*linebyte+pushPoint.x)=j;
					edgeFlg=0;
					contourFlg=0;

					//判断该新点是否边缘点或轮廓点
					for(k=0;k<8;k++){
						neighborPoint.x=pushPoint.x+direct[k][0];
						neighborPoint.y=pushPoint.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  ){
							edgeFlg=1;							
						}	
						if(  mark!=j && mark!=objectCount+1 &&mark!=0){
							contourFlg=1;
						}
					}
					if(flag_contour){//不同类间加分水岭线的标志(叠坝)
						if(contourFlg) 
							*(pMarker+pushPoint.y*width+pushPoint.x)=objectCount+1;
					}
					if(edgeFlg){										
						if(minGradient<i){
							if(IsOverflow(i,j)){
								CString str;
								str.Format("%d",minGradient);
								CString str1="第"+ str + "个队溢出!";
								::MessageBox(0,str1,MB_OK,0);
								return;
							}
							
							Push(i,j,pushPoint);
						}					
						else{
							if(IsOverflow(minGradient,j)){
								CString str;
								str.Format("%d",minGradient);
								CString str1="第"+ str + "个队溢出!";
								::MessageBox(0,str1,MB_OK,0);
								return;
							}
							Push(minGradient,j,pushPoint);
							
						}	
					}
				}

				//处理刚才出队的点,若该点仍然是边缘点,则重新进队
				edgeFlg=0;
				contourFlg=0;

				//判断被弹出点是否边缘点且非轮廓
				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  ){
						edgeFlg=1;
					}
					if(  mark!=j && mark!=objectCount+1 &&mark!=0){
						contourFlg=1;
					}
				}				
				
				if(flag_contour){//不同类间加分水岭线的标志(叠坝)
					if(contourFlg) //轮廓线标志
						*(pMarker+popPoint.y*linebyte+popPoint.x)=objectCount+1;						
				}
				if(edgeFlg){				
					if(IsOverflow(i,j)){
						CString str;
						str.Format("%d",minGradient);
						CString str1="第"+ str + "个队溢出!";
						::MessageBox(0,str1,MB_OK,0);
						return;
					}
					Push(i,j,popPoint);
				}
				
				
			}//while end
			
		}// for(j) end

	}//for(i) end

}

/***********************************************************************
* 函数名称:
* GenerateMarkerByPos()
*
*函数参数:
*  unsigned char* pMarker  -图像的标记图
*  int width  -图像的宽
*  int height  -图像的高
*  CPoint position[]   -指定种子点数组
*  int objectCount   -分类数
*
*返回值:
*   无
*
*说明:给定种子点数组position及分类数objectCount,产生标记图pMarker
***********************************************************************/
void Watershed::GenerateMarkerByPos(unsigned char* pMarker, int width,
							int height, CPoint position[], int objectCount)
{
	//每行像素字节数
	int linebyte=(width+3)/4*4;

	//初始化标记图置0,0代表未作标记的点(等待生长的点)
	memset(pMarker, 0, linebyte*height);

	//循环变量
	int k;
	//将第k个指定点置成标记k,
	for(k=0;k<objectCount;k++){
		*(pMarker+position[k].y*linebyte+position[k].x)=k+1;
	}
}

/***********************************************************************
* 函数名称:
* Sobel()
*
*函数参数:
*  unsigned char* imgBuf  -图像数据
*  int width  -图像的宽
*  int height  -图像的高
*  unsigned char *gradient  -梯度图
*
*返回值:
*   无
*
*说明:给定图像数据,进行sobel变换,得到的梯度图存入gradient缓冲区,此处
*      没有调用前面ImgSegment类中的Sobel(),是为了Watershed类的集成性,便
*      于代码移植
***********************************************************************/
void Watershed::Sobel(unsigned char *imgBuf, int width, int height,
					  unsigned char *gradient)
{
	//每行像素字节数
	int linebyte=(width+3)/4*4;

	//梯度图像缓冲区初始化置0。
	memset(gradient, 0, linebyte*height);

	//循环变量,图像的坐标
	int i, j;

	//中间变量
	int x, y, t;

	for(i=1;i<height-1; i++){
		for(j=1; j<width-1; j++){
			//x方向梯度
			x=*(imgBuf+(i+1)*linebyte+j-1)+2**(imgBuf+(i+1)*linebyte+j)
				+*(imgBuf+(i+1)*linebyte+j+1) -*(imgBuf+(i-1)*linebyte+j-1)
				-2**(imgBuf+(i-1)*linebyte+j)-*(imgBuf+(i-1)*linebyte+j+1);

			//y方向梯度
			y=*(imgBuf+(i+1)*linebyte+j-1)+2**(imgBuf+i*linebyte+j-1)
				+*(imgBuf+(i-1)*linebyte+j)-*(imgBuf+(i+1)*linebyte+j+1)
				-2**(imgBuf+i*linebyte+j+1)-*(imgBuf+(i-1)*linebyte+j+1);

			//梯度
			t=sqrt(x*x+y*y);
			if(t>255) t=255;
			*(gradient+i*linebyte+j)=t;
		}
	}
}

/***********************************************************************
* 函数名称:
* WatershedSegment()
*
*函数参数:
*  CPoint position[]  -种子点数组
*  int classCount  -分类数
*  int contourFlg  -标志性变量,1为叠坝(加轮廓线),0为不叠坝(不加轮廓线)
*
*返回值:
*   无
*
*说明:给定种子点及分类数,对输入图像进行水域分割函数
***********************************************************************/
void Watershed::WatershedSegment(CPoint position[], int classCount, int contourFlg)
{
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像为标记图像的输出,此处为灰度类型
	m_nBitCountOut=m_nBitCount;
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,
              sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;
	int lineByte=(m_imgWidth*m_nBitCountOut/8+3)/4*4;
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];


	//queueLng表示队列的长度,为节省空间,其值为图像像素总数的1/16,实际处理中队
	//列最长还可能远远小于本程序设定的值,或者采用指针方式实现队列更为合理 
	queueLng=m_imgWidth*m_imgHeight/16;

	//标记数
	objectCount=classCount;

	//循环变量
	int i, j;

	//申请队列缓冲区
	for(i=0;i<256;i++){
		for(j=0;j<4;j++)
    		queue[i][j]=new CPoint[queueLng];

	}

	//通过指定点参数产生标记,此时m_pImgDataOut内是初始标记图
	GenerateMarkerByPos(m_pImgDataOut, m_imgWidth, m_imgHeight, 
		position, objectCount);


	//申请缓冲区,存放sobel变换梯度图
	unsigned char *sobelBuf=new unsigned char[lineByte*m_imgHeight];
	Sobel(m_pImgData, m_imgWidth, m_imgHeight, sobelBuf);

	//水域变换,变换后m_pImgDataOut内存放的是水域生长以后的标记图,即分割结果
	WatershedTrans(sobelBuf, m_pImgDataOut, m_imgWidth, m_imgHeight,contourFlg);

	//标记图按一定比例显示
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			if(*(m_pImgDataOut+i*lineByte+j)==objectCount+1)
				*(m_pImgDataOut+i*lineByte+j)=255;
				else
	     		*(m_pImgDataOut+i*lineByte+j)= 
				(*(m_pImgDataOut+i*lineByte+j)-1)*255/objectCount;
		}
	}

	//清除梯度图缓冲区
	delete []sobelBuf;

	//清除队列缓冲区
	if(queueLng!=0){
		for(i=0;i<256;i++){
			for(j=0;j<4;j++){
				//释放队列缓冲区
				delete []queue[i][j];
			}
			
		}
		queueLng=0;
	}
}



/*
//用直方图方法生成标记图,threshInterval阈值段数组
void Watershed::calculateMarker(unsigned char* pImgBuf, unsigned char* pMarker, int width,int height, int threshInterval[], int objectCount)
{
	//每行像素字节数
	int linebyte=(width+3)/4*4;

	//初始化标记图置0,0代表未作标记的点(等待生长的点)
	memset(pMarker, 0, linebyte*height);
	
	//循环变量
	int i,j,k;
	unsigned char t;
	for(i=0;i<height;i++){
		for(j=0;j<width;j++){
			for(k=0;k<objectCount;k++){
				//坐标为(i,j)像素的指针
				t=*(pImgBuf+i*linebyte+j);
				if(t>=threshInterval[k*2+0]  &&  t<threshInterval[k*2+1])//第k类目标灰度区间
					*(pMarker+i*linebyte+j)=k+1;
			}
		}
	}
	
}

void Watershed::WatershedSegment1(int threshInterval[], int classCount, int contourFlg)
{
	if(classCount<2||classCount>3){
		::MessageBox(0,"分类数只能是2或3",MB_OK,0);
		return;
	}
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像为标记图象的输出,此处为灰度类型
	m_nBitCountOut=8;
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		for(int i=0; i<m_nColorTableLengthOut;i++){
			m_lpColorTableOut[i].rgbBlue=i;
			m_lpColorTableOut[i].rgbGreen=i;
			m_lpColorTableOut[i].rgbRed=i;
			m_lpColorTableOut[i].rgbReserved=0;
		}
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;
	int lineByte=(m_imgWidth*m_nBitCountOut/8+3)/4*4;
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

	//进队的像素是每个区域的边缘像素,边缘像素的数目要小于区域的像素数
	//而图像又被分成classCount个目标类,因此每个队列的最长远小于图像像素的总数
	//maxQueueBufLng用来作为申请队列缓冲区大小的依据,为节省空间,此处maxQueueBufLng的值为图像像素总数除以16
	//实际处理中队列最长还可能远远小于本程序设定的值
	maxQueueBufLng=m_imgWidth*m_imgHeight/16;

	//标记数
	objectCount=classCount;
	//循环变量
	int i, j;

	//申请队列缓冲区
	for(i=0;i<256;i++){
		for(j=0;j<4;j++)
    		queue[i][j]=new CPoint[maxQueueBufLng];

	}

	//通过指定点参数产生标记图,此时m_pImgDataOut是初始标记图
    calculateMarker(m_pImgData, m_pImgDataOut, m_imgWidth, m_imgHeight, threshInterval, objectCount);

	//申请缓冲区,存放梯度图
	unsigned char *sobelBuf=new unsigned char[lineByte*m_imgHeight];

	//计算sobel梯度图
	sobel(m_pImgData, m_imgWidth, m_imgHeight, sobelBuf);

	//水域变换
	waterShed(sobelBuf, m_pImgDataOut, m_imgWidth, m_imgHeight,contourFlg);
	//显示
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			if(*(m_pImgDataOut+i*lineByte+j)==objectCount+1)
				*(m_pImgDataOut+i*lineByte+j)=255;
				else
	     		*(m_pImgDataOut+i*lineByte+j)= 
				(*(m_pImgDataOut+i*lineByte+j)-1)*255/objectCount;
		}
	}
	
	

	//清除梯度缓冲区
	delete []sobelBuf;


	//清除队列缓冲区
	if(maxQueueBufLng!=0){
		for(i=0;i<256;i++){
			for(j=0;j<4;j++){
			//申请队列缓冲区
			delete []queue[i][j];
			}
			
		}
		maxQueueBufLng=0;
	}
}

  
	*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -