当前位置:网站首页>【OpenCV】-算子(Sobel、Canny、Laplacian)学习
【OpenCV】-算子(Sobel、Canny、Laplacian)学习
2022-07-29 08:19:00 【我菜就爱学】
开头一下:
本篇博客主要介绍边缘检测所涉及的三大算子,分别是Sobel算子、Canny算子、Laplacian算子)。上篇博客python版CV也介绍了这三个算子的用法。
文章目录
首先介绍一下边缘检测的步骤:
(1)滤波
边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能。常见的滤波方法主要有高斯滤波,即采用离散化的高斯函数产生一组归一化的高斯核,然后基于高斯核函数对图像灰度矩阵的每一点进行加权求和。
(2)增强
增强边缘的基础是确定图像各点邻域强度的变化值。增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。在具体编程通过梯度幅值来确定
(3)检测
经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是要找的边缘点,所以应该采用某种方法来对这些点进行取舍。实际工程中,常用的方法是通过阈值化方法来检测
1、sobel算子
1.1 sobel算子的基本概念
Sobel算子是一个主要用于边缘检测的离散微分算子。它结合了高斯平滑核微分求导,用来计算图像灰度函数的近视似梯度。在图像的任何一点使用此算子,都将会产生对于的梯度矢量或其法矢量
1.2 sobel算子的计算过程
(1)分别在x和y两个方向求导
水平变化:将I与一个奇数大小的内核Gx进行卷积。比如,当内核大小为3时,Gx的计算结果:
G x = I 3 − I 1 + 2 ∗ I 6 − 2 ∗ I 4 + I 9 − I 7 Gx=I3-I1+2*I6-2*I4+I9-I7 Gx=I3−I1+2∗I6−2∗I4+I9−I7垂直变化:将I与一个奇数大小的内核进行卷积。比如,当内核大小为3时,Gx的计算结果:
G y = I 3 − 2 ∗ I 2 − I 1 + I 9 + 2 ∗ I 8 + I 7 Gy=I3-2*I2-I1+I9+2*I8+I7 Gy=I3−2∗I2−I1+I9+2∗I8+I7
(2)在图像的每一点,结合以上两个今儿个求出近似梯度:
G = s q r t ( G x 2 + G y 2 ) G=sqrt(Gx^2+Gy^2) G=sqrt(Gx2+Gy2)
有时也可以用下面公式代替:
G = ∣ G x ∣ + ∣ G y ∣ G=|Gx|+|Gy| G=∣Gx∣+∣Gy∣
1.3 使用Sobel算子:Sobel()函数
void Sobel(InputArray src,OutputArray dst,int ddepth,int dx,int dy,
int kszie=3,double scale=1,double delta=0,
int borderType=BORDER_DEFAULT);
第一个参数:输入图像,填Mat类型即可
第二个参数:目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型
第三个参数:输出图像的深度,支持如下组合:
- 若src.depth()=CV_8U,取ddepth=-1/CV_16S/CV_32F/CV_64F
- 若src.depth()=CV_16U/CV_16S,取ddepth=-1/CV_32F/CV_64F
- 若src.depth()=CV_32F,取ddepth=-1/CV_32F/CV_64F
- 若src.depth()=CV_64F,取ddepth=-1/CV_64F
第四个参数:x方向上的差分阶数
第五个参数:y方向上的差分阶数
第六个参数:核大小,取1,3,5,7
第七个参数:double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。
第八个参数:double类型的delta,表示存入目标图
第九个参数:边界模式。有默认值:BORDER_DEFAULT
补充说明:
(1)当内核大小为3时,Sobel内核可能产生比较明显的误差。所以OpenCV提供了Scharr函数,但该函数仅作用于大小为3的内核。比Sobel函数的结果更加精确
(2)Sobel算子结合了高斯平滑核分化,因此结果会具有更多的抗噪性:
计算图像X方向的导数,取【xorder=1,yorder=0,ksize=3】,对应内核:
计算图像Y方向的导数,取【xorder=0,yorder=1,ksize=3】,对应内核:
1.4 示例程序
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
//创建grad_x和grad_y矩阵
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y, dst;
//载入原始图
Mat src = imread("E:\\Pec\\fushiyuan.jpg");
imshow("【原始图】", src);
//求X方向的梯度
Sobel(src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
//白到黑是正数,黑到白是负数,所有的负数都会截断成0,所以要取绝对值
convertScaleAbs(grad_x, abs_grad_x);
imshow("【效果图】X方向Sobel", abs_grad_x);
//求Y方向的梯度
Sobel(src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
//白到黑是正数,黑到白是负数,所有的负数都会截断成0,所以要取绝对值
convertScaleAbs(grad_y, abs_grad_y);
imshow("【效果图】Y方向Sobel", abs_grad_y);
//合并梯度
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
imshow("【效果图】正题方向", dst);
waitKey(0);
}
2、canny算子
2.1 Canny边缘检测的步骤
(1)【第一步】图像灰度化
canny算法处理的图像为灰度图,因此如果摄像机获取的是彩色图像,那首先就得进行灰度化。对一幅彩色图进行灰度化,就是根据图像各个通道的采样值进行加权平均。
G a r y = ( R + G + B ) / 3 Gary=(R+G+B)/3 Gary=(R+G+B)/3
(2)【第二步】消除噪声
一般情况下,使用高斯平滑滤波器卷积降噪,以下显示一个size=5的高斯内核示例:
(3)【第三步】计算梯度幅值和方向
此处:按照Sobel滤波器的步骤来操作,索贝尔算子(Sobel
operator)是图像处理的算子之一,主要用作边缘检测。技术上是离散型差分算子,用来运算图像亮度函数的梯度之近视值。
运用一对卷积阵列(分别作用于x和y方向)
使用下列公式计算梯度赋值和方向,梯度方向取的角度一般是0°,45°,90°,135°
(3)【第三步】非极大值抑制
这一步排除边缘像素,仅仅保留了一些细线条(候选边缘)。在求出的幅值图像中,可能存在多个较大幅值临近的情况,但真正的边缘点只有一个,针对这样的情况进行非极大值抑制,找出局部最大值,从而可以剔除大部分非边缘点。
(4)【第四步】滞后阈值
这是最后一步,Canny使用滞后阈值,滞后阈值需要两个阈值(高阈值和低阈值):
- 若某一像素位置的幅值超过高阈值,该像素被保留为边缘像素
- 若某一像素位置的幅值小于低阈值,该像素排除
- 若某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留
2.2 Canny边缘检测:Canny()函数
void Canny(InputArray image,OutputArray edges,double threshold1,double threshold2,int apertureSize=3,
bool L2gradient=false)
- 第一个参数:输入图像,即源图像,填Mat类的对象即可,且需为单通道8为图像
- 第二个参数:输出的边缘图,需要和源图片有一样的尺寸和类型
- 第三个参数:第一个滞后阈值
- 第四个参数:第二个滞后阈值
- 第五个参数:int类型的 apertureSize,表示应用Sobel算子的孔径大小,其默认值3
- 第六个参数:bool 类型的L2gradient,一个计算图像梯度幅值的标识,有默认值false
注意:函数阈值1和阈值2两者较小的值用于边缘连接,而较大的值用来控制强边缘的初始段,推荐的高低阈值比在2 :1到3 :1之间
2.3 示例程序
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
//载入原始图
Mat src = imread("E:\\Pec\\灭霸.jpg");
Mat src1 = src.clone();
imshow("【原始图】", src);
Mat dst,dst1, edge, gray;
//创建与src同样类型和大小的矩阵
dst.create(src.size(), src1.type());
//将原图转换为灰度图像
cvtColor(src1, gray, COLOR_BGR2GRAY);
//先使用3x3内核来降噪
blur(gray, edge, Size(3, 3));
//运行Canny算子
Canny(gray, edge, 3, 9, 3);
//将dst内的所有元素设置为0
dst = Scalar::all(0);
dst1 = Scalar::all(0);
gray.copyTo(dst, edge);
src1.copyTo(dst1, edge);
imshow("【彩色检测图】", dst1);
imshow("【灰度检测图】", dst);
waitKey(0);
return 0;
}
3、Laplacian算子
3.1 Laplacian算子简介
Laplacian算子是n维欧几里得空间中的一个二阶微分算子,定义为梯度grad的散度div。因此如果f是二阶可微的实函数,则f的拉普拉斯算子定义如下:
(1)f是拉普拉斯算子,也是笛卡坐标系xi中的所有非混合二阶偏导数求和
(2)作为一个二阶微分算子,拉普拉斯算子把C函数映射到C函数。根据图像处理的原理可知,二阶导数可以用来进行检测边缘。因为图像是“二维”,需要在两个方向进行求导。
3.2 拉普拉斯变换:Laplacian()函数
void Laplacian(InputArray src,OutputArray dst,int ddepth,int ksize=1,double scale=1,double delta=0,
intborderType=BORDER_DEFAULT);
第一个参数:输入图像,填Mat类型即可
第二个参数:目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型
第三个参数:目标图像的深度
- 若src.depth()=CV_8U,取ddepth=-1/CV_16S/CV_32F/CV_64F
- 若src.depth()=CV_16U/CV_16S,取ddepth=-1/CV_32F/CV_64F
- 若src.depth()=CV_32F,取ddepth=-1/CV_32F/CV_64F
- 若src.depth()=CV_64F,取ddepth=-1/CV_64F
第四个参数:int类型的ksize,用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数,默认值为1
第五个参数:double类型的scale,计算拉普拉斯值的时候可选的比例因子,默认值1
第六个参数:doubel类型的delta,表示在结果存入目标图,默认值0
第七个参数:边界模式,默认值为BORDER_DEFAULT
注意:Laplacian()函数主要利用sobel算子的运算。
3.3 示例程序
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat src_gray,dst, abs_dst;
//载入原始图
Mat src = imread("E:\\Pec\\fushi.jpg");
imshow("【原始图】", src);
//使用高斯滤波消除噪声
GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
//转为灰度图
cvtColor(src, src_gray, COLOR_RGB2GRAY);
//使用拉普拉斯函数
Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
//计算绝对值,并将结果转换成8位
convertScaleAbs(dst, abs_dst);
imshow("【效果图】", abs_dst);
waitKey(0);
return 0;
}
边栏推荐
- Preparation of SQL judgment statement
- [beauty of software engineering - column notes] "one question and one answer" issue 2 | 30 common software development problem-solving strategies
- Ga-rpn: recommended area network for guiding anchors
- node:文件写入数据(readFile、writeFile),覆盖与增量两种模式
- 数仓分层设计及数据同步问题,,220728,,,,
- Tle5012b+stm32f103c8t6 (bluepill) reading angle data
- Node: file write data (readfile, WriteFile), two modes: overwrite and increment
- [robomaster] control RM motor from scratch (2) -can communication principle and electric regulation communication protocol
- Qt/PyQt 窗口类型与窗口标志
- BiSeNet v2
猜你喜欢
node:文件写入数据(readFile、writeFile),覆盖与增量两种模式
[beauty of software engineering - column notes] 30 | make good use of source code management tools to make your collaboration more efficient
Proteus simulation based on msp430f2491 (realize water lamp)
Time function in MySQL
简易计算器微信小程序项目源码
Data warehouse layered design and data synchronization,, 220728,,,,
Proteus simulation based on msp430f2491
Privacy is more secure in the era of digital RMB
Preparation of SQL judgment statement
(Video + graphic) machine learning introduction series - Chapter 5 machine learning practice
随机推荐
Gan: generate adversarial networks
sql判断语句的编写
HC-SR04超声波测距模块使用方法和例程(STM32)
What is Amazon self support number and what should sellers do?
Implementation of simple matcap+fresnel shader in unity
Simplefoc parameter adjustment 1-torque control
commonjs导入导出与ES6 Modules导入导出简单介绍及使用
DC motor speed regulation system based on 51 single chip microcomputer (use of L298)
Chapter contents of the romance of the Three Kingdoms
TCP——滑动窗口
AES 双向加密解密工具
Unity Shader学习(六)实现雷达扫描效果
RPC和REST
PostgreSQL手动创建HikariDataSource解决报错Cannot commit when autoCommit is enabled
torch.nn.functional.one_ hot()
UE4 highlight official reference value
Lora opens a new era of Internet of things -asr6500s, asr6501/6502, asr6505, asr6601
Simulation of four way responder based on 51 single chip microcomputer
Process and concept of process
PostgreSQL manually creates hikaridatasource to solve the error cannot commit when autocommit is enabled