Laplacian()函数实现边缘检测。
理论
前面的例子学习了使用Sobel边缘检测。原理是利用边缘区域像素值的跳变。通过求一阶导数,可以使边缘值最大化。如下图所示。
那么,如果求二阶导数会得到什么呢?
可以观察到二阶导数为0的地方。因此,可以利用该方法获取图像中的边缘。然而,需要注意的是二级导数为0的不只出现在边缘地方,还可能是一些无意义的位置,根据需要通过滤波处理该情况。
拉普拉斯算子
从上面的解释,可以看出二级导数可以拥有边缘检测。由于图像是二维的,因此需要分别获取两个方向的导数。这里使用的是拉普拉斯算子来进行近似。
拉普拉斯算子用下面公式定义:
在OpenCV中用Laplacian()函数实现。事实上,函数内部也调用了Sobel算子。
代码
// @tutorials imgproc module 14
// @文件 Laplace_Demo.cpp
// @主题 Laplace算子用于边缘检测
// @修改 CVer
// @日期 2020年1月8日
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
int main( int argc, char** argv )
{
Mat src, src_gray, dst;
int kernel_size = 3;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
const char* window_name = "Laplace Demo";
const char* imageName = "lena.jpg";
src = imread( samples::findFile( imageName ), IMREAD_COLOR );
if(src.empty())
{
printf(" Error opening imagen");
return -1;
}
// 高斯滤波( kernel size = 3 )
GaussianBlur( src, src, Size(3, 3), 0, 0, BORDER_DEFAULT );
//转为灰度图像
cvtColor( src, src_gray, COLOR_BGR2GRAY );
// Laplace变换,结果是CV_16S
Mat abs_dst;
Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
// CV_16S转换为CV_8U
convertScaleAbs( dst, abs_dst );
// 显示
imshow( window_name, abs_dst );
waitKey(0);
return 0;
}
结果
下面是OpenCV示例中给出的结果。可以看出牛和树的轮廓很明显。树后面远处的屋顶,由于对比度很强,所以变换结果很明显。