📄 segapi.cpp
字号:
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 + -