默认padding方式:Reflect101
void Reflect101_Padding(unsigned char* img, unsigned char* padded, int rows, int cols, int channels, int pad_size)
{
int padded_rows = rows + pad_size * 2;
int padded_cols = cols + pad_size * 2;
#ifdef _USE_OMP
#pragma omp parallel for num_threads(omp_get_max_threads())
#endif
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
for (int z = 0; z < channels; ++z)
padded[(y + pad_size) * padded_cols * channels + (x + pad_size) * channels + z] = img[y * cols * channels + x * channels + z];
}
}
#ifdef _USE_OMP
#pragma omp parallel for num_threads(omp_get_max_threads())
#endif
for (int i = 0; i < cols; ++i)
{
for (int k = 1; k <= pad_size; ++k)
{
for (int z = 0; z < channels; ++z)
{
padded[(pad_size - k) * padded_cols * channels + (i + pad_size) * channels + z] = img[k * cols * channels + i * channels + z];
padded[(pad_size + rows - 1 + k) * padded_cols * channels + (i + pad_size) * channels + z] = img[(rows - 1 - k) * cols * channels + i * channels + z];
}
}
}
#ifdef _USE_OMP
#pragma omp parallel for num_threads(omp_get_max_threads())
#endif
for (int i = 0; i < padded_rows; ++i)
{
for (int k = 1; k <= pad_size; ++k)
{
for (int z = 0; z < channels; ++z)
{
padded[i * padded_cols * channels + (pad_size - k) * channels + z] = padded[i * padded_cols * channels + (pad_size + k) * channels + z];
padded[i * padded_cols * channels + (pad_size + cols - 1 + k) * channels + z] = padded[i * padded_cols * channels + (pad_size + cols - 1 - k) * channels + z];
}
}
}
}
一、经典高斯滤波
1.代码
void Gen_Gaussian_Kernel_2D(double* kernel, int kernel_size, double sigma, bool norm)
{
int r = (kernel_size - 1) / 2;
double sum = 0;
double c1 = 2 * sigma * sigma;
double c2 = c1 * PI;
for (int y = -r; y <= r; ++y)
{
for (int x = -r; x <= r; ++x)
{
kernel[(y + r) * kernel_size + (x + r)] = exp(-(x * x + y * y) / c1) / c2;
sum += kernel[(y + r) * kernel_size + (x + r)];
}
}
if (norm)
{
for (int i = 0; i < kernel_size * kernel_size; ++i)
kernel[i] = kernel[i] / sum;
}
}
void Conv_Filter(unsigned char* padded, int pad_rows, int pad_cols, int pad_size, int pad_c, double* k, int k_rows, int k_cols, unsigned char* out)
{
int k_hc = (k_rows - 1) / 2;
int k_wc = (k_cols - 1) / 2;
int o_cols = pad_cols - 2 * pad_size;
#ifdef _USE_OMP
#pragma omp parallel for num_threads(omp_get_max_threads())
#endif
for (int y = pad_size; y < pad_rows - pad_size; ++y)
{
for (int x = pad_size; x < pad_cols - pad_size; ++x)
{
for (int z = 0; z < pad_c; ++z)
{
double sum = 0;
for (int j = 0; j < k_rows; ++j)
{
for (int i = 0; i < k_cols; ++i)
{
sum += k[j * k_cols + i] * padded[(y - k_hc + j) * pad_cols * pad_c + (x - k_wc + i) * pad_c + z];
}
}
out[(y - pad_size) * o_cols * pad_c + (x - pad_size) * pad_c + z] = sum;
}
}
}
}
void Gaussian_Blur(unsigned char* img, unsigned char* out, int rows, int cols, int channels, int kernel_size, double sigma)
{
int pad_size, center;
pad_size = center = (kernel_size - 1) / 2;
int padded_rows = rows + pad_size * 2;
int padded_cols = cols + pad_size * 2;
double* gauss_kernel = new double[kernel_size * kernel_size];
unsigned char* padded = new unsigned char[padded_rows * padded_cols * channels];
unsigned char* temp = new unsigned char[padded_rows * padded_cols * channels];
Gen_Gaussian_Kernel_2D(gauss_kernel, kernel_size, sigma, true);
Reflect101_Padding(img, padded, rows, cols, channels, pad_size);
Conv_Filter(padded, padded_rows, padded_cols, pad_size, channels, gauss_kernel, kernel_size, kernel_size, out);
delete[] gauss_kernel;
delete[] padded;
delete[] temp;
}
2.测试
int main()
{
Mat img = imread("./test_img/test2.png");
Mat test(img.rows, img.cols, CV_8UC3);
Gaussian_Blur(img.data, test.data, img.rows, img.cols, img.channels(), 9, 2.025);
imshow("yuan", img);
imshow("test", test);
waitKey(0);
return 0;
}
二、线性分离加速高斯滤波
1.代码
void Gen_Gaussian_Kernel_1D(double* kernel, int kernel_size, double sigma, bool norm)
{
int r = (kernel_size - 1) / 2;
double sum = 0;
double c1 = 2 * sigma * sigma;
double c2 = sqrt(2 * PI) * sigma;
for (int x = -r; x <= r; ++x)
{
kernel[x + r] = exp(-x * x / c1) / c2;
sum += kernel[x + r];
}
if (norm)
{
for (int i = 0; i < kernel_size; ++i)
kernel[i] = kernel[i] / sum;
}
}
void Gaussian_Blur(unsigned char* img, unsigned char* out, int rows, int cols, int channels, int kernel_size, double sigma)
{
int pad_size, center;
pad_size = center = (kernel_size - 1) / 2;
int padded_rows = rows + pad_size * 2;
int padded_cols = cols + pad_size * 2;
double* gauss_kernel = new double[kernel_size];
unsigned char* padded = new unsigned char[padded_rows * padded_cols * channels];
unsigned char* temp = new unsigned char[padded_rows * padded_cols * channels];
Gen_Gaussian_Kernel_1D(gauss_kernel, kernel_size, sigma, true);
Reflect101_Padding(img, padded, rows, cols, channels, pad_size);
#ifdef _USE_OMP
#pragma omp parallel for num_threads(omp_get_max_threads())
#endif
for (int y = pad_size; y < padded_rows - pad_size; ++y)
{
for (int x = 0; x < padded_cols; ++x)
{
for (int z = 0; z < channels; ++z)
{
double sum = gauss_kernel[center] * padded[y * padded_cols * channels + x * channels + z];
for (int dy = 0; dy < center; ++dy)
{
sum += gauss_kernel[dy] * (padded[(y - (center - dy)) * padded_cols * channels + x * channels + z]
+ padded[(y + (center - dy)) * padded_cols * channels + x * channels + z]);
}
temp[y * padded_cols * channels + x * channels + z] = sum > 255 ? 255 : int(sum);
}
}
}
#ifdef _USE_OMP
#pragma omp parallel for num_threads(omp_get_max_threads())
#endif
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
for (int z = 0; z < channels; ++z)
{
double sum = gauss_kernel[center] * temp[(y + pad_size) * padded_cols * channels + (x + pad_size) * channels + z];
for (int dx = 0; dx < center; ++dx)
{
sum += gauss_kernel[dx] * (temp[(y + pad_size) * padded_cols * channels + ((x + pad_size) - (center - dx)) * channels + z]
+ temp[(y + pad_size) * padded_cols * channels + ((x + pad_size) + (center - dx)) * channels + z]);
}
out[y * cols * channels + x * channels + z] = sum > 255 ? 255 : int(sum);
}
}
}
delete[] gauss_kernel;
delete[] padded;
delete[] temp;
}
2.测试
int main()
{
Mat img = imread("./test_img/glue.jpg");
Mat test(img.rows, img.cols, CV_8UC3);
Gaussian_Blur(img.data, test.data, img.rows, img.cols, img.channels(), 9, 2.025);
return 0;
}