Canny是图像处理中经常用到的一种边缘检测算法,Canny的具体算法流程:
(1)根据sobel后的结果,通过幅值和角度进行非极大值抑制
(2)对非极大值抑制后的结果进行双阈值处理
(3)双阈值后的图像,进行边缘连接,得到连续性较好的边缘信息
更加具体的理论可以参考:点击打开链接,本文主要是参考opencv源码实现的Canny,具体代码如下:
void canny(image_uchar_ptr image, image_grad_ptr gradImg, image_uchar_ptr cannyImg, UCHAR **stack,int low, int high, int w, int h)
{
sobel_grad_direction(image, gradImg,w,h);
UINT *gmag_ptr = gradImg->gmag + w;
INT *gx_ptr = gradImg->g_x + w;
INT *gy_ptr = gradImg->g_y + w;
UCHAR *canny_ptr = cannyImg->data + w;
UCHAR **stack_top = &stack[0];
UCHAR **stack_bottom = &stack[0];
#define _PUSHKK(d) *(d) = (UCHAR)(2), *stack_top++ = (d)
#define _POPKK(d) (d) = *--stack_top
int y = 0, x = 0,yy = 0,xx = 0;
for (int i = 1; i < h - 1; i++)
{
gmag_ptr[0] = 0;
gmag_ptr[w - 1] = 0;
canny_ptr[0] = 1;
canny_ptr[w - 1] = 1;
int prev_flag = 0;
for (int j = 1; j < w - 1; j++)
{
int m = gmag_ptr[j];
if (m > low)
{
int xs = gx_ptr[j];
int ys = -gy_ptr[j];
int x0 = abs(xs);
int y0 = abs(ys) << CANNY_SHIFT;
int tg22x = x0 * TG22;
if (y0 < tg22x)
{
if (m > gmag_ptr[j - 1] && m >= gmag_ptr[j + 1])
{
goto __ocv_canny_push;
}
}
else
{
int tg67x = tg22x + (x0 << (CANNY_SHIFT + 1));
if (y0 > tg67x)
{
if (m > (gmag_ptr - w)[j] && m >= (gmag_ptr + w)[j])
{
goto __ocv_canny_push;
}
}
else
{
int s = (xs ^ ys) < 0 ? -1 : 1;
if (m > (gmag_ptr - w)[j - s] && m > (gmag_ptr + w)[j + s])
{
goto __ocv_canny_push;
}
}
}
}
prev_flag = 0;
canny_ptr[j] = (UCHAR)(1);
continue;
__ocv_canny_push:
if (!prev_flag && m > high && (canny_ptr - w)[j] != 2)
{
_PUSHKK(canny_ptr + j);
prev_flag = 1;
}
else
canny_ptr[j] = 0;
}
gmag_ptr += w;
gx_ptr += w;
gy_ptr += w;
canny_ptr += w;
}
while (stack_top > stack_bottom)
{
uchar *m;
_POPKK(m);
if (!m[-1]) _PUSHKK(m - 1);
if (!m[1]) _PUSHKK(m + 1);
if (!m[-w - 1]) _PUSHKK(m - w - 1);
if (!m[-w]) _PUSHKK(m - w);
if (!m[-w + 1]) _PUSHKK(m - w + 1);
if (!m[w - 1]) _PUSHKK(m + w - 1);
if (!m[w]) _PUSHKK(m + w);
if (!m[w + 1]) _PUSHKK(m + w + 1);
}
canny_ptr = cannyImg->data + w;
for (int i = 1; i < h - 1; i++)
{
for (int j = 1; j < w - 1; j++)
{
canny_ptr[j] = 256 -(canny_ptr[j] >> 1);
}
canny_ptr += w;
}
}
若发现有不当之处,欢迎指正讨论,谢谢!