应用sobel算子算法c语言,Canny算子与Sobel算子求图像边缘的C代码实现

*Canny算子与Sobel算子求图像边缘笔记*

1、Canny求边缘算法原理简述

Canny检测边缘主要分为以下 四个算法步骤:

A:噪声去除

canny算子是通过对每个像素点求一阶导数来找到梯度明显的边缘,对图像中的噪声很敏感。所以用Canny算子对图像求导前,先用高斯滤波核函数对图像灰度矩阵的每一点进行加权求平均,以平滑图像去除噪声。这里采用

的高斯核对图像进行卷积实现高斯滤波。

B:求图像梯度

利用如下图的Canny算子对图像求X,Y方向梯度(数学意义上的X,Y方向的偏导),然后综合X,Y方向梯度计算该点的梯度,及梯度与X轴的夹角。

上图是算子,下图是梯度计算公式:

C:极大值抑制(代码中未实现)

其实就是找出局部的极大值,将非极大值设为0。

D: 双阈值提取与边缘连接

采用一大一小阈值对梯度图像进行过滤,摄取出两幅边缘图像, 一个边缘噪声少,但有可能损失部分边缘,一个边缘噪声多,但边缘比前者充分。再通过类似求联通区域的方法连接两图像,得到边缘。

C代码实现如下

(这只是一个很粗陋的代码实现,上班之余的小练习,如错误欢迎指正):

{

/*先高斯滤波*/

/*求对应像素点四个方向的梯度幅值与方向*/

/*非极大值抑制*/

/*双阀值边缘连接*/

S16 asGaussFilter[E_3x3_KERNEL][E_3x3_KERNEL] = {{1, 2, 1},

{2, 4, 2},

{1, 2, 1}};

U8 *pucGaussBuf = pucTmpBuf;

PU16 pusCnyGrdBuf = (PU16)(pucGaussBuf + usImgStep*usImgHgt*sizeof(U8)); /*梯度大小*/

PU16 pusCnyCnrBuf = (PU16)(pusCnyGrdBuf + usImgStep*usImgHgt*sizeof(U8)); /*梯度角度*/

U8 *pucCnyGrdBuf3 = (PU8)(pusCnyCnrBuf) + usImgStep*usImgHgt*sizeof(U16);

U8 *pucCnyGrdBuf4 = pucCnyGrdBuf3 + usImgStep*usImgHgt*sizeof(U8);

U16 *pusCnyStkPosY = (U16 *)(pucCnyGrdBuf4 + usImgStep * usImgHgt * sizeof(U8));

U16 *pusCnyStkPosX = pusCnyStkPosY + usImgStep * usImgHgt;

U16 usKnlWth = E_3x3_KERNEL;

U16 usKnlHgt = E_3x3_KERNEL;

S16 sThreshCny1 = 20;

S16 sThreshCny2 = 30;

U8 ucSrlNum = 1;

U32 uiStackCnt = 0;

/*高斯滤波*/

for ( usYIdx = 0 ; usYIdx < usImgHgt ; usYIdx++ )

{

for ( usXIdx = 0 ; usXIdx < usImgWth ; usXIdx++ )

{

uiXYIdx = (U32)(usYIdx * usImgStep + usXIdx);

if( 0 == usXIdx ||

0 == usYIdx ||

usImgWth - 1 == usXIdx ||

usImgHgt - 1 == usYIdx )

{

pucGaussBuf[uiXYIdx] = pucYImgIn[uiXYIdx];

}

else

{

U16 usGaussTmpVal = 0;

U8 *pucBuf = pucYImgIn + uiXYIdx - usImgStep - 1;

for ( usKYIdx = 0 ; usKYIdx < usKnlHgt ; usKYIdx++ )

{

for ( usKXIdx = 0 ; usKXIdx < usKnlWth ; usKXIdx++ )

{

usGaussTmpVal += (U16)(pucBuf[usKYIdx * usImgStep + usKXIdx]) * (U16)(asGaussFilter[usKYIdx][usKXIdx]);

}

}

pucGaussBuf[uiXYIdx] = ((usGaussTmpVal >> 4) > 255) ? (255) : (usGaussTmpVal >> 4);

}

}

}

memset(pucCnyGrdBuf3, 0, usImgStep*usImgHgt*sizeof(U8));

memset(pucCnyGrdBuf4, 0, usImgStep*usImgHgt*sizeof(U8));

/*Canny求梯度*/

for(usYIdx = 0; usYIdx < usImgHgt; usYIdx++)

{

for(usXIdx = 0; usXIdx < usImgWth; usXIdx++)

{

uiXYIdx = (U32)(usYIdx*usImgStep+usXIdx);

if(usImgWth - 1 == usXIdx || usImgHgt - 1 == usYIdx)

{

pusCnyGrdBuf[uiXYIdx] = 0;

pusCnyCnrBuf[uiXYIdx] = 0;

}

else

{

PU8 pucTisBuf = pucGaussBuf + uiXYIdx;

PU8 pucDwBuf = pucGaussBuf + uiXYIdx + usImgStep;

PU8 pucRgtBuf = pucGaussBuf + uiXYIdx + 1;

PU8 pucRgtDwBuf = pucGaussBuf + uiXYIdx + usImgStep + 1;

S32 iHorGrad = abs((int)(pucRgtBuf[0] +pucRgtDwBuf[0])-(int)(pucTisBuf[0]+pucDwBuf[0]))/2;

S32 iVerGrad = abs((int)(pucRgtDwBuf[0]+pucDwBuf[0]) -(int)(pucTisBuf[0]+pucRgtBuf[0]))/2;

FL fGrdCnr = atan2(iVerGrad, iHorGrad)*57.3;

pusCnyGrdBuf[uiXYIdx] = (U16)((S32)(sqrt((FL)(iHorGrad*iHorGrad)+(FL)(iVerGrad*iVerGrad))));

pusCnyCnrBuf[uiXYIdx] = (fGrdCnr < 0) ? (fGrdCnr+360.0) : (fGrdCnr);

if(pusCnyGrdBuf[uiXYIdx] > (U16)(sThreshCny2))

{

pucCnyGrdBuf3[uiXYIdx] = 255;

}

else if(pusCnyGrdBuf[uiXYIdx] > (U16)(sThreshCny1))

{

pucCnyGrdBuf4[uiXYIdx] = 255;

}

}

}

}

memset(pucYImgOut, 0, sizeof(U8)*usImgStep*usImgHgt);

/*边缘连接*/

for(usYIdx = 0; usYIdx < usImgHgt; usYIdx++ )

{

for(usXIdx = 0; usXIdx < usImgWth; usXIdx++)

{

uiXYIdx = (U32)(usYIdx * usImgStep + usXIdx);

if(0 == usXIdx ||

0 == usYIdx ||

usImgWth - 1 == usXIdx ||

usImgHgt - 1 == usYIdx )

{

/*不处理*/

}

else

{

if(255 == pucCnyGrdBuf3[uiXYIdx])

{

uiStackCnt = 0;

pusCnyStkPosY[uiStackCnt] = usYIdx;

pusCnyStkPosX[uiStackCnt] = usXIdx;

uiStackCnt += 1;

pucCnyGrdBuf3[uiXYIdx] = ucSrlNum;

while(0 != uiStackCnt)

{

U16 usYTmpIdx = 0;

U16 usXTmpIdx = 0;

U32 uiTmpXYIdx = 0;

U32 uiTmpIdx = 0;

uiStackCnt--;

usYTmpIdx = pusCnyStkPosY[uiStackCnt];

usXTmpIdx = pusCnyStkPosX[uiStackCnt];

uiTmpIdx = (U32)(usYTmpIdx * usImgStep + usXTmpIdx);

/*左上*/

uiTmpXYIdx = (U32)(uiTmpIdx - usImgStep - 1);

if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx - 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx - 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf3[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

else if(255 == pucCnyGrdBuf4[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx - 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx - 1;

pucCnyGrdBuf4[uiTmpXYIdx] = ucSrlNum;

pucYImgOut[uiTmpXYIdx] = 255;

uiStackCnt += 1;

}

/*左*/

uiTmpXYIdx = (U32)(uiTmpIdx - 1);

if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx - 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf3[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

else if( 255 == pucCnyGrdBuf4[uiTmpXYIdx] )

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx - 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf4[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

/*左下*/

uiTmpXYIdx = (U32)(uiTmpIdx + usImgStep - 1);

if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx + 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx - 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf3[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

else if(255 == pucCnyGrdBuf4[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx + 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx - 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf4[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

/*下*/

uiTmpXYIdx = (U32)(uiTmpIdx + usImgStep);

if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx + 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf3[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

else if(255 == pucCnyGrdBuf4[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx + 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf4[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

/*右下*/

uiTmpXYIdx = (U32)(uiTmpIdx + usImgStep + 1);

if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx + 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx + 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf3[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

else if(255 == pucCnyGrdBuf4[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx + 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx + 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf4[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

/*右*/

uiTmpXYIdx = (U32)(uiTmpIdx + 1);

if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx + 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf3[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

else if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx + 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf4[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

/*右上*/

uiTmpXYIdx = (U32)(uiTmpIdx - usImgStep + 1);

if(255 == pucCnyGrdBuf3[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx - 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx + 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf3[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

else if(255 == pucCnyGrdBuf4[uiTmpXYIdx])

{

pusCnyStkPosY[uiStackCnt] = usYTmpIdx - 1;

pusCnyStkPosX[uiStackCnt] = usXTmpIdx + 1;

pucYImgOut[uiTmpXYIdx] = 255;

pucCnyGrdBuf4[uiTmpXYIdx] = ucSrlNum;

uiStackCnt += 1;

}

}

}

}

}

}

}

实现效果如下:

应用sobel算子算法c语言,Canny算子与Sobel算子求图像边缘的C代码实现_第1张图片

2、Soble边缘检测算法:

算法的大致流程跟Canny类似,只是算子改成:

1965b556a8d8fe16052585f8ed66340f.png85fb6b585498d49cd914252be8791fde.png

分别对图像做卷积,求出每个点Y,X方向梯度,再求出综合的梯度及梯度方向。

感谢:

http://www.cnblogs.com/lancidie/archive/2011/07/17/2108885.html

http://blog.csdn.net/likezhaobin/article/details/6892176

你可能感兴趣的:(应用sobel算子算法c语言)