*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 ; us