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

📄 segapi.cpp

📁 《Visual C++数字图像获取 处理及实践应用》一书的源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
		nWeight[1][1][2] =  0 ;   
		nWeight[1][2][0] = -1 ;   
		nWeight[1][2][1] = -1 ;   
		nWeight[1][2][2] = -1 ;   
		
		
		
		//这个变量用来表示Laplacian算子象素值
		int nTmp[3][3];
		
		// 临时变量
		double dGrad   ;
		double dGradOne;
		double dGradTwo;
		
		// 模板循环控制变量
		int yy ;
		int xx ;
		
		
		// 下面开始利用Prewitt算子进行计算,为了保证计算所需要的
		// 的数据位于图像数据的内部,下面的两重循环的条件是
		// y<nHeight-1 而不是y<nHeight,相应的x方向也是x<nWidth-1
		// 而不是x<nWidth
		for(y=1; y<nHeight-1 ; y++ )
			for(x=1 ; x<nWidth-1 ; x++ )
			{
				dGrad    = 0 ; 
				dGradOne = 0 ;
				dGradTwo = 0 ;
				// Laplacian算子需要的各点象素值
				
				// 模板第一行
				nTmp[0][0] = lpImage[(y-1)*nSaveWidth + x - 1 ] ; 
				nTmp[0][1] = lpImage[(y-1)*nSaveWidth + x     ] ; 
				nTmp[0][2] = lpImage[(y-1)*nSaveWidth + x + 1 ] ; 
				
				// 模板第二行
				nTmp[1][0] = lpImage[y*nSaveWidth + x - 1 ] ; 
				nTmp[1][1] = lpImage[y*nSaveWidth + x     ] ; 
				nTmp[1][2] = lpImage[y*nSaveWidth + x + 1 ] ; 
				
				// 模板第三行
				nTmp[2][0] = lpImage[(y+1)*nSaveWidth + x - 1 ] ; 
				nTmp[2][1] = lpImage[(y+1)*nSaveWidth + x     ] ; 
				nTmp[2][2] = lpImage[(y+1)*nSaveWidth + x + 1 ] ; 
				
				// 计算梯度
				for(yy=0; yy<3; yy++)
					for(xx=0; xx<3; xx++)
					{
						dGradOne += nTmp[yy][xx] * nWeight[0][yy][xx] ;
						dGradTwo += nTmp[yy][xx] * nWeight[1][yy][xx] ;
					}
					dGrad = dGradOne*dGradOne + dGradTwo*dGradTwo  ;
					dGrad = sqrt(dGrad) ;
					// 梯度值写入内存
					*(pdGrad+y*nWidth+x)=dGrad;
			}
}

/*************************************************************************
 *
 * \函数名称:
 *   EdgeTrack()
 *
 * \输入参数:
 *   CDib * pDib					- 指向CDib类的指针,含有原始图象信息
 *   unsigned char * pUnEdgeTrack	- 指向边界跟踪结果的指针
 *
 * \返回值:
 *   无
 *
 * \说明:
 *   pUnEdgeTrack指针指向的数据区存储了边界跟踪的结果,其中1(逻辑)表示
 *	 对应象素为边界点,0表示为非边界点
 *
 *   串行边界分割
 *
 *************************************************************************
 */
void EdgeTrack(CDib * pDib, unsigned char * pUnEdgeTrack)
{
	static int nDx[8]={-1,-1,-1, 0, 0, 1, 1, 1};
	static int nDy[8]={-1, 0, 1,-1, 1,-1, 0, 1};

	// 遍历图象的纵坐标
	int y;

	// 遍历图象的横坐标
	int x;

	// 图象的长宽大小
	CSize sizeImage		= pDib->GetDimensions();
	int nWidth			= sizeImage.cx		;
	int nHeight			= sizeImage.cy		;
	
	// 指向梯度数据的指针
	double * pdGrad;

	// 按照图像的大小开辟内存空间,存储梯度计算的结果
	pdGrad=new double[nHeight*nWidth];

    // 调用Roberts算子求梯度
	RobertsOperator(pDib, pdGrad);

	// 定义当前象素梯度值
	double dCurrGrad = 0;
	
	// 定义最大梯度值
	double dMaxGrad;

	// 设置初值
	dMaxGrad = 0;

	// 最大梯度值对应的象素点坐标
	int nPx;
	int nPy;

	nPx = 0;
	nPy = 0;

	// 求梯度最大值所在的象素点坐标
	for(y=0; y<nHeight; y++)
	{
		for(x=0; x<nWidth; x++)
		{
			dCurrGrad = pdGrad[y*nWidth + x] ;
			if( dMaxGrad< dCurrGrad )
			{
				dMaxGrad = dCurrGrad;
				nPx = x ;
				nPy = y ; 
			}
		}
	}

	// 初始化
	memset(pUnEdgeTrack,0,sizeof(unsigned char)*nWidth*nHeight);
	dCurrGrad = pdGrad[nPy*nWidth + nPx] ;

	// 从(nPx,nPy)点开始进行边界跟踪
	pUnEdgeTrack[nPy*nWidth + nPx] = 255 ;

	// 循环变量,遍历当前象素的8邻域
	int i ;

	int yy;
	int xx;
	
	int nDetX;
	int nDetY;

	while(dCurrGrad>10)
	{
		// 设置当前点为边界点
		pUnEdgeTrack[nPy*nWidth + nPx] = 255 ;

		dMaxGrad = 0 ;
		for(i=0; i<8; i++)
		{
			nDetX=nDx[i];
			nDetY=nDy[i];
			y = nPy + nDetY;
			x = nPx + nDetX;

			// 判断是否在图像内部
			if(x>=0 && x<nWidth && y>=0 && y<nHeight)
			{
				if( ( pdGrad[y*nWidth + x] > dMaxGrad)  && ( pUnEdgeTrack[y*nWidth + x] == 0) )
				{
					dMaxGrad = pdGrad[y*nWidth + x] ;
					yy = y;
					xx = x;
				}
			}
		}
		// 下一个边界点的梯度,横纵坐标
		dCurrGrad = dMaxGrad ;
		nPy = yy;
		nPx = xx;
	}

	//释放内存
	delete pdGrad;
	pdGrad = NULL;

}

/*************************************************************************
 *
 * \函数名称:
 *   MakeGauss()
 *
 * \输入参数:
 *   double sigma									        - 高斯函数的标准差
 *   double **pdKernel										- 指向高斯数据数组的指针
 *   int *pnWindowSize										- 数据的长度
 *
 * \返回值:
 *   无
 *
 * \说明:
 *   这个函数可以生成一个一维的高斯函数的数字数据,理论上高斯数据的长度应
 *   该是无限长的,但是为了计算的简单和速度,实际的高斯数据只能是有限长的
 *   pnWindowSize就是数据长度
 *   
 *************************************************************************
 */
void MakeGauss(double sigma, double **pdKernel, int *pnWindowSize)
{
	// 循环控制变量
	int i   ;
	
	// 数组的中心点
	int nCenter;

	// 数组的某一点到中心点的距离
	double  dDis  ; 

	double PI = 3.14159;
	// 中间变量
	double  dValue; 
	double  dSum  ;
	dSum = 0 ; 
	
	// 数组长度,根据概率论的知识,选取[-3*sigma, 3*sigma]以内的数据。
	// 这些数据会覆盖绝大部分的滤波系数
	*pnWindowSize = 1 + 2 * ceil(3 * sigma);
	
	// 中心
	nCenter = (*pnWindowSize) / 2;
	
	// 分配内存
	*pdKernel = new double[*pnWindowSize] ;
	
	for(i=0; i< (*pnWindowSize); i++)
	{
		dDis = (double)(i - nCenter);
		dValue = exp(-(1/2)*dDis*dDis/(sigma*sigma)) / (sqrt(2 * PI) * sigma );
		(*pdKernel)[i] = dValue ;
		dSum += dValue;
	}
	
	// 归一化
	for(i=0; i<(*pnWindowSize) ; i++)
	{
		(*pdKernel)[i] /= dSum;
	}
}

/*************************************************************************
 *
 * \函数名称:
 *   GaussianSmooth()
 *
 * \输入参数:
 *   unsigned char * pUnchImg				- 指向图象数据的指针
 *   int nWidth											- 图象数据宽度
 *   int nHeight										- 图象数据高度
 *   double dSigma									- 高斯函数的标准差
 *   unsigned char * pUnchSmthdImg	- 指向经过平滑之后的图象数据
 *
 * \返回值:
 *   无
 *
 * \说明:
 *   为了抑止噪声,采用高斯滤波对图象进行滤波,滤波先对x方向进行,然后对
 *   y方向进行。
 *   
 *************************************************************************
 */
void GaussianSmooth(unsigned char *pUnchImg, int nWidth, int nHeight, 
										double sigma, unsigned char * pUnchSmthdImg)
{
	// 循环控制变量
  int y;
	int x;
	
	int i;
	
	// 高斯滤波器的数组长度
	
	int nWindowSize;
	
	//  窗口长度的1/2
	int	nHalfLen;   
	
	// 一维高斯数据滤波器
	double *pdKernel ;
	
	// 高斯系数与图象数据的点乘
	double  dDotMul     ;
	
	// 高斯滤波系数的总和
	double  dWeightSum     ;          
  
	// 中间变量
	double * pdTmp ;
	
	// 分配内存
	pdTmp = new double[nWidth*nHeight];
	
	// 产生一维高斯数据滤波器
	// MakeGauss(sigma, &dKernel, &nWindowSize);
	MakeGauss(sigma, &pdKernel, &nWindowSize) ;
	
	// MakeGauss返回窗口的长度,利用此变量计算窗口的半长
	nHalfLen = nWindowSize / 2;
	
  // x方向进行滤波
	for(y=0; y<nHeight; y++)
	{
		for(x=0; x<nWidth; x++)
		{
			dDotMul		= 0;
			dWeightSum = 0;
			for(i=(-nHalfLen); i<=nHalfLen; i++)
			{
				// 判断是否在图象内部
				if( (i+x) >= 0  && (i+x) < nWidth )
				{
					dDotMul += (double)pUnchImg[y*nWidth + (i+x)] * pdKernel[nHalfLen+i];
					dWeightSum += pdKernel[nHalfLen+i];
				}
			}
			pdTmp[y*nWidth + x] = dDotMul/dWeightSum ;
		}
	}
	
	// y方向进行滤波
	for(x=0; x<nWidth; x++)
	{
		for(y=0; y<nHeight; y++)
		{
			dDotMul		= 0;
			dWeightSum = 0;
			for(i=(-nHalfLen); i<=nHalfLen; i++)
			{
				// 判断是否在图象内部
				if( (i+y) >= 0  && (i+y) < nHeight )
				{
					dDotMul += (double)pdTmp[(y+i)*nWidth + x] * pdKernel[nHalfLen+i];
					dWeightSum += pdKernel[nHalfLen+i];
				}
			}
			pUnchSmthdImg[y*nWidth + x] = (unsigned char)(int)dDotMul/dWeightSum ;
		}
	}

	// 释放内存
	delete []pdKernel;
	pdKernel = NULL ;
	
	delete []pdTmp;
	pdTmp = NULL;
}


/*************************************************************************
 *
 * \函数名称:
 *   DirGrad()
 *
 * \输入参数:
 *   unsigned char *pUnchSmthdImg					- 经过高斯滤波后的图象
 *   int nWidht														- 图象宽度
 *   int nHeight      										- 图象高度
 *   int *pnGradX                         - x方向的方向导数
 *   int *pnGradY                         - y方向的方向导数
 * \返回值:
 *   无
 *
 * \说明:
 *   这个函数计算方向倒数,采用的微分算子是(-1 0 1) 和 (-1 0 1)'(转置)
 *   计算的时候对边界象素采用了特殊处理
 *   
 *   
 *************************************************************************
 */
void DirGrad(unsigned char *pUnchSmthdImg, int nWidth, int nHeight,
										 int *pnGradX , int *pnGradY)
{
	// 循环控制变量
	int y ;
	int x ;
	
	// 计算x方向的方向导数,在边界出进行了处理,防止要访问的象素出界
	for(y=0; y<nHeight; y++)
	{
		for(x=0; x<nWidth; x++)
		{
			pnGradX[y*nWidth+x] = (int) ( pUnchSmthdImg[y*nWidth+min(nWidth-1,x+1)]  
													          - pUnchSmthdImg[y*nWidth+max(0,x-1)]     );
		}
	}

	// 计算y方向的方向导数,在边界出进行了处理,防止要访问的象素出界
	for(x=0; x<nWidth; x++)
	{
		for(y=0; y<nHeight; y++)
		{
			pnGradY[y*nWidth+x] = (int) ( pUnchSmthdImg[min(nHeight-1,y+1)*nWidth + x]  
																		- pUnchSmthdImg[max(0,y-1)*nWidth+ x ]     );
		}
	}
}
/*************************************************************************
 *
 * \函数名称:
 *   GradMagnitude()
 *
 * \输入参数:
 *   int *pnGradX                         - x方向的方向导数
 *   int *pnGradY                         - y方向的方向导数
 *   int nWidht														- 图象宽度
 *   int nHeight      										- 图象高度
 *   int *pnMag                           - 梯度幅度   
 *
 * \返回值:
 *   无
 *
 * \说明:
 *   这个函数利用方向倒数计算梯度幅度,方向倒数是DirGrad函数计算的结果
 *   
 *************************************************************************
 */
void GradMagnitude(int *pnGradX, int *pnGradY, int nWidth, int nHeight, int *pnMag)
{
	
	// 循环控制变量
	int y ;
	int x ;

	// 中间变量
	double dSqtOne;
	double dSqtTwo;
	
	for(y=0; y<nHeight; y++)
	{
		for(x=0; x<nWidth; x++)
		{
			dSqtOne = pnGradX[y*nWidth + x] * pnGradX[y*nWidth + x];
			dSqtTwo = pnGradY[y*nWidth + x] * pnGradY[y*nWidth + x];
			pnMag[y*nWidth + x] = (int)(sqrt(dSqtOne + dSqtTwo) + 0.5);
		}
	}
}
/*************************************************************************
 *
 * \函数名称:
 *   NonmaxSuppress()
 *
 * \输入参数:
 *   int *pnMag                - 梯度图
 *   int *pnGradX							 - x方向的方向导数	
 *   int *pnGradY              - y方向的方向导数

⌨️ 快捷键说明

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