【opencv学习笔记】018之Sobel算子与Scharr算子

目录

一、前言

二、算子

1、咋理解算子

2、算子定义

三、Sobel算子

1、讲解

2、API

3、代码展示

4、执行结果

四、Scharr算子

1、讲解

2、API

3、代码展示

4、执行结果


一、前言

继续填坑。

如果想看其他有关于OpenCV学习方法介绍、学习教程、代码实战、常见报错及解决方案等相关内容,可以直接看我的OpenCV分类:

【OpenCV系列】:https://blog.csdn.net/shuiyixin/article/category/7581855

如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧!

二、算子

1、咋理解算子

今天开始,我们来了解一下算子的概念,这个名字可能大家刚开始入门计算机视觉,会听到,但是会感觉别扭,就觉得,这是个啥?

听着不太对劲,是不是说错了?

其实呢,算子本身来源于数学。

啊!数学

啊!数学

啊!数学

如果你想掌控全世界,那你一定要会数学。

好,崇拜完数学之后,我们来了解一下算子。

简单来说,算子就是一个东西通过算子之后之后,变成了另一个东西。

这个熟悉不,大家想想函数,一个自变量的值,通过映射,得到了函数值。一个图像,经过卷积操作,变成另一个图像,一块肉,经过加工,变成了香肠

这样大家是不是就更容易理解啦。

 

2、算子定义

趁热打铁,我们来看一下算子的概念:

狭义的算子实际上是指从一个函数空间到另一个函数空间(或它自身)的映射

广义的算子的定义只要把上面的空间推广到一般空间,可以是向量空间,赋范向量空间,内积空间,或更进一步,Banach空间,Hilbert空间都可以。算子还可分为有界的与无界的,线性的与非线性的等等类别。

 

三、Sobel算子

1、讲解

讲完了算子,我们来说一个具体的算子Sobel算子,可以让大家理解地更深。

Sobel算子又叫索贝尔算子,是计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。Sobel算子是把图像中每个像素的上下左右四领域的灰度值加权差,在边缘处达到极值从而检测边缘

Sobel算子所采用的算法是先进行加权平均,然后进行微分运算,算子的计算方法如下:

对于一个二元函数f(x,y)来说,x有三个取值,y有三个取值,那我们就可以构造一个3×3的矩阵,矩阵的中心点为(x,y),向上向左为减一,向右向下为加一。我们用矩阵来表示一下上面的式子:

由此,我们设计两个核,一个是x方向上的,一个是y方向上的,设计的两个核是3×3的矩阵,分别是:

所以,如果对于一个图像I,我们能通过这两个核分别计算该图像X方向和Y方向的梯度:

我们也能根据两个方向的梯度计算总的梯度:

2、API

 

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 
);

函数参数含义如下:

(1)InputArray类型的src ,输入图像。

(2)OutputArray类型的dst ,输出图像,图像的大小、通道数和输入图像相同。

(3)int类型的ddepth,输出图像深度,请参阅@ref filter_depth“组合”;如果是8位输入图像,则会导致导数截断。

(4)int类型的dx,导数x的阶数。

(5)int类型的dy,导数y的阶数。

(6)int类型的ksize,扩展Sobel内核的大小;它必须是1、3、5或7。

(7)double类型的scale,计算派生值的可选比例因子;默认情况下,不应用缩放(有关详细信息,请参见cv::getDerivKernels。

(8)double类型的delta,在将筛选的像素存储到dst中之前添加到这些像素的可选值。说的有点专业了其实就是给所选的像素值添加一个值delta。

(9)int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT。

3、代码展示

在这里,我们用到一个很简单的函数:

void convertScaleAbs( 
    InputArray src, 
    OutputArray dst, 
    double alpha= 1,                       
    double belt= 0, 
);

我们这个函数只需要设置前两个参数,这个函数可以计算图像src的像素绝对值,输出到图像dst。

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
	Mat img, gx, gy, src;

	img = imread("E:/image/girl2.png");
	if (!img.data)
	{
		cout << "could not load image !";
		return -1;
	}
	imshow("【输入图像】", img);

	Sobel(img, gx, CV_16S, 1, 0);
	Sobel(img, gy, CV_16S, 0, 1);

	convertScaleAbs(gx, gx);
	convertScaleAbs(gy, gy);
	addWeighted(gx, 0.5, gy, 0.5, 0, src);
	imshow("【输出图像】", src);

	waitKey(0);
	return 0;
}

4、执行结果

原图
Sobel算子操作后

四、Scharr算子

1、讲解

当然,对导数比较熟悉的同学呢,我们都知道,导数是对于连续函数来说的,现在的这个不是连续的函数呀,所以这种方式,其实只是一个近似解。但是这种近似解,对于上面的来说又不是特别的精确,所以,在opencv中,采用更加精确的Scharr算子:

2、API

void Scharr( 
    InputArray src, 
    OutputArray dst, 
    int ddepth,  
    int dx,
    int dy,
    double scale = 1,                       
    double delta = 0, 
    int borderType = BORDER_DEFAULT 
);

函数参数含义如下:

(1)InputArray类型的src ,输入图像。

(2)OutputArray类型的dst ,输出图像,图像的大小、通道数和输入图像相同。

(3)int类型的ddepth,输出图像深度,请参阅@ref filter_depth“组合”;如果是8位输入图像,则会导致导数截断。

(4)int类型的dx,导数x的阶数。

(5)int类型的dy,导数y的阶数。

(6)double类型的scale,计算派生值的可选比例因子;默认情况下,不应用缩放(有关详细信息,请参见cv::getDerivKernels。

(7)double类型的delta,在将筛选的像素存储到dst中之前添加到这些像素的可选值。说的有点专业了其实就是给所选的像素值添加一个值delta。

(8)int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT。

 

3、代码展示

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
	Mat img, gx, gy, src;
	img = imread("E:/image/girl2.png");
	if (!img.data)
	{
		cout << "could not load image !";
		return -1;
	}
	imshow("【输入图像】", img);

	Scharr(img, gx, CV_16S, 1, 0);
	Scharr(img, gy, CV_16S, 0, 1);

	convertScaleAbs(gx, gx);
	convertScaleAbs(gy, gy);
	addWeighted(gx, 0.5, gy, 0.5, 0, src);
	imshow("【输出图像】", src);

	waitKey(0);
	return 0;
}

4、执行结果

原图
Scharr算子

大家也可以自己尝试一下呀,一定要多做练习!

发布了270 篇原创文章 · 获赞 534 · 访问量 54万+

猜你喜欢

转载自blog.csdn.net/shuiyixin/article/details/104484635