OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

一.卷积核的概念

卷积核,通常也叫算子。用一个设定数值模板去处理一张输入图片,进行卷积运算。目的是使目标与目标之间的差距变得更大。卷积在数字图像处理中最常见的应用为锐化和边缘提取。

边缘提取:
当前景目标像素值与周边背景目标的像素值有较大差异时,可以通过卷积核对原图矩阵中的这个位置进行卷积运算,得出的值和该像素点原来的灰度值会产生显著的差异。变化的值超过我们预设的范围后,就可以将图像进行阈值处理,将图像的差异最大化,可以得到了一黑色为背景,白色线条作为边缘或形状的边缘提取效果图。

锐化算子:
通过卷积运算,可以增大矩阵每一个元素与周边元素的反差,起到锐化作用。图像锐化是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空间域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征,也被称为边缘增强。

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

=========================================================================

二.图像卷积的运算原理

卷积核作为一个设定数值模板矩阵,输入的待处理的图像作为原型矩阵,二者进行图像卷积运算,主要是使模板矩阵的中心像素点(称之为锚点)覆盖在待计算原型矩阵元素上面,中心像素点逐一对齐原型矩阵上的像素点(边缘像素无法对齐锚点,也就无法进行卷积计算,只能通过边缘像素处理后才能进行卷积),然后计算元素值与被覆盖的卷积核中的值的乘积和。将这个和赋值给当前锚点,这就是卷积的运算过程。 ​​​

——————————————————————————————————————————–

第一类:Sobel算子

Sobel算子的概念
Sobel算子是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度。sobel算子由两个3X3的卷积核构成,分别用于计算中心像素邻域的灰度加权差。分为垂直方向和水平方向的索伯滤波器Gx 和Gy。Soble算子功能集合高斯平滑和微分求导,又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方法与Y方向梯度图像,如下图。

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用
#参数说明:
I 代表输入图像产生的图像矩阵,
Gx及Gy 分别代表经横向及纵向边缘检测的图像灰度值
G 表示图像的每一个像素的横向及纵向灰度值,有两种计算方式,通常Gx和Gy开方运算比较复杂

——————————————————————————————————————-

Sobel算子的卷积计算过程
为计算图像x方向上的梯度图像,我们需要一个卷积核kernel(Gx)和3*3的像素图片矩阵P。

#卷积核kernel和图像 P
Mat kernel = (Mat_<char>(3, 3) << -1&#xFF0C;0&#xFF0C;+1&#xFF0C;-2&#xFF0C;0&#xFF0C;+2&#xFF0C;-1&#xFF0C;0&#xFF0C;+1);
Mat P       = (Mat_<char>(3, 3) <<p1,p2,p3,p4,p5,p6,p7,p8,p9); < code></p1,p2,p3,p4,p5,p6,p7,p8,p9);></char></char>

以卷积核模板的中心像素为锚点,将卷积核与图像上像素值一一对应进行像素遍历,卷积核上的数字相当于加权系数。利用如下公式即可计算出卷积核中心的x方向梯度。

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

卷积计算过程为:P5 = (P3-P1)+2*(P6-P4)+(P9-P7)

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

同样的原理,在Gy方向上的梯度计算也可以求取
卷积计算过程为:P5 = (P7-P1)+2*(P8-P2)+(P9-P3),这样就得到了垂直方向和水平方向的图像梯度Gx 和Gy,就可以求出总的图像梯度,通常取|Gx| + |Gy|的和作为总的图像梯度。

———————————————————————————————————————————

Sobel算子API函数接口:

#&#x51FD;&#x6570;API&#x63A5;&#x53E3;&#xFF1A;

cv::Sobel (
InputArray Src // &#x8F93;&#x5165;&#x56FE;&#x50CF;
OutputArray dst// &#x8F93;&#x51FA;&#x56FE;&#x50CF;&#xFF0C;&#x5927;&#x5C0F;&#x4E0E;&#x8F93;&#x5165;&#x56FE;&#x50CF;&#x4E00;&#x81F4;
int depth // &#x8F93;&#x51FA;&#x56FE;&#x50CF;&#x6DF1;&#x5EA6;.

Int dx.  // X&#x65B9;&#x5411;&#xFF0C;&#x51E0;&#x9636;&#x5BFC;&#x6570;
int dy // Y&#x65B9;&#x5411;&#xFF0C;&#x51E0;&#x9636;&#x5BFC;&#x6570;.

int ksize, SOBEL&#x7B97;&#x5B50;kernel&#x5927;&#x5C0F;&#xFF0C;&#x5FC5;&#x987B;&#x662F;1&#x3001;3&#x3001;5&#x3001;7&#x3001;
double scale  = 1
double delta = 0
int borderType = BORDER_DEFAULT
)

参数说明:

第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。
第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,要求与源图片有一样的尺寸和类型。
第三个参数,int类型的ddepth,输出图像的深度,目标图像的深度必须大于原图像的深度,支持如下src.depth()和ddepth的组合:

&#x82E5;src.depth() = CV_8U, &#x53D6;ddepth =-1/CV_16S/CV_32F/CV_64F
&#x82E5;src.depth() = CV_16U/CV_16S, &#x53D6;ddepth =-1/CV_32F/CV_64F
&#x82E5;src.depth() = CV_32F, &#x53D6;ddepth =-1/CV_32F/CV_64F
&#x82E5;src.depth() = CV_64F, &#x53D6;ddepth = -1/CV_64F

第四个参数,int类型的dx,x 方向上的差分阶数。
第五个参数,int类型的dy,y方向上的差分阶数。
第六个参数,int类型ksize,有默认值3,表示Sobel核的大小; 必须取1,3,5或7奇数的核。
第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
第九个参数, int类型的borderType,边界模式,默认值为BORDER_DEFAULT。

enum BorderTypes {
&#xA0; &#xA0; BORDER_CONSTANT &#xA0; &#xA0;= 0, //&#x4F7F;&#x7528;&#x6307;&#x5B9A;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_REPLICATE &#xA0; = 1, //&#x7528;&#x5DF2;&#x77E5;&#x7684;&#x8FB9;&#x7F18;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_REFLECT &#xA0; &#xA0; = 2, //&#x4F7F;&#x7528;&#x5DF2;&#x77E5;&#x7684;&#x8FB9;&#x7F18;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x53CD;&#x8F6C;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_WRAP &#xA0; &#xA0; &#xA0; &#xA0;= 3, //&#x7528;&#x53E6;&#x5916;&#x4E00;&#x8FB9;&#x7684;&#x50CF;&#x7D20;&#x6765;&#x8865;&#x507F;&#x586B;&#x5145;
&#xA0; &#xA0; BORDER_REFLECT_101 = 4, //&#x4F7F;&#x7528;&#x5DF2;&#x77E5;&#x7684;&#x8FB9;&#x7F18;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x53CD;&#x8F6C;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_TRANSPARENT = 5, //&#x4F7F;&#x7528;&#x9ED1;&#x8272;&#x8FDB;&#x884C;&#x586B;&#x5145;&#xFF0C;&#x672C;&#x8D28;&#x4E0A;&#x5C31;&#x662F;&#x586B;&#x5145;0
&#xA0;
&#xA0; &#xA0; BORDER_REFLECT101 &#xA0;= BORDER_REFLECT_101,
&#xA0; &#xA0; BORDER_DEFAULT &#xA0; &#xA0; = BORDER_REFLECT_101,
&#xA0; &#xA0; BORDER_ISOLATED &#xA0; &#xA0;= 16 //

——————————————————————————————————————————–

注意知识点:

1.图像在经过处理后,需要用cv::函数将其转回原来的uint8形式,否则将无法显示图像,而只是一副灰色的窗口。

convertScaleAbs()函数原型:

void cv::convertScaleAbs(
2     cv::InputArray src, // &#x8F93;&#x5165;&#x6570;&#x7EC4;
3     cv::OutputArray dst, // &#x8F93;&#x51FA;&#x6570;&#x7EC4;
4     double alpha = 1.0, // &#x4E58;&#x6570;&#x56E0;&#x5B50;
5     double beta = 0.0 // &#x504F;&#x79FB;&#x91CF;
6 );

      //&#x7ED3;&#x679C;&#x8FD4;&#x56DE;uint8&#x7C7B;&#x578B;&#x7684;&#x56FE;&#x7247;

功能:实现将原图片转换为uint8类型

2.由于Sobel算子是在X轴,Y轴两个方向计算的,还需要用cv2.addWeighted()函数将其组合起来

函数原型:

CV_EXPORTS_W void addWeighted(InputArray src1, double alpha, InputArray src2,

double beta, double gamma, OutputArray dst, int dtype=-1);

src1: &#x7B2C;&#x4E00;&#x5E45;&#x8F93;&#x5165;&#x56FE;&#x50CF;
alpha: &#x7EBF;&#x6027;&#x6DF7;&#x5408;&#x65F6;&#x7B2C;&#x4E00;&#x5E45;&#x56FE;&#x50CF;&#x7684;&#x6743;&#x91CD;
src2: &#x7B2C;&#x4E8C;&#x5E45;&#x8F93;&#x5165;&#x56FE;&#x50CF;
beta: &#x7B2C;&#x4E8C;&#x5E45;&#x8F93;&#x5165;&#x56FE;&#x50CF;&#x7684;&#x6743;&#x91CD;
dst: &#x56FE;&#x50CF;&#x7EBF;&#x6027;&#x6DF7;&#x5408;&#x540E;&#x7684;&#x76EE;&#x6807;&#x56FE;&#x50CF;
gamma: &#x6DFB;&#x52A0;&#x5230;&#x6BCF;&#x4E00;&#x4E2A;&#x7EBF;&#x6027;&#x53E0;&#x52A0;&#x603B;&#x548C;&#x7684;gamma&#x503C;
dtype: &#x76EE;&#x6807;&#x56FE;&#x50CF;&#x6DF1;&#x5EA6;&#xFF0C;&#x5F53;&#x4E24;&#x5E45;&#x56FE;&#x50CF;&#x6DF1;&#x5EA6;&#x76F8;&#x540C;&#x65F6;&#x53EF;&#x4EE5;&#x5C06;dtype&#x7F6E;&#x4E3A;-1,&#x8FD9;&#x6837;&#x76EE;&#x6807;&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;&#x5C06;&#x4E0E;&#x8F93;&#x5165;&#x56FE;&#x50CF;&#x76F8;&#x540C;

&#x5176;&#x4E2D;beta - (1.0 - alpha);
&#x5BF9;&#x4E8E;&#x6BCF;&#x4E2A;&#x50CF;&#x7D20;&#x70B9;&#x5176;&#x8BA1;&#x7B97;&#x516C;&#x5F0F;&#x5982;&#x4E0B;&#xFF1A;
dst = a&#xD7;src1+b&#xD7;src2+r

功能:实现以不同的权重将两幅图片叠加,对于不同的权重,叠加后的图像会有不同的透明度

=========================================================================

第二类: Scharr算子

Scharr算子比Sobel算子的值更大,是在Sorbel算子基础上改进的,因此对于灰度变化更为敏感,会得到较强的边缘强度,但是也会损失一些细节。

cv::Scharr (
InputArray Src // &#x8F93;&#x5165;&#x56FE;&#x50CF;
OutputArray dst// &#x8F93;&#x51FA;&#x56FE;&#x50CF;&#xFF0C;&#x5927;&#x5C0F;&#x4E0E;&#x8F93;&#x5165;&#x56FE;&#x50CF;&#x4E00;&#x81F4;
int depth // &#x8F93;&#x51FA;&#x56FE;&#x50CF;&#x6DF1;&#x5EA6;.

Int dx.  // X&#x65B9;&#x5411;&#xFF0C;&#x51E0;&#x9636;&#x5BFC;&#x6570;
int dy // Y&#x65B9;&#x5411;&#xFF0C;&#x51E0;&#x9636;&#x5BFC;&#x6570;.

double scale  = 1
double delta = 0
int borderType = BORDER_DEFAULT
)

&#x7B2C;&#x4E00;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;InputArray &#x7C7B;&#x578B;&#x7684;src&#xFF0C;&#x4E3A;&#x8F93;&#x5165;&#x56FE;&#x50CF;&#xFF0C;&#x586B;Mat&#x7C7B;&#x578B;&#x5373;&#x53EF;&#x3002;
&#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;OutputArray&#x7C7B;&#x578B;&#x7684;dst&#xFF0C;&#x5373;&#x76EE;&#x6807;&#x56FE;&#x50CF;&#xFF0C;&#x51FD;&#x6570;&#x7684;&#x8F93;&#x51FA;&#x53C2;&#x6570;&#xFF0C;&#x8981;&#x6C42;&#x4E0E;&#x6E90;&#x56FE;&#x7247;&#x6709;&#x4E00;&#x6837;&#x7684;&#x5C3A;&#x5BF8;&#x548C;&#x7C7B;&#x578B;&#x3002;
&#x7B2C;&#x4E09;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;int&#x7C7B;&#x578B;&#x7684;ddepth&#xFF0C;&#x8F93;&#x51FA;&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;&#xFF0C;&#x76EE;&#x6807;&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;&#x5FC5;&#x987B;&#x5927;&#x4E8E;&#x539F;&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;&#xFF0C;&#x652F;&#x6301;&#x5982;&#x4E0B;src.depth()&#x548C;ddepth&#x7684;&#x7EC4;&#x5408;&#xFF1A;
    BORDER_CONSTANT &#xA0; &#xA0;= 0, //&#x4F7F;&#x7528;&#x6307;&#x5B9A;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_REPLICATE &#xA0; = 1, //&#x7528;&#x5DF2;&#x77E5;&#x7684;&#x8FB9;&#x7F18;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_REFLECT &#xA0; &#xA0; = 2, //&#x4F7F;&#x7528;&#x5DF2;&#x77E5;&#x7684;&#x8FB9;&#x7F18;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x53CD;&#x8F6C;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_WRAP &#xA0; &#xA0; &#xA0; &#xA0;= 3, //&#x7528;&#x53E6;&#x5916;&#x4E00;&#x8FB9;&#x7684;&#x50CF;&#x7D20;&#x6765;&#x8865;&#x507F;&#x586B;&#x5145;
&#xA0; &#xA0; BORDER_REFLECT_101 = 4, //&#x4F7F;&#x7528;&#x5DF2;&#x77E5;&#x7684;&#x8FB9;&#x7F18;&#x50CF;&#x7D20;&#x503C;&#x6765;&#x53CD;&#x8F6C;&#x586B;&#x5145;&#x8FB9;&#x7F18;
&#xA0; &#xA0; BORDER_TRANSPARENT = 5, //&#x4F7F;&#x7528;&#x9ED1;&#x8272;&#x8FDB;&#x884C;&#x586B;&#x5145;&#xFF0C;&#x672C;&#x8D28;&#x4E0A;&#x5C31;&#x662F;&#x586B;&#x5145;0

&#x7B2C;&#x56DB;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;int&#x7C7B;&#x578B;&#x7684;dx&#xFF0C;x &#x65B9;&#x5411;&#x4E0A;&#x7684;&#x5DEE;&#x5206;&#x9636;&#x6570;&#x3002;
&#x7B2C;&#x4E94;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;int&#x7C7B;&#x578B;&#x7684;dy&#xFF0C;y&#x65B9;&#x5411;&#x4E0A;&#x7684;&#x5DEE;&#x5206;&#x9636;&#x6570;&#x3002;
&#x7B2C;&#x516D;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;int&#x7C7B;&#x578B;ksize&#xFF0C;&#x6709;&#x9ED8;&#x8BA4;&#x503C;3&#xFF0C;&#x8868;&#x793A;Sobel&#x6838;&#x7684;&#x5927;&#x5C0F;; &#x5FC5;&#x987B;&#x53D6;1&#xFF0C;3&#xFF0C;5&#x6216;7&#x5947;&#x6570;&#x7684;&#x6838;&#x3002;
&#x7B2C;&#x4E03;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;double&#x7C7B;&#x578B;&#x7684;scale&#xFF0C;&#x8BA1;&#x7B97;&#x5BFC;&#x6570;&#x503C;&#x65F6;&#x53EF;&#x9009;&#x7684;&#x7F29;&#x653E;&#x56E0;&#x5B50;&#xFF0C;&#x9ED8;&#x8BA4;&#x503C;&#x662F;1&#xFF0C;&#x8868;&#x793A;&#x9ED8;&#x8BA4;&#x60C5;&#x51B5;&#x4E0B;&#x662F;&#x6CA1;&#x6709;&#x5E94;&#x7528;&#x7F29;&#x653E;&#x7684;&#x3002;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x5728;&#x6587;&#x6863;&#x4E2D;&#x67E5;&#x9605;getDerivKernels&#x7684;&#x76F8;&#x5173;&#x4ECB;&#x7ECD;&#xFF0C;&#x6765;&#x5F97;&#x5230;&#x8FD9;&#x4E2A;&#x53C2;&#x6570;&#x7684;&#x66F4;&#x591A;&#x4FE1;&#x606F;&#x3002;
&#x7B2C;&#x516B;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;double&#x7C7B;&#x578B;&#x7684;delta&#xFF0C;&#x8868;&#x793A;&#x5728;&#x7ED3;&#x679C;&#x5B58;&#x5165;&#x76EE;&#x6807;&#x56FE;&#xFF08;&#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;dst&#xFF09;&#x4E4B;&#x524D;&#x53EF;&#x9009;&#x7684;delta&#x503C;&#xFF0C;&#x6709;&#x9ED8;&#x8BA4;&#x503C;0&#x3002;
&#x7B2C;&#x4E5D;&#x4E2A;&#x53C2;&#x6570;&#xFF0C; int&#x7C7B;&#x578B;&#x7684;borderType&#xFF0C;&#x8FB9;&#x754C;&#x6A21;&#x5F0F;&#xFF0C;&#x9ED8;&#x8BA4;&#x503C;&#x4E3A;BORDER_DEFAULT&#x3002;

=========================================================================

第三类:拉普拉斯( Laplance )算子

拉普拉斯 算子原理

拉普拉斯算子(Laplance operator) 边缘提取的数学依据:在二阶导数的时候,最大变化处的值为零即边缘是零值。计算图像二阶导数,可以用来梯度计算、提取边缘、检测边缘。

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

Laplacian提取边缘流程

1)高斯模糊 – 去噪声GaussianBlur()
GaussianBlur(src, dst, Size(3, 3), 0, 0); //高斯模糊
2)转灰度 – cvtColor()
cvtColor(dst, gray_src, CV_BGR2GRAY); //转灰度
3)拉普拉斯 – 二阶导数计算Laplacian()
Laplacian(gray_src, edge_image, CV_16S, 3); //Laplacian算子
4)取绝对值 – convertScaleAbs() – 此处即可得到边缘图像
convertScaleAbs(edge_image, edge_image); //取绝对值
5)再二值化阈值处理 – 增强边缘特征threshold() – 边缘图像更明显
threshold(edge_image, edge_image, 0, 255, THRESH_BINARY | THRESH_OTSU);//自动计算二值化otsu阈值,忽略输入的阈值

——————————————————————————————————————————–

Laplacian算子API函数接口

void Laplacian(InputArray src, OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT )
&#x53C2;&#x6570;&#x8BF4;&#x660E;&#xFF1A;

&#x524D;&#x4E24;&#x4E2A;&#x662F;&#x5FC5;&#x987B;&#x7684;&#x53C2;&#x6570;&#xFF1A;
&#x7B2C;&#x4E00;&#x4E2A;&#x53C2;&#x6570;&#x662F;&#x8F93;&#x5165;&#x7684;&#x539F;&#x56FE;&#x50CF;&#xFF0C;Mat&#x7C7B;&#x578B;&#x7684;&#x56FE;&#x7247;&#xFF1B;
&#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;&#x662F;&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;&#xFF0C;-1&#x8868;&#x793A;&#x4E0E;&#x539F;&#x56FE;&#x50CF;&#x76F8;&#x540C;&#x6DF1;&#x5EA6;&#x3002;&#x76EE;&#x6807;&#x56FE;&#x50CF;&#x6DF1;&#x5EA6;&#x5FC5;&#x987B;&#x5927;&#x4E8E;&#x7B49;&#x4E8E;&#x539F;&#x56FE;&#x50CF;&#x6DF1;&#x5EA6;&#xFF1B;

&#x5176;&#x540E;&#x662F;&#x53EF;&#x9009;&#x7684;&#x53C2;&#x6570;&#xFF1A;
&#x7B2C;&#x4E09;&#x4E2A;&#x53C2;&#x6570;dst&#x76EE;&#x6807;&#x56FE;&#x50CF;&#xFF0C;Mat&#x7C7B;&#x578B;&#x7684;&#x56FE;&#x7247;&#xFF1B;
&#x7B2C;&#x56DB;&#x4E2A;&#x53C2;&#x6570;ksize&#x662F;&#x7B97;&#x5B50;&#x7684;&#x5927;&#x5C0F;&#xFF0C;&#x5FC5;&#x987B;&#x4E3A;1&#x3001;3&#x3001;5&#x3001;7&#x3002;&#x9ED8;&#x8BA4;&#x4E3A;1&#x3002;
&#x7B2C;&#x4E94;&#x4E2A;&#x53C2;&#x6570;scale&#x662F;&#x7F29;&#x653E;&#x5BFC;&#x6570;&#x7684;&#x6BD4;&#x4F8B;&#x5E38;&#x6570;&#xFF0C;&#x9ED8;&#x8BA4;&#x65E0;&#x4F38;&#x7F29;&#x7CFB;&#x6570;&#xFF1B;
&#x7B2C;&#x516D;&#x4E2A;&#x53C2;&#x6570;delta&#x662F;&#x53EF;&#x9009;&#x589E;&#x91CF;&#xFF0C;&#x4F1A;&#x52A0;&#x5230;&#x6700;&#x7EC8;&#x7684;dst&#x4E2D;&#xFF0C;&#x9ED8;&#x8BA4;&#x60C5;&#x51B5;&#x4E0B;&#x65E0;&#x989D;&#x5916;&#x7684;&#x503C;&#x52A0;dst&#xFF1B;
&#x7B2C;&#x4E03;&#x4E2A;&#x53C2;&#x6570;borderType&#x662F;&#x5224;&#x65AD;&#x56FE;&#x50CF;&#x8FB9;&#x754C;&#x6A21;&#x5F0F;&#x3002;&#x7F3A;&#x7701;cv.BORDER_DEFAULT&#x3002;

=========================================================================

代码实现:

#include"stdafx.h"
#include<opencv2 opencv.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;

int main(int argc, char**argv)
{
    Mat src, gray_src, dst, dst2;
    src = imread("F:/photo/qx.jpg");
    if (!src.data) {
        printf("can naot load the image ...\n");
        return -1;
    }
    char input_title[] = "input_picture";
    char output_title[] = "sobel demo2";
    namedWindow(input_title, WINDOW_AUTOSIZE);
    imshow(input_title, src);//&#x8F93;&#x51FA;&#x539F;&#x56FE;&#x50CF;

    GaussianBlur(src, dst, Size(3, 3), 0, 0);//&#x9AD8;&#x65AF;&#x6A21;&#x7CCA;
    cvtColor(dst, gray_src, COLOR_BGR2GRAY);//&#x8F93;&#x51FA;&#x7070;&#x5EA6;&#x56FE;
    imshow("gray_picture", gray_src);

    Mat xgrad, ygrad;
    Sobel(gray_src, xgrad, CV_32F, 1, 0,3);//x&#x65B9;&#x5411;
    Sobel(gray_src, ygrad, CV_32F, 0, 1,3);//y&#x65B9;&#x5411;

    Mat xygrad_0;
    convertScaleAbs(xgrad, xgrad);//&#x53D6;&#x7EDD;&#x5BF9;&#x503C;
    convertScaleAbs(ygrad, ygrad);
    imshow("xgrad", xgrad);
    imshow("ygrad", ygrad);        //&#x53E0;&#x52A0;&#x56FE;&#x50CF;&#x8F93;&#x51FA;

    addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad_0,-1);
    imshow("sobel_addweight", xygrad_0);
    imwrite("sobel_demo1.jpg", xygrad_0);

    //&#x624B;&#x52A8;&#x5B9E;&#x73B0;&#x878D;&#x5408;
    Mat xygrad_2 = Mat(xgrad.size(), xgrad.type());
    int width = xgrad.cols;
    int height = ygrad.rows;
    for (int row = 0; row < height; row++) {
        for (int col = 0; col <width; col++) { int xg="xgrad.at<uchar">(row, col);
            int yg = ygrad.at<uchar>(row, col);
            int xy = xg + yg;
            xygrad_2.at<uchar>(row, col) = saturate_cast<uchar>(xy);
        }
    }
    imshow(output_title, xygrad_2);
    imwrite("sobel_demo2.jpg", xygrad_2);

    Mat xgrad_1, ygrad_1;
    Scharr(gray_src, xgrad_1, CV_32F, 1, 0);
    Scharr(gray_src, ygrad_1, CV_32F, 0, 1);
    convertScaleAbs(xgrad_1, xgrad_1);//&#x53D6;&#x7EDD;&#x5BF9;&#x503C;
    convertScaleAbs(ygrad_1, ygrad_1);
    addWeighted(xgrad_1, 0.5, ygrad_1, 0.5, 0, dst2, -1);
    imshow("scharr_demo", dst2);
    imwrite("scharr_demo.jpg", dst2);
    imshow("schaar_xaddweight", xgrad_1);
    imshow("schaar_yaddweight", ygrad_1);

    waitKey(0);
    return 0;
}

</uchar></uchar></uchar></width;></math.h></iostream></opencv2>

图像处理效果:

Sorbel算子图像边缘提取部分

输入原图和灰度图

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

Sorbel算子在X方向的梯度和Y方向的梯度以及addWeighted()整合后的图像

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

手动融合的Sorbel图像的图像梯度效果会比ddWeighted()整合后的图像强很多

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

=========================================================================

Scharr算子图像边缘提取部分

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

Scharr算子图像边缘提取与 Sorbel算子图像边缘提取的比较,可以看出, Scharr算子提取的图像比 Sorbel算子提取的图像边缘特征强度更高,具有更强的抗干扰的特性。

OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

Original: https://blog.csdn.net/weixin_44651073/article/details/126395558
Author: 肖爱Kun
Title: OpenCV图像处理学习十六,解析图像卷积运算原理并应用Sobel算子,Scharr算子和拉普拉斯算子(Laplance)的应用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/703143/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球