之前介绍了用核心矩阵进行线性滤波的概念。这些滤波器通过移除或减弱高频成分,达到模糊图像的效果。下文中我们执行一种反向的变换,即放大图像中的高频成分。然后用本节介绍的高通滤波器进行边缘检测。
一、边缘检测概述
边缘检测可以提取图像重要轮廓信息,减少图像内容, 可以用于分割图像、做特征提取等。
边缘检测的一般步骤:滤波----(滤出噪声対检测边缘的影响)
增强----(可以将像素邻域强度变化凸显出来---梯度算子)
检测----(阈值方法确定边缘)
常用的边缘检测算子: Canny算子、Sobel算子、Scharr算子、Laplacian算子、Roberts算子、Prewitt算子。。。。
(1)、Canny边缘检测
Canny边缘检测算子是John F.Canny于1986 年开发出来的一个多级边缘检测算法, Canny边缘检测算法以Canny的名字命名, 被很多人推崇为当今最优的边缘检测的算法。
Canny边缘检测步骤:
消除噪声:一般情况使用高斯平滑滤波器卷积降噪
计算梯度幅值和方向:如下图所示:
非极大值抑制: 排除非边缘像素
滞后阈值: 滞后阈值需要两个阈值(高阈值和低阈值),如下所示:
1、如果某一像素位置的幅值超过高阈值,该像素被保留为边缘像素;
2、如果某一像素位置的幅值小于低阈值,该像素被排除;
3、如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留。
Canny边缘检测函数----Canny()
函数原型:
CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,
double threshold1, double threshold2,
int apertureSize=3, bool L2gradient=false );
src: 输入原图像(一般为单通道8位图像);
dst: 输出边缘图像要求和src一样的尺寸和类型(单通道);
threshold1: 滞后阈值低阈值(用于边缘连接);
threshold2: 滞后阈值高阈值(控制边缘初始段),推荐高低阈值比值在2:1到3:1之间;
apertureSize: 表示孔径大小, 默认值3;
L2gradient: 计算图像梯度幅值的标识;
Canny边缘检测效果:
(2)、Sobel算子
Sobel算子是一个主要用于边缘检测的离散微分算子, 它结合了高斯平滑和微分求导, 用来计算图像灰度函数的近似梯度。
计算过程:
Sobel边缘检测函数-----Sobel()
函数原型:
CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth,
int dx, int dy, int ksize=3,
double scale=1, double delta=0,
int borderType=BORDER_DEFAULT );
src: 输入原图像;
dst: 输出图像要求和src一样的尺寸和类型;
ddepth: 输出图像的深度, 支持如下组合:
dx: X方向上的差分阶数;
dy: Y方向上的差分阶数;
ksize: 默认值3, 表示Sobel核大小, 1,3,5,7;
scale: 计算导数值时的缩放因子, 默认值1, 表示不缩放;
delta(δ): 表示在结果存入目标图之前可选的delta值, 默认值0;
borderType: 边界模式, 一般采用默认。
代码如下:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image=imread("/Users/zhangxiaoyu/Desktop/1.png",0);//读取灰度图像
if(image.empty())
{
cout<<"Error!/n";
return -1;
}
cv::imshow("original image", image);
cv::Mat result;
cv::Mat grad_x,grad_y;
cv::Mat abs_grad_x,abs_grad_y;
//X方向
Sobel(image, grad_x ,CV_16S, 1,0,3,1,1,BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
cv::imshow("sobel-X image",abs_grad_x);
//Y方向
Sobel(image, grad_y ,CV_16S, 0,1,3,1,1,BORDER_DEFAULT);
convertScaleAbs(grad_y, abs_grad_y);
cv::imshow("sobel-Y image",abs_grad_y);
//合并
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, result);
cv::imshow("result image", result);
waitKey(0);
}
运行结果如下所示:
(3)、Laplacian算子
Laplacian算子是n维欧几里德中的一个二阶微分算子。
Laplacian算子的定义:
Laplacian边缘检测函数---Laplacian()
函数原型:
CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth,
int ksize=1, double scale=1, double delta=0,
int borderType=BORDER_DEFAULT );
src: 输入原图像(单通道8位图像);
dst: 输出边缘图像要求和src一样的尺寸和通道数;
ddepth: 目标图像的深度;
Ksize: 用于计算二阶导数的滤波器孔径大小, 须为正奇数, 默认值1;
scale: 可选比例因子, 默认值1;
delta: 可选参数δ, 默认值0;
borderType: 边界模式, 一般采用默认值。
代码如下:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image=imread("/Users/zhangxiaoyu/Desktop/1.png",0);//读取灰度图像
if(image.empty())
{
cout<<"Error!/n";
return -1;
}
cv::imshow("original image", image);
cv::Mat result;
Laplacian(image, result, CV_16S,3,1,0,BORDER_DEFAULT);
convertScaleAbs(result, result);
cv::imshow("Laplacian image", result);
waitKey(0);
}
结果如下: