C++手写高斯滤波

默认padding方式:Reflect101

/*
* 自动填充函数, 对应halcon与opencv的默认镜像填充方式
* \param img 输入图片指针
* \param padded 输出图片指针
* \param rows 输入图片高
* \param cols 输入图片宽
* \param channels 输入图片通道数
* \param pad_size 上下左右padding的尺寸,=(卷积核尺寸-1)/2
*/
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.代码

/*
* 生成二维高斯滤波核
* \param kernel 输出高斯核
* \param kernel_size 核大小
* \param sigma 标准差
* \param norm 是否归一化
*/
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;
	}
}


/*
* 卷积滤波
* \param padded 输入padding后的图像
* \param pad_rows padding后图片高
* \param pad_cols padding后图片宽
* \param pad_size 上下左右四边扩充的尺寸
* \param pad_c 输入图片通道数
* \param k 卷积核
* \param k_rows 卷积核高
* \param k_cols 卷积核宽
* \param out 输出图像
*/
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.代码

/*
* 生成一维高斯滤波核
* \param kernel 输出高斯核
* \param kernel_size 核大小
* \param sigma 标准差
* \param norm 是否归一化
*/
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;
	}
}


/*
* 优化线性分离高斯滤波,生成高斯核->y卷积->x卷积,循环次数 k-1 | 传统高斯滤波 k*k | 线性分离高斯滤波 2k
* \param img 输入灰度图
* \param out 输出图片指针
* \param rows 输入图片高
* \param cols 输入图片宽
* \param channels 输入图片通道数
* \param kernel_size 卷积核大小
* \param sigma 标准差(x=y)
*/
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值