Canny算子子像素边缘检测方法_薛武
- 格式:pdf
- 大小:733.65 KB
- 文档页数:4
Canny算法是一种常用的边缘检测算法,它通过一系列步骤来识别图像中的边缘。
具体步骤如下:
1. 去噪:使用高斯模糊来减少图像中的噪声,因为噪声可能会影响边缘检测的准确性。
高斯模糊可以通过选择一个适当大小的高斯核对图像进行卷积来实现。
2. 计算梯度的幅度与方向:这一步是为了找出图像中亮度变化显著的地方,这些地方通常是边缘所在。
梯度的大小和方向可以帮助确定边缘的强度和方向。
3. 非极大值抑制:在这一步中,算法会细化边缘,确保边缘只有一个像素宽。
这是通过抑制那些在梯度方向上不是最大值的像素来实现的。
4. 双阈值处理:Canny算法使用两个阈值来确定哪些边缘是真实的。
一个高阈值用来识别强边缘,而一个低阈值用来识别弱边缘。
这个步骤有助于区分真正的边缘和由噪声引起的假边缘。
5. 连接边缘:最后,算法会连接那些被标记为弱边缘的像素,如果它们与强边缘相连。
这样可以减少因高斯模糊而导致的边缘丢失问题。
在使用Canny算法时,需要注意选择合适的阈值,因为阈值的选择会影响检测到的边缘数量和质量。
阈值设置得过低可能会导致提取过多的细节边缘,而设置得过高则可能会错过一些真实的边缘。
Canny算法因其优秀的边缘检测性能而被广泛应用于图像处理领域,如图像分割、特征提取等。
在实际应用中,通常需要根据具体的图像内容和需求来调整算法的参数,以获得最佳的边缘检测效果。
Canny算子边缘检测的一种改进方法
王佐成;刘晓冬;薛丽霞
【期刊名称】《计算机工程与应用》
【年(卷),期】2010(046)034
【摘要】传统Canny算子在高斯滤波方差和滞后阈值的选择上需要人工干预,不具备自适应能力.高斯滤波方差的大小选择会影响到去噪和边缘保持效果,用不同尺度的形态学滤波代替高斯滤波,不仅能降低噪声影响,而且可保持边缘强度和细节;滞后阈值的选择会影响到假边缘现象的强弱和真实边缘的连续性,引入Otsu阈值法并将其推广至直方图具有多峰特点的情况,算法可根据图像自身特点选取阈值,使检测出的边缘更加连续并减少假边缘的存在.
【总页数】4页(P202-204,248)
【作者】王佐成;刘晓冬;薛丽霞
【作者单位】重庆邮电大学计算机学院,重庆,400065;重庆邮电大学计算机学院,重庆,400065;重庆邮电大学计算机学院,重庆,400065
【正文语种】中文
【中图分类】TP391
【相关文献】
1.基于Canny算子图像边缘检测的改进方法 [J], 陈世文;丘威;房宜汕
2.一种基于Canny算子的图像边缘检测方法 [J], 辛玉欣;王传洋
3.一种形态学与Canny算子融合的焊接熔池边缘检测算法 [J], 张亚红;覃科;
4.一种形态学与Canny算子融合的焊接熔池边缘检测算法 [J], 张亚红;覃科
5.一种改进型Canny算子边缘检测算法 [J], 朱秋林; 石银涛; 李靖
因版权原因,仅展示原文概要,查看原文内容请购买。
Canny检测算法与实现1、原理图象边缘就是图像颜⾊快速变化的位置,对于灰度图像来说,也就是灰度值有明显变化的位置。
图像边缘信息主要集中在⾼频段,图像锐化或检测边缘实质就是⾼通滤波。
数值微分可以求变化率,在图像上离散值求梯度,图像处理中有多种边缘检测(梯度)算⼦,常⽤的包括普通⼀阶差分,Robert算⼦(交叉差分),Sobel算⼦,⼆阶拉普拉斯算⼦等等,是基于寻找梯度强度。
Canny 边缘检测算法是John F. Canny 于1986年开发出来的⼀个多级边缘检测算法,也被很多⼈认为是边缘检测的最优算法, 最优边缘检测的三个主要评价标准是:低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产⽣的误报。
⾼定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。
最⼩响应: 图像中的边缘只能标识⼀次。
Canny算⼦求边缘点具体算法步骤如下:1. ⽤⾼斯滤波器平滑图像.2. ⽤⼀阶偏导有限差分计算梯度幅值和⽅向.3. 对梯度幅值进⾏⾮极⼤值抑制.4. ⽤双阈值算法检测和连接边缘.2、实现步骤2.1、消除噪声使⽤⾼斯平滑滤波器卷积降噪。
下⾯显⽰了⼀个 size = 5 的⾼斯内核⽰例:2.2、计算梯度幅值和⽅向按照Sobel滤波器的步骤,计算⽔平和垂直⽅向的差分Gx和Gy:在vs中可以看到sobel像素值和形状:梯度幅值和⽅向为:梯度⽅向近似到四个可能⾓度之⼀(⼀般 0, 45, 90, 135)。
2.3、⾮极⼤值抑制⾮极⼤值抑制是指寻找像素点局部最⼤值。
sobel算⼦检测出来的边缘太粗了,我们需要抑制那些梯度不够⼤的像素点,只保留最⼤的梯度,从⽽达到瘦边的⽬的。
沿着梯度⽅向,⽐较它前⾯和后⾯的梯度值,梯度不够⼤的像素点很可能是某⼀条边缘的过渡点,排除⾮边缘像素,最后保留了⼀些细线。
在John Canny提出的Canny算⼦的论⽂中,⾮最⼤值抑制就只是在0、90、45、135四个梯度⽅向上进⾏的,每个像素点梯度⽅向按照相近程度⽤这四个⽅向来代替。
Canny算子子像素边缘检测方法薛武;张永生;董广军;纪松;于英【期刊名称】《遥感信息》【年(卷),期】2013(028)001【摘要】This paper employs a quadratic interpolation of the values of the gradient norm by using three values in the gradient direction and then returns the position of the local maxima point as the exact position of the edge. The main advantage of this new method over other edge detectors is that it increases the edge detection accuracy to the level of sub-pixels while keeping the original amount of calculation.%在Canny算子的基础上,通过对梯度模值的内插求得沿边缘点梯度方向上相邻像素的梯度模值,利用这些梯度模值拟合二次曲线求出其极大值得到子像素定位的精确位置.通过推导,证明了梯度模在梯度方向上的极大值点就是边缘的精确位置.该算法在几乎没有增加计算量的前提下将Canny算子边缘检测精度提高到了子像素级.【总页数】4页(P8-10,15)【作者】薛武;张永生;董广军;纪松;于英【作者单位】信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052【正文语种】中文【中图分类】TP79【相关文献】1.基于改进的Canny算子和Zernike矩的亚像素边缘检测方法 [J], 马艳娥;高磊;吕晶晶;刘国鹏;张波涛2.融合Canny算子和小波变换的边缘检测方法 [J], 赵静;杨化超3.一种基于Canny算子的图像边缘检测方法 [J], 辛玉欣;王传洋4.基于改进Canny算子的磁共振T2加权图像边缘检测方法研究 [J], 和清源;焦青亮;蒋依芹;傅瑜;刘子龙;于坤;张朋;王永中5.基于改进RGHS和Canny算子的水下图像边缘检测方法 [J], 王慧芳;陈远明;彭荣发;洪晓斌因版权原因,仅展示原文概要,查看原文内容请购买。
一.Canny边缘检测算法原理JohnCanny于1986年提出Canny算子,属于是先平滑后求导数的方法。
其处理过程大体上分为下面四部分。
1. 对原始图像进行灰度化Canny算法通常处理的图像为灰度图,因此如果获取的是彩色图像,那首先就得进行灰度化。
对一幅彩色图进行灰度化,就是根据图像各个通道的采样值进行加权平均。
以RGB格式的彩图为例,通常灰度化采用的方法主要有:方法1:Gray=(R+G+B)/3;方法2:Gray=0.299R+0.587G+0.114B;(这种参数考虑到了人眼的生理特点)至于其他格式的彩色图像,可以根据相应的转换关系转为RGB然后再进行灰度化;在编程时要注意图像格式中RGB的顺序通常为BGR。
2. 对图像进行高斯滤波图像高斯滤波的实现可以用两个一维高斯核分别两次加权实现,也可以通过一个二维高斯核一次卷积实现。
1)高斯核实现上式为离散化的一维高斯函数,确定参数就可以得到一维核向量。
上式为离散化的二维高斯函数,确定参数就可以得到二维核向量。
在求得高斯核后,要对整个核进行归一化处理。
2)图像高斯滤波对图像进行高斯滤波,其实就是根据待滤波的像素点及其邻域点的灰度值按照一定的参数规则进行加权平均。
这样可以有效滤去理想图像中叠加的高频噪声。
通常滤波和边缘检测是矛盾的概念,抑制了噪声会使得图像边缘模糊,这会增加边缘定位的不确定性;而如果要提高边缘检测的灵敏度,同时对噪声也提高了灵敏度。
实际工程经验表明,高斯函数确定的核可以在抗噪声干扰和边缘检测精确定位之间提供较好的折衷方案。
3. 用一阶偏导的有限差分来计算梯度的幅值和方向关于图像灰度值得梯度可使用一阶有限差分来进行近似,这样就可以得图像在x和y 方向上偏导数的两个矩阵。
常用的梯度算子有如下几种:1)Roberts算子上式为其x和y方向偏导数计算模板,可用数学公式表达其每个点的梯度幅值为:2)Sobel算子上式三个矩阵分别为该算子的x向卷积模板、y向卷积模板以及待处理点的邻域点标记矩阵,据此可用数学公式表达其每个点的梯度幅值为:3)Prewitt算子和Sobel算子原理一样,在此仅给出其卷积模板。
一种改进的Canny算子边缘检测算法宗露艳;吴陈【摘要】边缘是图像的基本特征之一,因此在图像处理中图像边缘检测是图像处理的一个重要部分.由于传统的Canny边缘检测算法是通过在2×2领域内求有限差分来计算梯度幅值的,易受噪声的影响,容易检测出孤立点和伪边缘.在基于传统的Canny边缘检测算法的基础上,采用3×3领域的梯度幅值计算方法,提高了边缘的定位精度,改善了对噪声的敏感性.实验结果表明,该算法在保证实时性的同时,具有更好的检测精度和准确度.%Edge is one of the basic characteristics of the image, so image edge detection is an important part of image proccssing.The traditional Canny edge detection algorithm found finite difference in 2 × 2 field to calculate gradient amplitude, so it can be easily affected by the noise, and the outlier and untrue edge can be easily detected.A 3×3 field gradient magnitude calculation method is used based on the traditional Canny edge detection algorithm.This method proves that it can improve the image's edge positioning accuracy and the sensitivity tonoise.Experimental results indicate that this algorithm has better examination precision and accuracy during guarantee its real-time performance.【期刊名称】《现代电子技术》【年(卷),期】2011(034)004【总页数】3页(P104-106)【关键词】Canny算子;边缘检测;图像处理;梯度幅值【作者】宗露艳;吴陈【作者单位】江苏科技大学,计算机科学与工程学院,江苏镇江212003;江苏科技大学,计算机科学与工程学院,江苏镇江212003【正文语种】中文【中图分类】TN919-34;TP3910 引言图像的边缘是图像灰度发生空间突变或在梯度方向上发生突变的像素集合。
Canny 边缘检测算法【OpenCV】Canny 边缘检测分类:【OpenCV】2012-08-08 10:17 490人阅读评论(10) 收藏举报Canny 边缘检测算法1986年,JOHN CANNY 提出一个很好的边缘检测算法,被称为Canny编边缘检测器[1]。
Canny边缘检测根据对信噪比与定位乘积进行测度,得到最优化逼近算子,也就是Canny算子。
类似与LoG边缘检测方法,也属于先平滑后求导数的方法。
使用Canny边缘检测器,图象边缘检测必须满足两个条件:能有效地抑制噪声;必须尽量精确确定边缘的位置。
算法大致流程:1、求图像与高斯平滑滤波器卷积:2、使用一阶有限差分计算偏导数的两个阵列P与Q:3、幅值和方位角:4、非极大值抑制(NMS ):细化幅值图像中的屋脊带,即只保留幅值局部变化最大的点。
将梯度角的变化范围减小到圆周的四个扇区之一,方向角和幅值分别为:非极大值抑制通过抑制梯度线上所有非屋脊峰值的幅值来细化M[i,j],中的梯度幅值屋脊.这一算法首先将梯度角θ[i,j]的变化范围减小到圆周的四个扇区之一,如下图所示:5、取阈值将低于阈值的所有值赋零,得到图像的边缘阵列阈值τ取得太低->假边缘阈值τ取得太高->部分轮廊丢失选用两个阈值: 更有效的阈值方案.相关代码Canny算法实现:用高斯滤波器平滑图像(在调用Canny之前自己用blur平滑)用一阶偏导的有限差分来计算梯度的幅值和方向.对梯度幅值应用非极大值抑制.用双阈值算法检测和连接边缘.[cpp] view plaincopyprint?void cv::Canny( InputArray _src, OutputArray _dst,double low_thresh, double high_thresh,int aperture_size, bool L2gradient ){Mat src = _src.getMat();CV_Assert( src.depth() == CV_8U );_dst.create(src.size(), CV_8U);Mat dst = _dst.getMat();if (!L2gradient && (aperture_size &CV_CANNY_L2_GRADIENT) ==CV_CANNY_L2_GRADIENT){//backward compatibilityaperture_size &= ~CV_CANNY_L2_GRADIENT;L2gradient = true;}if ((aperture_size & 1) == 0 || (aperture_size != -1 && (aperture_size 7)))CV_Error(CV_StsBadFlag, "");#ifdef HA VE_TEGRA_OPTIMIZATIONif (tegra::canny(src, dst, low_thresh, high_thresh, aperture_size, L2gradient))return;#endifconst int cn = src.channels();cv::Mat dx(src.rows, src.cols, CV_16SC(cn));cv::Mat dy(src.rows, src.cols, CV_16SC(cn));cv::Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0,cv::BORDER_REPLICATE);cv::Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, cv::BORDER_REPLICATE);if (low_thresh > high_thresh)std::swap(low_thresh, high_thresh);if (L2gradient){low_thresh = std::min(32767.0, low_thresh);high_thresh = std::min(32767.0, high_thresh);if (low_thresh > 0) low_thresh *= low_thresh;if (high_thresh > 0) high_thresh *= high_thresh;}int low = cvFloor(low_thresh);int high = cvFloor(high_thresh);ptrdiff_t mapstep = src.cols + 2;cv::AutoBuffer buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int));int* mag_buf[3];mag_buf[0] = (int*)(uchar*)buffer;mag_buf[1] = mag_buf[0] + mapstep*cn;mag_buf[2] = mag_buf[1] + mapstep*cn;memset(mag_buf[0], 0, /* cn* */mapstep*sizeof(int));uchar* map = (uchar*)(mag_buf[2] + mapstep*cn); memset(map, 1, mapstep);memset(map + mapstep*(src.rows + 1), 1, mapstep);int maxsize = std::max(1std::vector stack(maxsize);uchar **stack_top = &stack[0];uchar **stack_bottom = &stack[0];/* sector numbers(Top-Left Origin)1 2 3* * ** * *0*******0* * ** * *3 2 1*/#define CANNY_PUSH(d) *(d) = uchar(2), *stack_top++ = (d)#define CANNY_POP(d) (d) = *--stack_top// calculate magnitude and angle of gradient, performnon-maxima supression.// fill the map with one of the following values:// 0 - the pixel might belong to an edge// 1 - the pixel can not belong to an edge// 2 - the pixel does belong to an edgefor (int i = 0; i{int* _norm = mag_buf[(i > 0) + 1] + 1;if (i{short* _dx = dx.ptrshort>(i);short* _dy = dy.ptrshort>(i);if (!L2gradient){for (int j = 0; j_norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j])); }else{for (int j = 0; j_norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j];}if (cn > 1){for(int j = 0, jn = 0; j{int maxIdx = jn;for(int k = 1; kif(_norm[jn + k] > _norm[maxIdx]) maxIdx = jn + k;_norm[j] = _norm[maxIdx];_dx[j] = _dx[maxIdx];_dy[j] = _dy[maxIdx];}}_norm[-1] = _norm[src.cols] = 0;}elsememset(_norm-1, 0, /* cn* */mapstep*sizeof(int));// at the very beginning we do not have a complete ring// buffer of 3 magnitude rows for non-maxima suppressionif (i == 0)continue;uchar* _map = map + mapstep*i + 1;_map[-1] = _map[src.cols] = 1;int* _mag = mag_buf[1] + 1; // take the central row ptrdiff_t magstep1 = mag_buf[2] - mag_buf[1]; ptrdiff_t magstep2 = mag_buf[0] - mag_buf[1];const short* _x = dx.ptrshort>(i-1);const short* _y = dy.ptrshort>(i-1);if ((stack_top - stack_bottom) + src.cols > maxsize) {int sz = (int)(stack_top - stack_bottom);maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;}int prev_flag = 0;for (int j = 0; j{#define CANNY_SHIFT 15const int TG22 =(int)(0.4142135623730950488016887242097*(1 int m = _mag[j];if (m > low){int xs = _x[j];int ys = _y[j];int x = std::abs(xs);int y = std::abs(ys)int tg22x = x * TG22;if (y{if (m > _mag[j-1] && m >= _mag[j+1]) goto __ocv_canny_push;}else{int tg67x = tg22x + (xif (y > tg67x){if (m > _mag[j+magstep2] && m >= _mag[j+magstep1]) goto __ocv_canny_push;}else{int s = (xs ^ ys)if (m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s]) goto __ocv_canny_push;}}}prev_flag = 0;_map[j] = uchar(1);continue;__ocv_canny_push:if (!prev_flag && m > high && _map[j-mapstep] != 2){CANNY_PUSH(_map + j);prev_flag = 1;}else_map[j] = 0;}// scroll the ring buffer_mag = mag_buf[0];mag_buf[0] = mag_buf[1];mag_buf[1] = mag_buf[2];mag_buf[2] = _mag;}// now track the edges (hysteresis thresholding)while (stack_top > stack_bottom){uchar* m;if ((stack_top - stack_bottom) + 8 > maxsize) {int sz = (int)(stack_top - stack_bottom); maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;}CANNY_POP(m);if (!m[-1]) CANNY_PUSH(m - 1);if (!m[1]) CANNY_PUSH(m + 1);if (!m[-mapstep-1]) CANNY_PUSH(m - mapstep - 1); if (!m[-mapstep]) CANNY_PUSH(m - mapstep);if (!m[-mapstep+1]) CANNY_PUSH(m - mapstep + 1); if (!m[mapstep-1]) CANNY_PUSH(m + mapstep - 1); if (!m[mapstep]) CANNY_PUSH(m + mapstep);if (!m[mapstep+1]) CANNY_PUSH(m + mapstep + 1); }// the final pass, form the final imageconst uchar* pmap = map + mapstep + 1;uchar* pdst = dst.ptr();for (int i = 0; i{for (int j = 0; jpdst[j] = (uchar)-(pmap[j] >> 1);}} void cv::Canny( InputArray _src, OutputArray _dst,double low_thresh, double high_thresh,int aperture_size, bool L2gradient ){Mat src = _src.getMat();CV_Assert( src.depth() == CV_8U );_dst.create(src.size(), CV_8U);Mat dst = _dst.getMat(); if (!L2gradient && (aperture_size & CV_CANNY_L2_GRADIENT) ==CV_CANNY_L2_GRADIENT){//backward compatibilityaperture_size &= ~CV_CANNY_L2_GRADIENT;L2gradient = true;} if ((aperture_size & 1) == 0 || (aperture_size != -1 && (aperture_size 7)))CV_Error(CV_StsBadFlag, "");#ifdefHA VE_TEGRA_OPTIMIZATIONif (tegra::canny(src, dst, low_thresh, high_thresh, aperture_size, L2gradient))return;#endif const int cn = src.channels();cv::Mat dx(src.rows, src.cols, CV_16SC(cn));cv::Mat dy(src.rows, src.cols, CV_16SC(cn));cv::Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0,cv::BORDER_REPLICATE);cv::Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, cv::BORDER_REPLICATE); if (low_thresh > high_thresh) std::swap(low_thresh, high_thresh); if(L2gradient){low_thresh = std::min(32767.0, low_thresh);high_thresh = std::min(32767.0, high_thresh);if (low_thresh > 0) low_thresh *= low_thresh;if (high_thresh > 0) high_thresh *= high_thresh;}int low = cvFloor(low_thresh);int high = cvFloor(high_thresh); ptrdiff_t mapstep =src.cols + 2;cv::AutoBuffer buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int));int* mag_buf[3];mag_buf[0] = (int*)(uchar*)buffer;mag_buf[1] = mag_buf[0] + mapstep*cn;mag_buf[2] = mag_buf[1] + mapstep*cn;memset(mag_buf[0], 0, /* cn* */mapstep*sizeof(int)); uchar* map = (uchar*)(mag_buf[2] + mapstep*cn);memset(map, 1, mapstep);memset(map + mapstep*(src.rows + 1), 1, mapstep);int maxsize = std::max(1 << 10, src.cols * src.rows / 10);std::vector stack(maxsize);uchar **stack_top = &stack[0];uchar **stack_bottom = &stack[0]; /* sector numbers (Top-Left Origin) 1 2 3* * ** * *0*******0* * ** * *3 2 1*/ #define CANNY_PUSH(d) *(d) = uchar(2),*stack_top++ = (d)#define CANNY_POP(d) (d) = *--stack_top // calculate magnitude and angle of gradient, perform non-maxima supression.// fill the map with one of the following values:// 0 - the pixel might belong to an edge// 1 - the pixel can not belong to an edge// 2 - the pixel does belong to an edgefor (int i = 0; i 0) + 1] + 1;if (i < src.rows){short* _dx = dx.ptr(i);short* _dy = dy.ptr(i); if(!L2gradient){for (int j = 0; j < src.cols*cn; j++)_norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j]));}else{for (int j = 0; j 1){for(int j = 0, jn = 0; j _norm[maxIdx]) maxIdx = jn + k;_norm[j] = _norm[maxIdx];_dx[j] = _dx[maxIdx];_dy[j] = _dy[maxIdx];}}_norm[-1] = _norm[src.cols] = 0;}elsememset(_norm-1, 0, /* cn**/mapstep*sizeof(int));// at the very beginning we do not have a complete ring// buffer of 3 magnitude rows for non-maxima suppressionif (i == 0)continue; uchar* _map = map +mapstep*i + 1;_map[-1] = _map[src.cols] = 1; int* _mag = mag_buf[1] + 1; // take the central rowptrdiff_t magstep1 = mag_buf[2] - mag_buf[1];ptrdiff_t magstep2 = mag_buf[0] - mag_buf[1]; const short* _x = dx.ptr(i-1);const short* _y = dy.ptr(i-1); if ((stack_top - stack_bottom) + src.cols > maxsize){int sz = (int)(stack_top - stack_bottom);maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;} int prev_flag = 0;for (int j = 0; j < src.cols; j++){#define CANNY_SHIFT 15const int TG22 =(int)(0.4142135623730950488016887242097*(1 low){int xs = _x[j];int ys = _y[j];int x = std::abs(xs);int y = std::abs(ys) = _mag[j+1]) goto __ocv_canny_push;}else{int tg67x = tg22x + (x =_mag[j+magstep1]) goto __ocv_canny_push;}else{int s = (xs ^ ys)_mag[j+magstep1+s]) goto __ocv_canny_push;}}}prev_flag = 0;_map[j] = uchar(1);continue;__ocv_canny_push:if (!prev_flag && m > high &&_map[j-mapstep] != 2){CANNY_PUSH(_map + j);prev_flag = 1;}else_map[j] = 0;} // scroll the ring buffer_mag = mag_buf[0];mag_buf[0] = mag_buf[1];mag_buf[1] = mag_buf[2];mag_buf[2] = _mag;} // now track the edges (hysteresis thresholding) while (stack_top > stack_bottom){uchar* m;if ((stack_top - stack_bottom) + 8 > maxsize){int sz = (int)(stack_top - stack_bottom);maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;} CANNY_POP(m); if (!m[-1]) CANNY_PUSH(m - 1);if (!m[1]) CANNY_PUSH(m + 1);if (!m[-mapstep-1]) CANNY_PUSH(m - mapstep - 1);if (!m[-mapstep]) CANNY_PUSH(m - mapstep);if (!m[-mapstep+1]) CANNY_PUSH(m - mapstep + 1);if (!m[mapstep-1]) CANNY_PUSH(m + mapstep - 1);if (!m[mapstep]) CANNY_PUSH(m + mapstep);if (!m[mapstep+1]) CANNY_PUSH(m + mapstep + 1);} // the final pass, form the final imageconst uchar* pmap = map + mapstep + 1;uchar* pdst = dst.ptr();for (int i = 0; i 1);}}Canny() 调用接口(C++):[cpp] viewplaincopyprint?void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2,int apertureSize=3, bool L2gradient=false ) voidCanny(InputArray image, OutputArray edges, double threshold1, double threshold2,int apertureSize=3, boolL2gradient=false )实践示例[cpp] viewplaincopyprint?Mat src, src_gray;Mat dst, detected_edges;int edgeThresh = 1;int lowThreshold;int const max_lowThreshold = 100;int ratio = 3;int kernel_size = 3;char* window_name = "Edge Map";void CannyThreshold(int, void*){/// Reduce noise with a kernel 3x3blur( src_gray, detected_edges, Size(3,3) );/// Canny detectorCanny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );dst = Scalar::all(0);src.copyTo( dst, detected_edges);imshow( window_name, dst );}int main( ){src = imread( "images\\happycat.png" );if( !src.data ){ return -1; }dst.create( src.size(), src.type() );cvtColor( src, src_gray, CV_BGR2GRAY ); namedWindow( window_name,CV_WINDOW_AUTOSIZE );createTrackbar( "Min Threshold:", window_name,&lowThreshold, max_lowThreshold, CannyThreshold ); CannyThreshold(0, 0);waitKey(0);return 0;} Mat src, src_gray;Mat dst, detected_edges;int edgeThresh = 1;int lowThreshold;int const max_lowThreshold = 100;int ratio = 3;int kernel_size = 3;char* window_name = "Edge Map";void CannyThreshold(int, void*){/// Reduce noise with a kernel 3x3blur( src_gray, detected_edges, Size(3,3) );/// Canny detectorCanny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );dst = Scalar::all(0);src.copyTo( dst, detected_edges);imshow( window_name, dst );}int main( ){src = imread( "images\\happycat.png" );if( !src.data ){ return -1; }dst.create( src.size(), src.type() );cvtColor( src, src_gray, CV_BGR2GRAY ); namedWindow( window_name,CV_WINDOW_AUTOSIZE );createTrackbar( "Min Threshold:", window_name,&lowThreshold, max_lowThreshold, CannyThreshold ); CannyThreshold(0, 0);waitKey(0);return 0;} 原图:边缘检测效果图:(从左到右lowThread分别为0、50、100)参考文献:[1] Canny. A Computational Approach to Edge Detection, IEEE Trans. on PatternAnalysis and Machine Intelligence, 8(6), pp. 679-698 (1986).转载请注明出处:/xiaowei_cqu/article/details/7839140资源下载:/detail/xiaowei_cqu/4483966。
canny边缘检测原理Canny边缘检测,是John F. Canny在1986年发表的论文《A Computational Approach to Edge Detection》中对边缘检测(Edge Detection)技术进行了改进,被认为是一种非常有效的图像边缘检测算法。
它是四个步骤(降噪、计算梯度强度、非最大值抑制和双阈值检测)的顺序应用,能够从图像中检测出边缘特征。
Canny边缘检测中的首先步骤是降噪,通过低通滤波器来做图像的高斯模糊处理,有利于减少噪点的影响,使边缘检测更加准确。
接下来是计算梯度强度,即图像梯度。
采用两个Sobel算子来计算图像的水平和垂直梯度,然后相加就得到图像的梯度强度,即边缘的粗略位置。
第三步是非最大值抑制,Canny算法可以自动减少某些边缘点,即抑制非边缘部分的梯度,使边缘更清晰。
双阈值检测(Double Thresholding)是Canny边缘检测的最后一步,采用双阈值的方法,可以用来调节边缘的细节,把不重要的部分过滤掉,有利于边缘的连接以及信息的提取。
总的来说,Canny边缘检测算法能够有效的对图像进行处理,从而清晰的检测出边缘特征,比其他算法更加精准。
因此,Canny边缘检测算法在图像处理中得到了广泛的应用,是一种非常有用的领域。
虽然Canny边缘检测算法具有较高的准确度,但是它也存在一定的局限性,比如在边缘检测的时候,可能会有一些误差,导致无法准确检测到边缘;另外,它也不适用于那种没有清晰轮廓和边界的图片检测。
因此,想要更好地使用Canny边缘检测算法,就需要在应用前进行充分的测试,以便更好地提取图片中边缘信息,清晰地检测出边缘特征,而不会出现不必要的错误。
从上述描述可以看出,Canny边缘检测算法是一种非常有效的边缘检测算法,具有较高的准确度,但也有一定的局限性,因此在使用时需要结合实际情况,特别是在处理含有较复杂边缘的图片时,需要经过充分的测试和调整,以获得更高的准确度。
基于Canny算子的图像边缘检测算法作者:石桂名等来源:《现代电子技术》2015年第12期据图像的某种特定信息,把目标的边缘与周围的区分开来。
回顾了几种传统的边缘检测方法,并分析它们的优缺点,详细阐述了Canny算子的检测原理和实验方法。
实验结果表明Canny算子是最优的边缘检测算子,能够较稳定地对目标图像进行边缘信息提取,得到较好的检测效果。
关键词:图像处理;边缘检测; Canny算子;参数选择中图分类号: TN911.73⁃34 文献标识码: A 文章编号: 1004⁃373X(2015)12⁃0092⁃02边缘检测算法是图像处理中的一个重要部分,本文比较了几种常用的传统边缘检测算法,分析Canny算法的含义、原理和步骤,并将Canny算法应用于车牌和动物的检测。
实验仿真结果验证了Canny算法的良好性能:提取缘信息的同时,能很好地抑制噪声的干扰,提高了图像边缘检测效果,但对于某些细节过于复杂的图像可能丢失一些信息。
1 边缘检测算法简介Roberts算子是一种利用局部差分来寻找边缘的边缘检测算子,它处理的边缘效果不是很好,不够平滑。
Sobel算子是滤波算子,用于提取边缘时,可以利用快速卷积函数,方法简单,使用率较高,但是不能严格地模拟人的视觉生理特征,提取的图像轮廓并不能令人满意[1]。
Prewitt算子是一种基于一阶微分算子的边缘检测,利用像素点周围邻点的灰度差,在边缘处达到极值检测边缘,除掉一些假边缘,起到了平滑噪声的功能。
Laplacian算子是一个二阶微分算子,定义为梯度([∇f])的散度([∇⋅f])。
LoG算子也就是高斯拉普拉斯函数,常常用于数字图像的边缘提取和二值化,它结合了Gauss平滑滤波器和Laplacian锐化滤波器,效果更好。
Canny算子是一个多级边缘检测算法,边缘检测效果最好[2⁃3]。
2 Canny边缘检测算子2.1 Canny算法的含义1986年,John F.Canny找到一个可以实现多级边缘检测的算法,命名为Canny边缘检测算子,其含义如下[4]:(1)最佳检测:能够检测到足够多的图像中实际的边缘,减少真实边缘的漏检率和误检率。
基于MATLAB的改进Canny算子的图像边缘检测研究陈若珠;薛彪【摘要】Edge detection is one of the important parts of image measurement. In order to pick up ef-fectively the edge of the target,an improved algorithm based on Canny algorithm is put forward. The algo-rithm improved in two major areas. Adopt median filter to replace the Gauss filter which is in Canny arith-metic to remove noise and calculate the optimal high and low dual-threshold through iteration arithme-tic. The experiments prove that the proposed arithmetic has the advantage of noise restraining and detail keeping in the field of images management,can better detect the edges of the images,and improving the image edge detection.%边缘检测是图像处理一个重要的环节,为了有效提取目标边缘,提出一种基于canny算法的改进算法,主要从两方面进行的改进,采用中值滤波代替高斯滤波对图像的噪声进行滤除和采用迭代法计算高低双阈值。
实验的仿真结果很好地验证了改进算法的性能:在保留边缘信息的同时,很好地抑制了噪声的干扰,可以提高图像边缘检测效果。
基于Canny算子的彩色图像边缘检测算法【摘要】本文将Canny算子应用于彩色图像,针对单尺度滤波器的缺点,本文采用改进的多尺度滤波器对彩色图像进行平滑。
通过实验证明,本文所采取的彩色图像边缘检测方法对噪声有很好的抑制作用,并且能够提取比较完整的图像边缘,是一种有效的检测方法。
【关键词】彩色图像;Canny算子;多尺度高斯滤波器1、引言边缘检测是图像处理中最基础也是最重要的部分。
其中有关灰度边缘检测的算子众多,有Sobel、Laplace、Roberts、Prewitt、Kisch和Laplacian、Canny等算子[1],然而,在我们现实生活中的大部分图像是彩色图像,与灰度图像相比,彩色图像能提供更多、更丰富的信息。
经过大量的实验证明,10%的边缘信息通过灰度边缘检测算子是检测不出来的[2],可能会丢失一些重要信息。
所以彩色图像边缘检测越来越受到人们的关注。
本文选取在RGB颜色空间中进行彩色图像边缘检测,利用Canny算子对彩色图像进行边缘检测,能够继承Canny算子定位准确,单边响应,信噪比高等优点。
然而,Canny算子在进行平滑图像的过程中,采用单尺度高斯滤波器,不能很好的滤除复杂繁多的噪点,针对这些问题,本文采取了一些措施。
2、算法原理2.1 多尺度高斯滤波器平滑图像利用不同尺度的高斯函数对图像进行滤波,在每个尺度下分别对R、G、B 三个分量多维磨光形成新的真彩色图像。
在本文中选取四个不同尺度的滤波器,分别对图像的3个分量进行滤波,然后对三个分量的四个不同结果进行加权求和,最后输出一个滤波图像。
假设,我们选取的四个不同尺度分别是,则利用这四个不同尺度的高斯函数分别对输入图像的R、G、B三分量进行平滑。
对得到的三分量进行加权求和,最后得到一个平滑后的图像,之后对这两个图像进行后续处理。
假设,加权权值,它们的取值与四个不同尺度的选择有关。
在本文中取分别为:(1)最后得到的滤波图像的三分量为公式(2):其中,分别表示经过四个不同尺度滤波器对三个颜色分量滤波后的三分量图。
Canny边缘检测算法的流程介绍边缘检测的⼀般标准包括:1) 以低的错误率检测边缘,也即意味着需要尽可能准确的捕获图像中尽可能多的边缘。
2) 检测到的边缘应精确定位在真实边缘的中⼼。
3) 图像中给定的边缘应只被标记⼀次,并且在可能的情况下,图像的噪声不应产⽣假的边缘。
在⽬前常⽤的边缘检测⽅法中,Canny边缘检测算法是具有严格定义的,可以提供良好可靠检测的⽅法之⼀。
由于它具有满⾜边缘检测的三个标准和实现过程简单的优势,成为边缘检测最流⾏的算法之⼀。
Canny边缘检测算法的处理流程Canny边缘检测算法可以分为以下5个步骤:1) 使⽤⾼斯滤波器,以平滑图像,滤除噪声。
2) 计算图像中每个像素点的梯度强度和⽅向。
3) 应⽤⾮极⼤值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
4) 应⽤双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
5) 通过抑制孤⽴的弱边缘最终完成边缘检测。
下⾯详细介绍每⼀步的实现思路。
1 ⾼斯平滑滤波为了尽可能减少噪声对边缘检测结果的影响,所以必须滤除噪声以防⽌由噪声引起的错误检测。
为了平滑图像,使⽤⾼斯滤波器与图像进⾏卷积,该步骤将平滑图像,以减少边缘检测器上明显的噪声影响。
⼤⼩为(2k+1)x(2k+1)的⾼斯滤波器核的⽣成⽅程式由下式给出:下⾯是⼀个sigma = 1.4,尺⼨为3x3的⾼斯卷积核的例⼦(需要注意归⼀化):若图像中⼀个3x3的窗⼝为A,要滤波的像素点为e,则经过⾼斯滤波之后,像素点e的亮度值为:其中*为卷积符号,sum表⽰矩阵中所有元素相加求和。
重要的是需要理解,⾼斯卷积核⼤⼩的选择将影响Canny检测器的性能。
尺⼨越⼤,检测器对噪声的敏感度越低,但是边缘检测的定位误差也将略有增加。
⼀般5x5是⼀个⽐较不错的trade off。
2 计算梯度强度和⽅向图像中的边缘可以指向各个⽅向,因此Canny算法使⽤四个算⼦来检测图像中的⽔平、垂直和对⾓边缘。
69科技资讯 科技资讯 SCIENCE & TECHNOLOGY INFORMATION2007 NO.34SCIENCE & TECHNOLOGY INFORMATIONI T 技 术物体的边缘是以图像局部的不连续性的形式出现的,例如,灰度值的突变,颜色的突变,纹理结构的突变等。
从本质上说,边缘常常意味着一个区域的终结和另一个区域的开始。
图像边缘信息在图像分布和人的视觉中都是十分重要的,是图像识别中提取图像特征的一个重要属性,而边缘提取算法则是图像边缘检测问题中经典技术难题之一。
它的解决对于我们进行高层次的特征描述、识别和理解等有着重大的影响,又由于边缘检测在许多方面都有着非常重要的使用价值,所以人们一直在致力于研究和解决如何构造出具有良好性质及好的效果的边缘检测算子的问题。
边缘检测的实质是采用某种算法来提取出图像中对象与背景间的交界线。
我们将边缘定义为图像中灰度发生急剧变化的区域边界。
图像灰度的变化情况可以用图像灰度分布的梯度来反映,因此我们可以用局部图像微分技术来获得边缘检测算子。
Canny(坎尼)算子这种方法是以待处理像素为中心的邻域作为进行灰度分析的基础,实现对图像边缘的提取并已经取得了较好的处理效果。
由于Canny边缘算子具有许多优点,所以重在介绍。
Canny算子检测方法的优点:①低误码率,很少把边缘点误认为非边缘点;②高定位精度,即精确地把边缘点定位在灰度变化最大的像素上;③抑制虚假边缘。
1 Canny边缘检测基本原理具有既能滤去噪声又保持边缘特性的边缘检测最优滤波器,其采用一阶微分滤波器。
采用二维高斯函数的任意方向上的一阶方向导数为噪声滤波器,通过与图像卷积进行滤波;然后对滤波后的图像寻找图像梯度的局部最大值,以此来确定图像边缘。
根据对信噪比与定位乘积进行测度,得到最优化逼近算子,这就是Canny边缘检测算子。
类似与Marr(LOG)边缘检测方法,也属于先平滑后求导数的方法。
2 Canny边缘检测算法,其数学描述如下:step1:用高斯滤波器平滑图象。
canny算子原理Canny算子原理。
Canny算子是一种经典的边缘检测算法,由约翰·F·坎尼于1986年提出。
它被广泛应用于计算机视觉领域,用于检测图像中的边缘信息。
Canny算子具有良好的抗噪声能力和准确的边缘定位能力,成为了图像处理中不可或缺的重要工具。
Canny算子的原理主要包括以下几个步骤:1. 高斯滤波。
首先,对输入的图像进行高斯滤波,以减少图像中的噪声。
高斯滤波采用了高斯函数作为卷积核,能够有效地平滑图像并保留图像的边缘信息。
2. 计算梯度幅值和方向。
接下来,利用Sobel算子计算图像中每个像素点的梯度幅值和方向。
梯度幅值反映了图像中灰度变化的快慢,而梯度方向则指示了灰度变化的方向。
3. 非极大值抑制。
在梯度方向上进行非极大值抑制,即对图像中的每个像素点,沿着梯度方向上比较其梯度幅值与相邻两个像素点的梯度幅值,保留局部梯度最大值,抑制非极大值点,以得到更细的边缘。
4. 双阈值边缘检测。
通过设定两个阈值,将图像中的像素点分为强边缘、弱边缘和非边缘三类。
强边缘是指梯度幅值大于高阈值的像素点,弱边缘是指梯度幅值介于高低阈值之间的像素点,非边缘则是指梯度幅值小于低阈值的像素点。
强边缘直接被认为是真实的边缘像素,而弱边缘则需要进一步的处理来判断其是否为真实的边缘。
5. 边缘跟踪与边缘连接。
最后,利用强边缘像素点进行边缘跟踪,将与强边缘像素点相邻的弱边缘像素点连接到边缘上,从而得到完整的边缘信息。
Canny算子通过以上几个步骤,能够有效地检测图像中的边缘信息,并且对噪声具有较好的抑制能力。
它在图像处理和计算机视觉领域有着广泛的应用,如人脸识别、目标检测、图像分割等方面都能看到它的身影。
总的来说,Canny算子是一种经典且高效的边缘检测算法,它的原理简单清晰,能够准确地提取图像中的边缘信息,因此在实际应用中具有重要的意义。
希望本文对Canny算子的原理有所帮助,让读者对其有一个更深入的理解。
canny边缘检测算子摘要在图象边缘检测中往往要求所检测到的边缘具有封闭特性,本文详细地分析了目前常用的两种算法:哈夫变换和Canny 边缘检测算法,最后,探讨边缘算子应满足的准则。
关键词边缘检测;闭合性;哈夫变换;Canny算子1引言图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是一个阶跃,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。
图象的边缘部分集中了图象的大部分信息,图象边缘的确定与提取对于整个图象场景的识别与理解是非常重要的,同时也是图象分割所依赖的重要特征,边缘检测主要是图象的灰度变化的度量、检测和定位,自从195 9提出边缘检测以来,经过五十多年的发展,已有许多中不同的边缘检测方法。
在我们常用的几种用于边缘检测的算子中Laplace算子常常会产生双边界;而其他一些算子如Sobel算子又往往会形成不闭合区域。
本文主要讨论了在边缘检测中,获取封闭边界区域的算法。
2 图象边缘检测的基本步骤(1)滤波。
边缘检测主要基于导数计算,但受噪声影响。
但滤波器在降低噪声的同时也导致边缘强度的损失。
(2)增强。
增强算法将邻域中灰度有显著变化的点突出显示。
一般通过计算梯度幅值完成。
(3)检测。
但在有些图象中梯度幅值较大的并不是边缘点。
最简单的边缘检测是梯度幅值阈值判定。
(4)定位。
精确确定边缘的位置。
图1 边缘检测酸法的基本步骤3 边界闭合的算法3.1 哈夫变换[3]由于噪声的存在,用各种算子得到的边缘象素不连续,但是由于边缘象素之间有一定的连续性,我们就可以根据边缘象素在梯度幅度或梯度方向上的连续性把他们连接起来。
具体说来,如果象素(s,t)在象素(x,y)的领域且它们的梯度幅度与梯度方向在给定的阈值下满足:T是幅度阈值;A是角度阈值;那么,如对所有的边缘象素都进行上述的判断和连接就可以得到一个闭合的边界。
哈夫变换方法是利用图像得全局特性而对目标轮廓进行直接检测的方法,在已知区域形状的条件下,哈夫变换可以准确地捕获到目标的边界(连续的获不连续的),并最终以连续曲线的形式输出变换结果,该变换可以从强噪声环境中将已知形状的目标准确得分割提取出来。
万方数据万方数据万方数据万方数据第8期王植等:一种基于Canny理论的自适应边缘检测方法961(g辣椒图像(512x512×8bits(h传统Canny算法图2试验结果(・Canny自适应算法注:传统Canny算法是用Matlab6.5中的Canny算法对原图像进行边缘检测得到的结果寰l算法复杂度算法高斯滤波计算梯度非极大值抑耦产生高低阁值——面弄丽蘸传统Canny算法2×M×Ⅳ次乘法2×MXN次加减2XM×N欢乘法M×Ⅳ欢开方2×MXN次乘法运算M×N次加减运算jlf×Ⅳ攻加减+由图像边缘复杂程度决定:::兰茎::鎏笙i釜釜ii釜銎兰i£墓邕童鳖算法次乘法次加减运算。
,0:=2让工:::2兰詈0、复杂程度决定衰2运算时间万方数据962中国图象图形学报第9卷5结论Canny自适应算法普遍适用于各类图像的阶跃边缘,本算法保持了传统Canny 算子的优点,提高了抑制噪声的能力,而且在算法复杂度和计算时间上均小于传统Canny算子,得到的边缘轮廓图信噪比高,连通性好,更重要的是本算法能够自适应的生成高、低阈值检测图像边缘,自动化程度高,为实现自动匹配进行了有益的探索。
Canny自适应算法也存在如检测效果优于Sobel、Laplacian等简单算子,但是速度相对较慢等问题,这有待于进一步研究解决。
参考文献1Gonzalez C Rafael,Woods E Richard.数字图像处理(第二版 [M],北京:电子工业出版杜,2003:463~4742Canny J A computational approach to edge detection[J]1EEE Transactions on Pattern Analysis and Machine Intelligence, 1986.8(6・679~698.3Demigny D,Lorca F G,Kessal L Evaluation of edge detectors performances with a discrete expression of Canny’s criteria[A].In:Proceedings of International Conference on Image Processing[c],Los Alamitos,CA,USA:1EEE,Computer SOC Press1995:169~1724Demigny D,Kamle T.A discrete expression of Canny’s criteria for step edge detector performances evaluation[J].1EEE Transactions on Pattern Analysis and Machine Intelligence, 1997,19(6:1199~1211.5Demigny D Extension of Canny’s discrete criteria to second derivative filters,towards a unified approach[A]In:Proceedings of International Conference on Image Processing[C].Los Alamitos,CA,USA:1EEE,Computer SOC Press,1998:520~ 5246Worthington P1一Enhanced Canny edge detection using curveture consistency[A].In:Proceedings International Conference on Pattern Recognition[Cj.Los Alamitos,CA,USA: 1EEE,Computer SOC Press,2002t596~5997贾云得机器视觉[M].北京:科学出版社,2000;97~100.8杨枝灵.王开,肖洪伟等.Visual C++数字图像获取处理及实践应用[M].北京;人民邮电出版社,2003:568~569主檀1979年生。
Canny 边缘检测本文档尝试解答如下问题:, 使用OpenCV函数 Canny 检测边缘. 原理?1. Canny 是 John F. Canny 于 1986边缘检测算法年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的最优算法, 最优边缘检测的三个主要评价标准是:, 低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。
, 高定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。
, 最小响应: 图像中的边缘只能标识一次。
步骤? 1. 消除噪声。
使用高斯平滑滤波器卷积降噪。
下面显示了一个的高斯内核示例:2. 计算梯度幅值和方向。
此处,按照Sobel滤波器的步骤:a. 运用一对卷积阵列 (分别作用于和方向):b. 使用下列公式计算梯度幅值和方向:梯度方向近似到四个可能角度之一(一般 0,45, 90, 135)3. 非极大值抑制。
这一步排除非边缘像素,仅仅保留了一些细线条(候选边缘)。
4. : 最后一步,Canny 使用了滞后阈值,滞后滞后阈值阈值需要两个阈值(高阈值和低阈值):a. 如果某一像素位置的幅值超过高阈值, 该像素被保留为边缘像素。
b. 如果某一像素位置的幅值小于阈值, 该低像素被排除。
c. 如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留。
Canny 推荐的高:低阈值比在 2:1 到3:1之间。
5. 想要了解更多细节,你可以参考任何你喜欢的计算机视觉书籍。
源码?1. 本程序做什么?o 要求使用者输入一个数字,设置 Canny EdgeDetector 的低阈值 (通过trackbar)o 使用 Canny 边缘检测产生一个 mask (白线代表边缘,黑色代表背景)。
o 使用 mask 作为掩码显示原图像。
2. 本教程的源码如下,你也可以从这里下载#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"#include <stdlib.h>#include <stdio.h>using namespace cv;/// 全局变量Mat src, src_gray;Mat dst, detected_edges;int edgeThresh = 1;int lowThreshold;int const max_lowThreshold = 100;int ratio = 3;int kernel_size = 3;char* window_name = "Edge Map";/*** @函数 CannyThreshold* @简介: trackbar 交互回调 - Canny阈值输入比例1:3*/void CannyThreshold(int, void*){/// 使用 3x3内核降噪blur( src_gray, detected_edges, Size(3,3) );/// 运行Canny算子Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );/// 使用 Canny算子输出边缘作为掩码显示原图像dst = Scalar::all(0);src.copyTo( dst, detected_edges);imshow( window_name, dst );}/** @函数 main */int main( int argc, char** argv ){/// 装载图像src = imread( argv[1] );if( !src.data ){ return -1; }/// 创建与src同类型和大小的矩阵(dst)dst.create( src.size(), src.type() );/// 原图像转换为灰度图像cvtColor( src, src_gray, CV_BGR2GRAY );/// 创建显示窗口namedWindow( window_name, CV_WINDOW_AUTOSIZE );/// 创建trackbarcreateTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );/// 显示图像CannyThreshold(0, 0);/// 等待用户反应waitKey(0);return 0;}解释?1. 创建程序中要用到的变量:2. Mat src, src_gray;3. Mat dst, detected_edges;4.5. int edgeThresh = 1;6. int lowThreshold;7. int const max_lowThreshold = 100;8. int ratio = 3;9. int kernel_size = 3;10. char* window_name = "Edge Map";11.12. 注意:13.14. a. 我们首先设定高:低阈值比为 3:1 (通过变量 *ratio* )15. b. 设定内核尺寸为 :math:`3` (Canny函数内部调用Sobel操作)c. 将低阈值的上限设定为 :math:`100`. 16. 装载原图像:17. /// 装载图像18. src = imread( argv[1] );19.20. if( !src.data )21. { return -1; }22. 创建与 src 同类型和大小的矩阵(dst)23. dst.create( src.size(), src.type() );24. 将输入图像转换到灰度空间 (使用函数 cvtColor): 25. cvtColor( src, src_gray, CV_BGR2GRAY );26. 创建显示窗口27. namedWindow( window_name,CV_WINDOW_AUTOSIZE );28. 创建trackbar,来获取用户交互输入的低阈值:29. createTrackbar( "Min Threshold:",window_name, &lowThreshold, max_lowThreshold,CannyThreshold );注意:a. 通过trackbar控制的变量为 lowThreshold ,上限为 max_lowThreshold (我们已经设定为100)b. 每次用户通过trackbar产生变动,回调函数CannyThreshold 被调用.30. 让我们一步一步的来观察 CannyThreshold 函数:a. 首先, 使用 3x3的内核平滑图像:b. blur( src_gray, detected_edges,Size(3,3) );c. 其次,运用 Canny 寻找边缘:d. Canny( detected_edges, detected_edges,lowThreshold, lowThreshold*ratio,kernel_size );输入参数:, detected_edges: 原灰度图像, detected_edges: 输出图像 (支持原地计算,可为输入图像), lowThreshold: 用户通过 trackbar设定的值。