高斯与LoG滤波器
高斯滤波器:
使用高斯滤波器(
7
×
7
7\times7
7×7)大小,对fate.jpeg
进行降噪处理。
高斯滤波器是一种可以使图像平滑的滤波器,用于去除噪声。它将中心像素周围的像素按照高斯分布加权平均进行平滑化。这样的(二维)权值通常被称为卷积核(kernel)或者滤波器(filter)。
考虑到图像的长宽可能不是滤波器大小的整数倍,我们需要在图像的边缘补 0 0 0。这种方法称作Zero Padding。并且权值 g g g(卷积核)要进行归一化操作( ∑ g = 1 \sum\ g = 1 ∑ g=1)。
按下面的高斯分布公式计算权值:
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 π σ21 e−2 σ2x2+y2
标准差
σ
=
1.3
\sigma=1.3
σ=1.3的
8
−
8-
8−近邻高斯滤波器如下:
K
=
1
16
[
1
2
1
2
4
2
1
2
1
]
K=\frac{1}{16}\ \left[ \begin{matrix} 1 & 2 & 1 \\ 2 & 4 & 2 \\ 1 & 2 & 1 \end{matrix} \right]
K=161 ⎣⎡121242121⎦⎤
代码如下(示例):
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <math.h>
cv::Mat gaussian_filter(cv::Mat img, double sigma, int kernel_size)
{
int row = img.rows;
int col = img.cols;
int channel = img.channels();
// 准备输出
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC3);
// 准备卷积核
int pad = floor(kernel_size / 2);
int index_x = 0, index_y = 0;
double kernel_sum = 0;
// 获取卷积核
float kernel[kernel_size][kernel_size];
for (int i = 0; i < kernel_size; i++)
{
for (int j =0; j < kernel_size; j++)
{
index_x = i - pad;
index_y = j - pad;
kernel[i][j] = 1 / (2 * M_PI * sigma * sigma) * exp( - (index_x * index_x + index_y * index_y) / (2 * sigma * sigma));
kernel_sum += kernel[i][j];
}
}
for (int i = 0; i < kernel_size; i++)
{
for (int j =0; j < kernel_size; j++)
{
kernel[i][j] /= kernel_sum;
}
}
// 高斯卷积
double val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
for (int c = 0; c < channel; c++)
{
val = 0;
// 卷积计算
for (int di = -pad; di < pad + 1; di++)
{
for (int dj = -pad; dj < pad + 1; dj++)
{
if ((i + di) >= 0 && (j + dj) >= 0)
{
val += (double)img.at<cv::Vec3b>(i + di, j + dj)[c] * kernel[pad + di][pad + dj];
}
}
}
new_image.at<cv::Vec3b>(i, j)[c] = (uchar)val;
}
}
}
return new_image;
}
int main(){
// read image
cv::Mat img = cv::imread("../fate.jpeg", cv::IMREAD_COLOR);
// gaussian_filter
cv::Mat new_image = gaussian_filter(img, 1.3, 9);
cv::imwrite("../1-10/fate1.jpeg", new_image);
cv::imshow("vvv", new_image);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
输入图像 (fate.jpeg) | 高斯滤波图像 (fate1.jpeg) |
---|---|
![]() | ![]() |
LoG滤波器:
使用LoG滤波器,对fate.jpeg
进行降噪处理。
LoG即高斯-拉普拉斯(Laplacian of Gaussian)的缩写,使用高斯滤波器使图像平滑化之后再使用拉普拉斯滤波器使图像的轮廓更加清晰。
为了防止拉普拉斯滤波器计算二次微分会使得图像噪声更加明显,所以我们首先使用高斯滤波器来抑制噪声。
LoG 滤波器使用以下式子定义:
LoG
(
x
,
y
)
=
x
2
+
y
2
−
s
2
2
π
s
6
e
−
x
2
+
y
2
2
s
2
\text{LoG}(x,y)=\frac{x^2 + y^2 - s^2}{2 \ \pi \ s^6} \ e^{-\frac{x^2+y^2}{2\ s^2}}
LoG(x,y)=2 π s6x2+y2−s2 e−2 s2x2+y2
代码如下(示例):
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <math.h>
cv::Mat BGR2GRAY(cv::Mat img)
{
// get row and col
int row = img.cols;
int col = img.rows;
// prepare output
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
// BGR -> Gray
new_image.at<uchar>(i, j) = 0.2126 * (float)img.at<cv::Vec3b>(i, j)[2] \
+ 0.7152 * (float)img.at<cv::Vec3b>(i, j)[1] \
+ 0.0722 * (float)img.at<cv::Vec3b>(i, j)[0];
}
}
return new_image;
}
cv::Mat LoG_filter(cv::Mat img, double sigma, int kernel_size)
{
int row = img.rows;
int col = img.cols;
// 准备输出
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
// 准备卷积核
int pad = floor(kernel_size / 2);
int index_x = 0, index_y = 0;
double kernel_sum = 0;
// 获取卷积核
double kernel[kernel_size][kernel_size];
for (int i = 0; i < kernel_size; i++)
{
for (int j =0; j < kernel_size; j++)
{
index_x = i - pad;
index_y = j - pad;
kernel[i][j] = (index_x * index_x + index_y * index_y - sigma * sigma) / (2 * M_PI * pow(sigma, 6)) * exp( - (index_x * index_x + index_y * index_y) / (2 * sigma * sigma));
kernel_sum += kernel[i][j];
}
}
for (int i = 0; i < kernel_size; i++)
{
for (int j =0; j < kernel_size; j++)
{
kernel[i][j] /= kernel_sum;
}
}
// 高斯卷积
double val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
val = 0;
// 卷积计算
for (int di = -pad; di < pad + 1; di++)
{
for (int dj = -pad; dj < pad + 1; dj++)
{
if (((i + di) >= 0) && (( j + dj) >= 0) && ((i + di) < row) && ((j + dj) < col))
{
val += img.at<uchar>(i + di, j + dj) * kernel[pad + di][pad + dj];
}
}
}
val = fmax(val, 0);
val = fmin(val, 255);
new_image.at<uchar>(i, j) = (uchar)val;
}
}
return new_image;
}
int main(){
// read image
cv::Mat img = cv::imread("../fate.jpeg", cv::IMREAD_COLOR);
// gray image
cv::Mat gray = BGR2GRAY(img);
// gaussian_filter
cv::Mat new_image = LoG_filter(gray, 5, 3);
cv::imwrite("../1-10/fate11.jpeg", new_image);
cv::imshow("vvv", new_image);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
输入图像 (fate.jpeg) | LoG滤波图像 (fate11.jpeg) |
---|---|
![]() | ![]() |