先来看几个滤波器公式:
高斯滤波器:
G ( x , y ; σ ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 G(x,y;\sigma) = \frac{1}{2 \pi \sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}} G(x,y;σ)=2πσ21e−2σ2x2+y2
图像的二阶导数:
∇ 2 f = ∂ 2 f ∂ x 2 + ∂ f ∂ y 2 \nabla^2 f = \frac{\partial ^ 2 f}{\partial x^2} + \frac{\partial ^ f}{\partial y^2} ∇2f=∂x2∂2f+∂y2∂f
LOG滤波器:
∇
2
G
(
x
,
y
;
σ
)
=
(
x
2
+
y
2
σ
4
−
2
σ
2
)
G
(
x
,
y
;
σ
)
\nabla^2 G(x,y;\sigma) = (\frac{x^2 + y^2}{\sigma^4 }- \frac{2}{\sigma ^2}) G(x,y;\sigma)
∇2G(x,y;σ)=(σ4x2+y2−σ22)G(x,y;σ)
计算机视觉材料中只有这几个孤零零的公式,没找到详细的说明,初次时便感到很有趣,但是不知道究竟如何利用这几个公式,以便实现滤波效果,但是我进行了如下测试。
首先声明,图片的操作目标是bmp图片。关于bmp图片的格式和操作,请看我的另一个帖子:https://blog.csdn.net/m0_37567738/article/details/134639843?spm=1001.2014.3001.5501
-
卷积操作。这个简单,根据卷积的定义操作即可,没什么好说的。但是实际操作过程中有一个奇怪的现象是:使用高斯卷积、双线性、sobel、角点、方框等几种常见卷积核测试,如果去掉卷积核前面的比例系数,会有一定的效果,如果保留,卷积无效,就是说卷积后图片未发生变化。后来发现,原因是将像素当作无符号数,改为有符号数后异常消失。
-
基于c/c++的、上述几个滤波公式的效果测试。有个问题是,我不知道上述几个滤波公式里面的x和y是什么意思,究竟是代表像素的坐标还是像素的值。首先,如果代表的是坐标的话,那么像素值将毫无意义,这显然是不可能的;但是如果代表的是像素值,那么究竟是像素的差异值还是像素值呢?我觉得都可以,不论是差异还是像素值,该公式都可以一定程度上体现出图片的特征。而老师表达的意思是,x和y代表是坐标值。我在测试中,使用的是如下方法:将图片中的像素值,从x和y两个方向,分别计算下一个像素对当前像素的差值,然后分别生成两张图片,然后将这两张图片中的像素值当作x和y,带入log公式,然后查看结果。
代码如下,其中的convolution是卷积函数,默认使用高斯滤波器;bmpFeature是滤波函数,其中x代表水平方向上当前像素和下一个像素的差值,y代表垂直方向上当前像素和下一个像素的差值,然后将x和y值带入LOG公式中。
#include "feature.h"
#include <math.h>
#include <stdio.h>
#include <Windows.h>
#define _USE_MATH_DEFINES
//#define FILTER_DIMENSION 5
//double g_filter[FILTER_DIMENSION][FILTER_DIMENSION] = { 1,4,6,4,1,4,6,24,16,4,6,24,36,24,6,4,6,24,16,4,1,4,6,4,1 };
#define FILTER_DIMENSION 3
double g_filter[FILTER_DIMENSION][FILTER_DIMENSION] = { 1,-2,1,-2,4,-2,1,-2};
int convolution( char* data, int h, int w) {
char* newdata = new char[w * (h + FILTER_DIMENSION)];
memset(newdata, 0, w * h);
for (int i = 0; i < h - FILTER_DIMENSION + 1;i ++) {
for (int j = 0; j < w - FILTER_DIMENSION + 1; j++) {
int p = i * w + j;
double t = 0;
for (int k = 0; k < FILTER_DIMENSION; k++) {
for (int m = 0; m < FILTER_DIMENSION; m++) {
t += data[p + k * w + m] * g_filter[k][m];
}
}
newdata[p] = t/256;
}
}
memcpy(data, newdata, w * h);
delete[]newdata;
return 0;
}
int bmpFeature(char* data, int h, int w) {
char* newdata = new char[w * h];
memset(newdata, 0, w * h);
char* td1 = new char[w * h];
memset(td1, 0, w * h);
char* td2 = new char[w * h];
memset(td2, 0, w * h);
for (int i = 0; i < h - 1; i++) {
for (int j = 0; j < w - 1; j++) {
int p = i * w + j;
int p1 = +1;
int p2 = p + w;
td1[p] = data[p1] - data[p];
td2[p] = data[p2] - data[p];
}
}
double pi = acos(-1);
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int p = i * w + j;
double t1 = ((td1[p]) ^ 2 + (td2[p]) ^ 2);
double c1 = (t1 - 2) * exp(-t1 / 2) / (2 * pi);
newdata[p] = c1;
}
}
memcpy(data, newdata, w * h);
delete[]newdata;
delete []td1;
delete []td2;
return 0;
}
int bmpFeature1( char * data,int h,int w) {
char* newdata = new char[w * h];
memset(newdata, 0, w * h);
double pi = acos(-1);
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int x = i * w + j;
int y = x + w;
if (y >= h*w) {
y = x;
}
double t1 = ( (data[x]) ^ 2 + (data[y]) ^ 2);
double c1 = (t1-2)* exp(-t1/2)/(2*pi);
y = x + 1;
if (x % w == 0) {
//y = x;
}
double t2 = ((data[x]) ^ 2 + (data[y]) ^ 2);
double c2 = (t2 - 2) * exp(-t2 / 2) / (2 * pi);
//newdata[x] = 256 - (c1 + c2)/2;
//newdata[x] = 256 - c1;
newdata[x] = 256 - ( c2) ;
}
}
memcpy(data, newdata, w * h);
delete []newdata;
return 0;
}
原始图片的灰度图片:
使用sobel核卷积后的图片:
使用高斯核卷积后的图片:
将x和y看作是对一个像素从x方向和y方向上的变化值,并带入LOG公式后,所得到的图片:
先sobel核卷积,又使用x、y两个方向的差值带入上述公式后的图片:
先高斯核卷积,又使用x、y两个方向的差值带入上述公式后的图片:
将像素值当作无符号数( 乱搞一气 😀 😃 😀)的测试效果图: