C++不使用外部库手写均值滤波、中值滤波

一、手写Auto_Padding

1.代码

// 判断x是否在区间[a,b]内。
bool IsInRange(int x, int a, int b) 
{
	return a <= x && x <= b;
}

// 判断输入字符串是否为纯数字
bool IsAllDigits(const string& str)
{
	return all_of(str.begin(), str.end(), isdigit);
}

/*
* 自动填充函数
* \param img 输入图片指针
* \param rows 输入图片高
* \param cols 输入图片宽
* \param kernel_size 卷积核大小
* \param mode 填充方式:0-255的正整数、replicate复制填充、reflect镜像填充
* \return unsigned char*型填充后图像的指针
*/
void* AutoPadding(unsigned char* img, int rows, int cols, int channels, int kernel_size, string mode, unsigned char* padded)
{
	if (kernel_size % 2 == 0) 
		throw "Error: Kernel size must be an odd number.";
	else 
	{
		int pad_size = (kernel_size - 1) / 2;
		int padded_rows = rows + pad_size * 2;
		int padded_cols = cols + pad_size * 2;

		if (IsAllDigits(mode))  // 常数填充
		{
			int padding_value = stoi(mode);
			if (IsInRange(padding_value, 0, 255))
			{
				for (int y = 0; y < padded_rows; ++y)
				{
					for (int x = 0; x < padded_cols; ++x)
					{
						for (int z = 0; z < channels; ++z)
						{
							if (IsInRange(y - pad_size, 0, rows - 1) && IsInRange(x - pad_size, 0, cols - 1))
								padded[y * padded_cols * channels + x * channels + z] = img[(y - pad_size) * cols * channels + (x - pad_size) * channels + z];  // 内部填充
							else
								padded[y * padded_cols * channels + x * channels + z] = padding_value;  // 边缘填充
						}
					}
				}
			}
			else
				throw "Error: Padding value is not in range.";
		}
		else if (mode == "replicate")  // 复制填充
		{
			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];  // 内部填充
					}
				}
			}
			for (int y = 0; y < pad_size; ++y)
			{
				for (int x = 0; x < padded_cols; ++x)
				{
					for (int z = 0; z < channels; ++z)
					{
						if (not IsInRange(x, pad_size, padded_cols - pad_size - 1)) // 四顶点矩阵填充
						{
							if (pad_size - x >= 0)
							{
								padded[y * padded_cols * channels + x * channels + z] = img[0];
								padded[(y + padded_rows - pad_size) * padded_cols * channels + x * channels + z] = img[(rows - 1) * cols * channels + z];
							}
							else
							{
								padded[y * padded_cols * channels + x * channels + z] = img[(cols - 1) * channels + z];
								padded[(y + padded_rows - pad_size) * padded_cols * channels + x * channels + z] = img[(rows - 1) * cols * channels + (cols - 1) * channels + z];
							}
						}
						else  // 上下边界填充
						{
							padded[y * padded_cols * channels + x * channels + z] = img[(x - pad_size) * channels + z];
							padded[(y + padded_rows - pad_size) * padded_cols * channels + x * channels + z] = img[(rows - 1) * cols * channels + (x - pad_size) * channels + z];
						}
					}
				}
				for (int x = pad_size; x < padded_rows - pad_size; ++x)  //  左右边界填充
				{
					for (int z = 0; z < channels; ++z)
					{
						padded[x * padded_cols * channels + y * channels + z] = img[(x - pad_size) * cols * channels + z];
						padded[x * padded_cols * channels + (y + padded_cols - pad_size) * channels + z] = img[(x - pad_size) * cols * channels + (cols - 1) * channels + z];
					}
				}
			}
		}
		else if (mode == "reflect")
		{
			if (pad_size <= rows - 1 && pad_size <= cols - 1)
			{
				int padded_rows = rows + pad_size * 2;
				int padded_cols = cols + pad_size * 2;


				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];  // 内部填充
					}
				}

				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];
						}
					}
				}
				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];
						}
					}
				}
			}
			else
				throw "Error: Kernel size is too big.";
		}
		else
			throw "Error: This mode is not defined.";
	}
}

2.测试

void PaddingMatrixTest(int rows , int cols, int kernel_size, string mode)
{
	Mat matrix = Mat::zeros(rows, cols, CV_8UC1);
	randu(matrix, Scalar(10), Scalar(99));
	cout << matrix << endl;
	Mat test(matrix.rows + (kernel_size - 1), matrix.cols + (kernel_size - 1), CV_8UC1);
	try
	{
		AutoPadding(matrix.data, matrix.rows, matrix.cols, matrix.channels(), kernel_size, mode, test.data);
	}
	catch (const char* error_msg)
	{
		cout << error_msg << endl;
	}
	cout << test << endl;
}

void PaddingImageTest(string path, string mode)
{
	Mat img = imread(path);
	imshow("原图", img);
	int kernel_size = min(int(img.rows / 2), int(img.cols / 2));
	Mat test(img.rows + (kernel_size - 1), img.cols + (kernel_size - 1), CV_8UC3);
	try
	{
		AutoPadding(img.data, img.rows, img.cols, img.channels(), kernel_size, mode, test.data);
	}
	catch (const char* error_msg)
	{
		cout << error_msg << endl;
	}
	imshow("填充", test);
	waitKey(0);
}

int main()
{
	
	PaddingMatrixTest(5, 5, 5, "replicate");
	PaddingImageTest("test.png", "replicate");

	return 0;
}

在这里插入图片描述
在这里插入图片描述

二、滤波函数

1.代码

/*
* 滤波
* \param img 输入图片指针
* \param rows 输入图片高
* \param cols 输入图片宽
* \param channels 输入图像通道数
* \param kernel_size 卷积核大小
* \param padding_mode 填充方式:0-255的正整数、replicate复制填充、reflect镜像填充
* \param blur_mode 滤波方式:Median、Mean
* \param blured 输出图片指针
*/
void Blur(unsigned char* img, int rows, int cols, int channels, int kernel_size, string padding_mode, string blur_mode, unsigned char* blured)
{
	int pad_size = (kernel_size - 1) / 2;
	int padded_rows = rows + pad_size * 2;
	int padded_cols = cols + pad_size * 2;
	unsigned char* padded = new unsigned char[padded_rows * padded_cols * channels];
	AutoPadding(img, rows, cols, channels, kernel_size, padding_mode, padded);
	
	vector<unsigned char> temp(kernel_size * kernel_size);

	for (int y = pad_size; y < padded_rows - pad_size; ++y)
	{
		for (int x = pad_size; x < padded_cols - pad_size; ++x)
		{
			for (int z = 0; z < channels; ++z)
			{
				int index = 0;
				for (int j = y - pad_size; j <= y + pad_size; ++j)
				{
					for (int i = x - pad_size; i <= x + pad_size; ++i)
						temp[index++] = padded[j * padded_cols * channels + i * channels + z];
				}
				if (blur_mode == "Median")
				{
					sort(temp.begin(), temp.end());
					blured[(y - pad_size) * cols * channels + (x - pad_size) * channels + z] = temp[(index - 1) / 2];
				}
				else if (blur_mode == "Mean")
				{
					int sum = accumulate(temp.begin(), temp.end(), 0);
					blured[(y - pad_size) * cols * channels + (x - pad_size) * channels + z] = sum / index;
				}
				else
					throw "Error: This mode is not defined.";
				//cout << z << "\n";
			}
		}
	}
	delete[] padded;
}

2.测试

void BlurTest(string path, int kernel_size, string padding_mode, string mode)
{
	Mat img = imread(path);
	imshow("原图", img);
	Mat test(img.rows, img.cols, CV_8UC3);
	try
	{
		Blur(img.data, img.rows, img.cols, img.channels(), kernel_size, padding_mode, mode, test.data);
	}
	catch (const char* error_msg)
	{
		cout << error_msg << endl;
	}
	imshow("滤波", test);
	waitKey(0);
}


int main()
{

	Mat img = imread("test.png");
	BlurTest("test.png", 5, "reflect", "Mean");

	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值