OpenCV计算机图像视觉基础学习笔记8——自定义线性滤波

唔,抱歉,这个系列咕了整整十天。

还是继续更新吧。


复习卷积

卷积是图像处理中的一个操作,是kernel在图像的每个像素上的操作。kernel本质上是一个固定大小的矩阵数组,其中心点称之为锚点。

卷积如何工作?把kernel放到像素数组之上,求锚点周围覆盖的像素乘积之和(包括锚点), 用来替换锚点覆盖下像素点值称为卷积处理。

卷积有三个作用。

  • 模糊图像
  • 提取边缘
  • 进行图像增强,比如锐化

采用卷积进行图像的处理,每一个小块的卷积和称之为算子。根据对图像的操作不同,算子也就不同。有一些比较经典的算子比如Robert算子,Sobel算子和Laplance算子。

简单的算子应用

Robert算子,X方向:

Robert算子,Y方向:

两个算子体现了在给定方向梯度上差异的最大体现。实际上,Robert算子是一种梯度算子。

尝试一下将两个算子计算出的结果相加后取反输出,是这样的:

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
Mat src, dst;
Mat robertx, roberty;
int ksize = 0;

src = imread("D:/pics/lovelive.jpg");
if (!src.data) {
cout << "could not load image..." << endl;
return -1;
}
char input_WIN[] = "input image";
char output_WIN[] = "output image";

imshow(input_WIN, src);
// Robert operator, direction X
Mat kernelx = (Mat_<int>(2, 2) << 1, 0, 0, -1);
filter2D(src, robertx, -1, kernelx, Point(-1, -1), 0, 0);

// Robert operator, direction Y
Mat kernely = (Mat_<int>(2, 2) << 0, 1, -1, 0);
filter2D(src, roberty, -1, kernely, Point(-1, -1), 0, 0);

add(robertx, roberty, dst);

imshow(output_WIN, ~dst);
waitKey(0);
return 0;
}

Sobel算子:

还是相加后取反输出,结果是这样,看起来要比Robert强一些。。。?它体现的差异值要比Robert更大一些,所以看起来效果会更好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
Mat src, dst;
Mat sobelx, sobely;
int ksize = 0;

src = imread("D:/pics/lovelive.jpg");
if (!src.data) {
cout << "could not load image..." << endl;
return -1;
}
char input_WIN[] = "input image";
char output_WIN[] = "output image";

imshow(input_WIN, src);
// Sobel operator, direction X
Mat kernelx = (Mat_<int>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
filter2D(src, sobelx, -1, kernelx, Point(-1, -1), 0, 0);

// Sobel operator, direction Y
Mat kernely = (Mat_<int>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
filter2D(src, sobely, -1, kernely, Point(-1, -1), 0, 0);

add(sobelx, sobely, dst);

imshow(output_WIN, ~dst);
waitKey(0);
return 0;
}

Laplance算子:

(仍然是对dst取反后输出)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
Mat src, dst;
int ksize = 0;

src = imread("D:/pics/lovelive.jpg");
if (!src.data) {
cout << "could not load image..." << endl;
return -1;
}
char input_WIN[] = "input image";
char output_WIN[] = "output image";

imshow(input_WIN, src);

// Laplance operator
Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);
filter2D(src, dst, -1, kernel, Point(-1, -1), 0, 0);

imshow(output_WIN, ~dst);
waitKey(0);
return 0;
}

自定义卷积模糊

核心在flit2D这个方法上面。这里给出原型解释:

1
2
3
4
5
6
7
8
9
void filter2D( 
InputArray src, // 输入图像
OutputArray dst, // 输出图像
int ddepth, // 图像深度,一般默认-1,即自动
InputArray kernel, // 卷积模板,输入一个Mat对象
Point anchor = Point(-1,-1), // 锚点位置,一般默认Point(-1, -1),即中心点
double delta = 0, // 计算出来的像素+delta
int borderType = BORDER_DEFAULT // 不清楚这个是干嘛的。。
);

采用一些方法可以让它动起来,这个是静态的效果图(懒得录gif了)

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
Mat src, dst;
int ksize = 0;

src = imread("D:/pics/lovelive.jpg");
if (!src.data) {
cout << "could not load image..." << endl;
return -1;
}
char input_WIN[] = "input image";
char output_WIN[] = "output image";

imshow(input_WIN, src);

// Custom operator demo
int c = 0;
int index = 0;
int dir = 1;
while (true) {
c = waitKey(1);
if ((char)c == 27) // 27是esc键
break;
else {
ksize = 4 + index * 2 + 1;
Mat kernel = Mat::ones(Size(ksize, ksize), CV_32F) / (float)(ksize * ksize);
filter2D(src, dst, -1, kernel, Point(-1, -1));
index += dir;
if (index == 8 || index == 0)
dir = -dir;
imshow(output_WIN, dst);
}
}
waitKey(0);
return 0;
}

其中Mat::ones是以前没见过的方法,给出的原解释是:

The method returns a Matlab-style identity matrix initializer, similarly to Mat::zeros. Similarly to Mat::ones, you can use a scale operation to create a scaled identity matrix efficiently.

翻译:该方法返回一个matlab样式的单位矩阵初始化器,类似于Mat::zeros。与Mat::ones类似,您可以使用缩放操作来高效地创建缩放的单位矩阵。

应该是一个用来初始化的东西吧……


-------------本文结束,感谢您的阅读转载请注明原作者及出处-------------


本文标题:OpenCV计算机图像视觉基础学习笔记8——自定义线性滤波

文章作者:Shawn Zhou

发布时间:2019年08月16日 - 13:08

最后更新:2019年08月18日 - 15:08

原始链接:http://shawnzhou.xyz/2019/08/16/19-08-16-01/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

知识无价,码字不易。对您有用,敬请打赏。金额随意,感谢关心。
0%