laplacian函数不能改变其获取内核函数地址值吗

1. Sobel算子
前面我们已经介绍了图像的卷积操作,而一个最重要的卷积运算就是对导数的计算,假设我们需要检测图像中的边缘部分,如下图所示:
前面我们介绍图像的高频和低频分量的时候说到,图像的高频分量一般出现在像素值显著改变的地方,而高频分量的出现就容易勾画出图像的轮廓。在高等数学中我们知道函数变化剧烈其所对应的导数值越大(极大值),所以表示图像像素值改变最大的一个方法就是求出图像的导数。其梯度值剧烈的改变预示着图像中内容发生显著变化。假设我们有一张一维图像,图中灰度值的“跃升”表示边缘的存在:
通过对函数进行一阶微分我们可以更加清晰的看到边缘“跃升”的存在,即在其一阶微分中最大值代表其所对应的像素值变化剧烈。如下图:
从上面的介绍中我们可以推测对于图像边缘的检测可以通过定位梯度值大于邻域的像素的方法找到(或者推广到大于一个阈值即可认为是图像边缘)
Sobel算子是一个离散微分算子(discrete differentiation operator),它用来计算图像灰度函数的近似梯度并结合了高斯平滑和微分求导。假设被处理的图像位I, Sobel算子数学表达公式如下:
1.1在两个方向求导
.a 水平变化:将I与一个奇数大小的内核Gx进行卷积,比如当内核大小为3时,Gx计算结果为:
.b 垂直变化:将I与一个奇数大小的内核Gy进行卷积,比如当内核大小为3时,Gy的计算结果为:
1.2 在图像的每一点结合以上两个结果求出近似梯度:
有时也使用如下更简单的公司代替:
当内核大小为3时,Sobel内核可能产生比较明显的误差,毕竟Sobel算子只是求取了导数的近似值,为了解决这一问题,opencv提供了Scharr函数,但该函数仅作用于大小为3的内核,该函数的运算与Sobel函数一样快,但结果更加精确,其内核如下:
关于Scharr的更多信息请
opencv中提供了sobel函数,其定义如下:
void cv::Sobel
( InputArray
OutputArray
ksize = 3,
scale = 1,
delta = 0,
borderType = BORDER_DEFAULT
当ksize=1时,内核形式为3x1或1x3(没有高斯平滑),ksize=1只能用于一阶或二阶x或y方向上的导数。当ksize=CV_SCHARR(-1)是一个特殊值,将会调用同样为3x3内核比Sobel计算的结果精确的Scharr滤波器。Scharr的核心是:
函数通过一个恰当的内核与图像进行卷积来计算图像导数,如下:
sobel算子结合高斯平滑和分化,所以结果有更好的抗噪性。通常这个函数设置为(xorder = 1, yorder = 0, ksize = 3)来计算图像在x方向上的导数,此时的核如下:
或(xorder = 0, yorder = 1, ksize = 3)来计算y方向图像导数,此时的核如下:
. InputArray src: 输入图像
. OutputArray dst: 输出图像
. int ddepth: 输出图像深度,与输入图像深度对应关系如下表所示:
当输入图像为8-bit时将会导致截断。
. int dx: x方向上的差分阶数
. int dy: y方向上的差分阶数
. int ksize = 3: Sobel函数核尺寸,只能是1、3、5、7中的一个,默认值是3
. double scale = 1: 计算导数值可选的缩放银子,默认值是1表示没有缩放。可以通过查看函数getDerivKernels()获取更加详细的信息
. int borderType = BORDER_DEFAULT:边界模式,可以查询borderInterpolate得到详细信息。
#include &iostream&
#include &opencv2/core.hpp&
#include &opencv2/highgui.hpp&
#include &opencv2/imgproc.hpp&
using namespace std;
using namespace
const int sobel_kernel_size_maxValue = 3;
int sobel_kernel_size_
Mat srcImage, dstImage, grayImage, x_gradImage, y_gradI
Mat x_abs_gradImage, y_abs_gradI
String windowName = "Sobel算子边缘检测";
int depth = 0;
int scale = 1;
int delta = 0;
void sobelFun(int, void*);
int main()
srcImage = imread("lena.jpg");
if(srcImage.empty())
cout && "图像加载失败!" &&
return -1;
cout && "图像加载成功!" && endl &&
GaussianBlur(srcImage, srcImage, Size(3, 3), 0, 0, BORDER_DEFAULT);
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
namedWindow("原图像灰度图", WINDOW_AUTOSIZE);
imshow("原图像灰度图", grayImage);
namedWindow(windowName, WINDOW_AUTOSIZE);
sobel_kernel_size_value = 1;
char kernelSizeName [20];
sprintf(kernelSizeName, "Sobel算子kernel尺寸", sobel_kernel_size_maxValue);
createTrackbar(kernelSizeName, windowName, &sobel_kernel_size_value,
sobel_kernel_size_maxValue, sobelFun);
sobelFun(sobel_kernel_size_value, 0);
waitKey(0);
void sobelFun(int, void*)
kernelvalue = sobel_kernel_size_value * 2 + 1;
Sobel(grayImage, x_gradImage, depth, 1, 0, kernelvalue, scale, delta, BORDER_DEFAULT);
convertScaleAbs(x_gradImage, x_abs_gradImage);
namedWindow("x方向的sobel边缘检测", WINDOW_AUTOSIZE);
imshow("x方向的sobel边缘检测", x_abs_gradImage);
Sobel(grayImage, y_gradImage, depth, 0, 1, kernelvalue, scale, delta, BORDER_DEFAULT);
convertScaleAbs(y_gradImage, y_abs_gradImage);
namedWindow("y方向上的sobel边缘检测", WINDOW_AUTOSIZE);
imshow("y方向上的sobel边缘检测", y_abs_gradImage);
addWeighted(x_abs_gradImage, 0.5, y_abs_gradImage, 0.5, 0, dstImage);
imshow(windowName, dstImage);
代码解释:
.Sobel算子一般与高斯滤波配合使用
.convertScaleAbs()函数的作用是对求得的结果取绝对值并将结果转换成8-bit.
运行结果如下:
2.Laplace算子
Sobel算子是基于在边缘部分,像素值会出现较大的变化,因此在边缘部分求取一阶导数可以得到极值点,如果在边缘部分求二阶导呢?如下图:
在一阶导数的极值位置,二阶导数为0.所以也可以利用这个特点来作为检测图像边缘的方法,但是二阶导数的0值不仅仅出现在边缘,它们也可能出现在无意义的位置,但我们可以过滤掉这些点。因为图像是二维的,需要在两个方向求导,opencv提供了Laplacian函数来实现,使用Laplacian算子将会使求导过程变得简单。Laplacian算子定义如下:
Laplacian函数定义如下:
void cv::Laplacian
InputArray
OutputArray
ksize = 1,
scale = 1,
delta = 0,
borderType = BORDER_DEFAULT
.src: 输入图像
. dst: 输出图像
. ddepth:图像深度
. ksize: 用于计算二阶导的kernel尺寸,可以查看getDerivKernels函数查看详细信息,尺寸必须是正奇数。
. scale: Laplacian算子的可选因子,有默认值1,此时没有应用缩放因子,可查看getDerivKernels查看详细信息
. delta: 存储目标图像前可选的delta值,有默认值0
. borderType:用于推断边界像素的模式,有默认值BORDER_DEFAULT
函数只有在ksize&1时才能正常计算,当ksize==1时,Laplacian将由下面的模板进行计算:
实际上,由于Laplacian使用了图像梯度,它内部调用了Sobel算子。
#include &iostream&
#include &opencv2/core.hpp&
#include &opencv2/highgui.hpp&
#include &opencv2/imgproc.hpp&
using namespace std;
using namespace
Mat srcImage, grayImage, dstImage, dst_absI
const int scale = 1;
const int delta = 0;
const int ddepth = CV_16S;
const int kernelSizeMaxValue = 3;
int kernelSizeV
void laplacianFun(int, void*);
String windowName = "Laplace算子边缘检测";
int main()
srcImage = imread("lena.jpg");
if(srcImage.empty())
cout && "图像加载失败!" &&
return -1;
cout && "图像加载成功!" && endl &&
GaussianBlur(srcImage, srcImage, Size(3, 3), 0, 0, BORDER_DEFAULT);
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
namedWindow("原图像", WINDOW_AUTOSIZE);
imshow("原图像", grayImage);
namedWindow(windowName, WINDOW_AUTOSIZE);
kernelSizeValue = 1;
char trackbarName[20];
sprintf(trackbarName, "laplacian算子kernel尺寸", kernelSizeMaxValue);
createTrackbar(trackbarName, windowName, &kernelSizeValue, kernelSizeMaxValue, laplacianFun);
laplacianFun(kernelSizeValue, 0);
waitKey(0);
void laplacianFun(int, void*)
int kernelS
kernelSize = kernelSizeValue * 2 + 1;
Laplacian(grayImage, dstImage, ddepth, kernelSize, scale, delta, BORDER_DEFAULT);
convertScaleAbs(dstImage, dst_absImage);
imshow(windowName, dst_absImage);
3.Canny算子
Canny边缘检测算法时John F. Canny于1986年开发出来的一个多级边缘检测算法,也被很多人认为时边缘检测的最优算法,,最有边缘检测的三个主要评价标准是:
.低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报
.高定位性:标识处的边缘要与图像中的世纪边缘尽可能接近
.最小响应:图像中的边缘只能标识一次。
Canny边缘检测的步骤如下:
3.1消除噪声
使用高斯平滑滤波器卷积降噪,下面显示了一个size = 5的高斯内核
3.2计算梯度幅值和方向
此处按照Sobel滤波器的步骤
a.运用一对卷积阵列分别作用于x和y方向
b.使用下列公式计算梯度幅值和方向
梯度方向近似得到四个可能角度之一(一般0,45,90,135)
3.3非极大值抑制
这一步排除非边缘像素,仅仅保留了一些细线条(候选边缘)
3.4滞后阈值
最后一步,Canny使用了滞后阈值,滞后阈值需要两个阈值(高阈值和低阈值)
a.如果某一像素位置的幅值超过高阈值,该像素被保留为边缘像素。
b.如果某一像素的幅值小于低阈值,该像素被排除
c.如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留。
Canny推荐的高低阈值比在2:1到3:1之间
opencv提供了两种形式的Canny函数定义,分别如下:
void cv::Canny
InputArray
OutputArray
threshold1,
threshold2,
apertureSize = 3,
L2gradient = false
参数解释:
.Image: 8-bit输入图像
.edges: 输出的边缘图像,8-bit单通道图像,与输入图像有相同的尺寸。
.threshold1: 第一个滞后性阈值
.threshold2: 第二个滞后性阈值
.apertureSize: 表示应用的Sobel算子孔径大小,有默认值3
.L2gradient: 一个计算图像梯度幅值的标识,有默认值false
第二种定义形式如下:
void cv::Canny
InputArray
InputArray
OutputArray
threshold1,
threshold2,
L2gradient = false
我们可以看到这种定义形式只是在输入图像与第一种输入图像不同,针对其输入解释如下:
.dx: 16-bit 输入图像x方向(CV_16SC1或CV_16SC3)
.dy: 16-bit输入图像y方向,与dx类型一样
. 其它参数解释请参考第一种定义形式
对于threshold1和threshold2两个阈值来讲,两者较小的值用于边缘连接而较大的值用来寻找边缘的初始段。
#include &iostream&
#include &opencv2/core.hpp&
#include &opencv2/highgui.hpp&
#include &opencv2/imgproc.hpp&
using namespace std;
using namespace
Mat srcImage, grayImage, dstI
int edgeThresh = 1;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
String windowName =
"Canny算子边缘检测";
void CannyThreshold(int, void*);
int main()
srcImage = imread("lena.jpg");
if(srcImage.empty())
cout && "图像加载失败!" &&
return -1;
cout && "图像加载成功!" && endl &&
GaussianBlur(srcImage, srcImage, Size(3, 3), 0, 0, BORDER_DEFAULT);
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
namedWindow("原图像", WINDOW_AUTOSIZE);
imshow("原图像", grayImage);
namedWindow(windowName, WINDOW_AUTOSIZE);
char trackbarName[20];
sprintf(trackbarName, "阈值", max_lowThreshold);
lowThreshold = 20;
createTrackbar(trackbarName, windowName, &lowThreshold, max_lowThreshold, CannyThreshold);
CannyThreshold(lowThreshold, 0);
waitKey(0);
void CannyThreshold(int, void*)
Canny(grayImage, dstImage, lowThreshold, lowThreshold*ratio, kernel_size);
imshow(windowName, dstImage);
运行结果如下:
本文已收录于以下专栏:
相关文章推荐
一、Laplace算法简介
二阶微分在亮的一边是负的,在暗的一边是正的。常数部分为零。可以用来确定边的准确位置,以及像素在亮的一侧还是暗的一侧。
拉普拉斯算子是最简单的各向同性微分算子,具...
一、图像边缘检测简介
图像的边缘是指图像局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是一个阶跃,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。图像的边缘部分集...
经典图像边缘检测(综合法思想)——Canny算子
John Canny于1986年提出Canny算子,它与Marr(LoG)边缘检测方法类似,也属于是先平滑后求导数的方法。John
Canny研究...
实现自己的线性滤波器
本篇教程中,我们将学到:
用OpenCV函数 filter2D 创建自己的线性滤波器。
以下解释节...
例五:一个复杂一点的变换
1.图像缩放
首先,我们要实现将图片缩放的功能,我们使用cvPyrDown(in,out);
参数in为输入图像的指针,out为输出图像的指针,所以我们需要先构造一个盛放输出...
写了一个很简单的小程序,用canny算子对一幅图像进行边缘检测,需要注意的一点是,canny()函数的输入图像必须为二值图像。
编译环境为win7+visual studio 2010+open...
图像的边缘检测的原理是检测出图像中所有灰度值变化较大的点,而且这些点连接起来就构成了若干线条,这些线条就可以称为图像的边缘。
    Canny边缘检测算子是John F. Canny于 198...
canny 算子實現圖像邊緣檢測(詳細過程附源碼)
/blue-lg/archive//2300899.html
边缘检测算法的基本步骤 
(1)滤波。边缘检测主要基于导数计算,但受噪声影响。但滤波器在降低噪声的同时也导致边缘强度的损失。 (2)增强。增强算法将邻域中灰度有显著变化的点突出显示。一般通过计算梯度...
本篇文章中,我们将一起学习OpenCV中边缘检测的各种算子和滤波器——Canny算子,Sobel算子,Laplace算子以及Scharr滤波器。文章中包含了五个浅墨为大家准备的详细注释的博文配套源代码...
他的最新文章
讲师:汪剑
讲师:刘道宽
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)网站配置未生效 |
| 百度云加速
请打开cookies.
你访问的网站() 使用了
网络。 百度云加速目前无法解析此域名 ().
主要因为: 网站主刚刚在百度云加速添加了这个域名,百度云加速需要几十秒的时间同步到全球网络中。稍等片刻刷新页面即可解决。
也有可能: 网站配置出错.opencv学习(三十二)之图像边缘检测Soble_Laplace_Canny
1. Sobel算子
前面我们已经介绍了图像的卷积操作,而一个最重要的卷积运算就是对导数的计算,假设我们需要检测图像中的边缘部分,如下图所示:
前面我们介绍图像的高频和低频分量的时候说到,图像的高频分量一般出现在像素值显著改变的地方,而高频分量的出现就容易勾画出图像的轮廓。在高等数学中我们知道函数变化剧烈其所对应的导数值越大(极大值),所以表示图像像素值改变最大的一个方法就是求出图像的导数。其梯度值剧烈的改变预示着图像中内容发生显著变化。假设我们有一张一维图像,图中灰度值的“跃升”表示边缘的存在:
通过对函数进行一阶微分我们可以更加清晰的看到边缘“跃升”的存在,即在其一阶微分中最大值代表其所对应的像素值变化剧烈。如下图:
从上面的介绍中我们可以推测对于图像边缘的检测可以通过定位梯度值大于邻域的像素的方法找到(或者推广到大于一个阈值即可认为是图像边缘)
Sobel算子是一个离散微分算子(discrete differentiation operator),它用来计算图像灰度函数的近似梯度并结合了高斯平滑和微分求导。假设被处理的图像位I, Sobel算子数学表达公式如下:
1.1在两个方向求导
.a 水平变化:将I与一个奇数大小的内核Gx进行卷积,比如当内核大小为3时,Gx计算结果为:
.b 垂直变化:将I与一个奇数大小的内核Gy进行卷积,比如当内核大小为3时,Gy的计算结果为:
1.2 在图像的每一点结合以上两个结果求出近似梯度:
有时也使用如下更简单的公司代替:
当内核大小为3时,Sobel内核可能产生比较明显的误差,毕竟Sobel算子只是求取了导数的近似值,为了解决这一问题,opencv提供了Scharr函数,但该函数仅作用于大小为3的内核,该函数的运算与Sobel函数一样快,但结果更加精确,其内核如下:
关于Scharr的更多信息请
opencv中提供了sobel函数,其定义如下:
void cv::Sobel
( InputArray
OutputArray
ksize = 3,
scale = 1,
delta = 0,
borderType = BORDER_DEFAULT
当ksize=1时,内核形式为3x1或1x3(没有高斯平滑),ksize=1只能用于一阶或二阶x或y方向上的导数。当ksize=CV_SCHARR(-1)是一个特殊值,将会调用同样为3x3内核比Sobel计算的结果精确的Scharr滤波器。Scharr的核心是:
函数通过一个恰当的内核与图像进行卷积来计算图像导数,如下:
sobel算子结合高斯平滑和分化,所以结果有更好的抗噪性。通常这个函数设置为(xorder = 1, yorder = 0, ksize = 3)来计算图像在x方向上的导数,此时的核如下:
或(xorder = 0, yorder = 1, ksize = 3)来计算y方向图像导数,此时的核如下:
. InputArray src: 输入图像
. OutputArray dst: 输出图像
. int ddepth: 输出图像深度,与输入图像深度对应关系如下表所示:
当输入图像为8-bit时将会导致截断。
. int dx: x方向上的差分阶数
. int dy: y方向上的差分阶数
. int ksize = 3: Sobel函数核尺寸,只能是1、3、5、7中的一个,默认值是3
. double scale = 1: 计算导数值可选的缩放银子,默认值是1表示没有缩放。可以通过查看函数getDerivKernels()获取更加详细的信息
. int borderType = BORDER_DEFAULT:边界模式,可以查询borderInterpolate得到详细信息。
#include &iostream&
#include &opencv2/core.hpp&
#include &opencv2/highgui.hpp&
#include &opencv2/imgproc.hpp&
using namespace std;
using namespace
const int sobel_kernel_size_maxValue = 3;
int sobel_kernel_size_
Mat srcImage, dstImage, grayImage, x_gradImage, y_gradI
Mat x_abs_gradImage, y_abs_gradI
String windowName = "Sobel算子边缘检测";
int depth = 0;
int scale = 1;
int delta = 0;
void sobelFun(int, void*);
int main()
srcImage = imread("lena.jpg");
if(srcImage.empty())
cout && "图像加载失败!" &&
return -1;
cout && "图像加载成功!" && endl &&
GaussianBlur(srcImage, srcImage, Size(3, 3), 0, 0, BORDER_DEFAULT);
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
namedWindow("原图像灰度图", WINDOW_AUTOSIZE);
imshow("原图像灰度图", grayImage);
namedWindow(windowName, WINDOW_AUTOSIZE);
sobel_kernel_size_value = 1;
char kernelSizeName [20];
sprintf(kernelSizeName, "Sobel算子kernel尺寸", sobel_kernel_size_maxValue);
createTrackbar(kernelSizeName, windowName, &sobel_kernel_size_value,
sobel_kernel_size_maxValue, sobelFun);
sobelFun(sobel_kernel_size_value, 0);
waitKey(0);
void sobelFun(int, void*)
kernelvalue = sobel_kernel_size_value * 2 + 1;
Sobel(grayImage, x_gradImage, depth, 1, 0, kernelvalue, scale, delta, BORDER_DEFAULT);
convertScaleAbs(x_gradImage, x_abs_gradImage);
namedWindow("x方向的sobel边缘检测", WINDOW_AUTOSIZE);
imshow("x方向的sobel边缘检测", x_abs_gradImage);
Sobel(grayImage, y_gradImage, depth, 0, 1, kernelvalue, scale, delta, BORDER_DEFAULT);
convertScaleAbs(y_gradImage, y_abs_gradImage);
namedWindow("y方向上的sobel边缘检测", WINDOW_AUTOSIZE);
imshow("y方向上的sobel边缘检测", y_abs_gradImage);
addWeighted(x_abs_gradImage, 0.5, y_abs_gradImage, 0.5, 0, dstImage);
imshow(windowName, dstImage);
代码解释:
.Sobel算子一般与高斯滤波配合使用
.convertScaleAbs()函数的作用是对求得的结果取绝对值并将结果转换成8-bit.
运行结果如下:
2.Laplace算子
Sobel算子是基于在边缘部分,像素值会出现较大的变化,因此在边缘部分求取一阶导数可以得到极值点,如果在边缘部分求二阶导呢?如下图:
在一阶导数的极值位置,二阶导数为0.所以也可以利用这个特点来作为检测图像边缘的方法,但是二阶导数的0值不仅仅出现在边缘,它们也可能出现在无意义的位置,但我们可以过滤掉这些点。因为图像是二维的,需要在两个方向求导,opencv提供了Laplacian函数来实现,使用Laplacian算子将会使求导过程变得简单。Laplacian算子定义如下:
Laplacian函数定义如下:
void cv::Laplacian
InputArray
OutputArray
ksize = 1,
scale = 1,
delta = 0,
borderType = BORDER_DEFAULT
.src: 输入图像
. dst: 输出图像
. ddepth:图像深度
. ksize: 用于计算二阶导的kernel尺寸,可以查看getDerivKernels函数查看详细信息,尺寸必须是正奇数。
. scale: Laplacian算子的可选因子,有默认值1,此时没有应用缩放因子,可查看getDerivKernels查看详细信息
. delta: 存储目标图像前可选的delta值,有默认值0
. borderType:用于推断边界像素的模式,有默认值BORDER_DEFAULT
函数只有在ksize&1时才能正常计算,当ksize==1时,Laplacian将由下面的模板进行计算:
实际上,由于Laplacian使用了图像梯度,它内部调用了Sobel算子。
#include &iostream&
#include &opencv2/core.hpp&
#include &opencv2/highgui.hpp&
#include &opencv2/imgproc.hpp&
using namespace std;
using namespace
Mat srcImage, grayImage, dstImage, dst_absI
const int scale = 1;
const int delta = 0;
const int ddepth = CV_16S;
const int kernelSizeMaxValue = 3;
int kernelSizeV
void laplacianFun(int, void*);
String windowName = "Laplace算子边缘检测";
int main()
srcImage = imread("lena.jpg");
if(srcImage.empty())
cout && "图像加载失败!" &&
return -1;
cout && "图像加载成功!" && endl &&
GaussianBlur(srcImage, srcImage, Size(3, 3), 0, 0, BORDER_DEFAULT);
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
namedWindow("原图像", WINDOW_AUTOSIZE);
imshow("原图像", grayImage);
namedWindow(windowName, WINDOW_AUTOSIZE);
kernelSizeValue = 1;
char trackbarName[20];
sprintf(trackbarName, "laplacian算子kernel尺寸", kernelSizeMaxValue);
createTrackbar(trackbarName, windowName, &kernelSizeValue, kernelSizeMaxValue, laplacianFun);
laplacianFun(kernelSizeValue, 0);
waitKey(0);
void laplacianFun(int, void*)
int kernelS
kernelSize = kernelSizeValue * 2 + 1;
Laplacian(grayImage, dstImage, ddepth, kernelSize, scale, delta, BORDER_DEFAULT);
convertScaleAbs(dstImage, dst_absImage);
imshow(windowName, dst_absImage);
3.Canny算子
Canny边缘检测算法时John F. Canny于1986年开发出来的一个多级边缘检测算法,也被很多人认为时边缘检测的最优算法,,最有边缘检测的三个主要评价标准是:
.低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报
.高定位性:标识处的边缘要与图像中的世纪边缘尽可能接近
.最小响应:图像中的边缘只能标识一次。
Canny边缘检测的步骤如下:
3.1消除噪声
使用高斯平滑滤波器卷积降噪,下面显示了一个size = 5的高斯内核
3.2计算梯度幅值和方向
此处按照Sobel滤波器的步骤
a.运用一对卷积阵列分别作用于x和y方向
b.使用下列公式计算梯度幅值和方向
梯度方向近似得到四个可能角度之一(一般0,45,90,135)
3.3非极大值抑制
这一步排除非边缘像素,仅仅保留了一些细线条(候选边缘)
3.4滞后阈值
最后一步,Canny使用了滞后阈值,滞后阈值需要两个阈值(高阈值和低阈值)
a.如果某一像素位置的幅值超过高阈值,该像素被保留为边缘像素。
b.如果某一像素的幅值小于低阈值,该像素被排除
c.如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留。
Canny推荐的高低阈值比在2:1到3:1之间
opencv提供了两种形式的Canny函数定义,分别如下:
void cv::Canny
InputArray
OutputArray
threshold1,
threshold2,
apertureSize = 3,
L2gradient = false
参数解释:
.Image: 8-bit输入图像
.edges: 输出的边缘图像,8-bit单通道图像,与输入图像有相同的尺寸。
.threshold1: 第一个滞后性阈值
.threshold2: 第二个滞后性阈值
.apertureSize: 表示应用的Sobel算子孔径大小,有默认值3
.L2gradient: 一个计算图像梯度幅值的标识,有默认值false
第二种定义形式如下:
void cv::Canny
InputArray
InputArray
OutputArray
threshold1,
threshold2,
L2gradient = false
我们可以看到这种定义形式只是在输入图像与第一种输入图像不同,针对其输入解释如下:
.dx: 16-bit 输入图像x方向(CV_16SC1或CV_16SC3)
.dy: 16-bit输入图像y方向,与dx类型一样
. 其它参数解释请参考第一种定义形式
对于threshold1和threshold2两个阈值来讲,两者较小的值用于边缘连接而较大的值用来寻找边缘的初始段。
#include &iostream&
#include &opencv2/core.hpp&
#include &opencv2/highgui.hpp&
#include &opencv2/imgproc.hpp&
using namespace std;
using namespace
Mat srcImage, grayImage, dstI
int edgeThresh = 1;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
String windowName =
"Canny算子边缘检测";
void CannyThreshold(int, void*);
int main()
srcImage = imread("lena.jpg");
if(srcImage.empty())
cout && "图像加载失败!" &&
return -1;
cout && "图像加载成功!" && endl &&
GaussianBlur(srcImage, srcImage, Size(3, 3), 0, 0, BORDER_DEFAULT);
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
namedWindow("原图像", WINDOW_AUTOSIZE);
imshow("原图像", grayImage);
namedWindow(windowName, WINDOW_AUTOSIZE);
char trackbarName[20];
sprintf(trackbarName, "阈值", max_lowThreshold);
lowThreshold = 20;
createTrackbar(trackbarName, windowName, &lowThreshold, max_lowThreshold, CannyThreshold);
CannyThreshold(lowThreshold, 0);
waitKey(0);
void CannyThreshold(int, void*)
Canny(grayImage, dstImage, lowThreshold, lowThreshold*ratio, kernel_size);
imshow(windowName, dstImage);
运行结果如下:
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?}

我要回帖

更多关于 内核函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信