图像增强之均值滤波原理

目录

note

code

test


note

此次使用的均值滤波卷积核3x3

[1/9,1/9,1/9;1/9,1/9,1/9;1/9,1/9,1/9]

code

// 图像噪声之椒盐噪声
// 随机分布
// 灰度值:0或255
void SaltPepperNoise(Mat& noise, int noiseAmount) {
	if (noise.type() != CV_8UC1 && noise.type() != CV_8UC3) {
		return;
	}
	srand(time(nullptr));
	for (int i = 0; i < noiseAmount; ++i) {
		int x = rand() % noise.cols;
		int y = rand() % noise.rows;
		if (i % 2) {
			if (noise.type() == CV_8UC1) {
				noise.at<uchar>(x,y) = 255;
			}
			else if (noise.type() == CV_8UC3) {
				noise.at<Vec3b>(x,y) = Vec3b(255,255,255);
			}
		} 
		else {
			if (noise.type() == CV_8UC1) {
				noise.at<uchar>(x,y) = 0;
			}
			else if (noise.type() == CV_8UC3) {
				noise.at<Vec3b>(x,y) = Vec3b(0,0,0);
			}
		}
	}
}

// 不扩充边缘的矩阵卷积,输出矩阵和输入矩阵一样大
void MyMatConvolute2(Mat& src, Mat& kernel, Mat& res) {
	if (src.channels() != 1) {
		return;
	}
	if ((kernel.channels() != 1) || (kernel.rows != kernel.cols) || (kernel.rows / 2 == 0)) {
		return;
	}
	int srcType = src.type();
	// 先扩大,再缩小为原来大小
	int edge = kernel.rows / 2;
	Mat tmp(src.rows+2*edge, src.cols+2*edge, srcType, Scalar(0));
	for (int i = 0; i < src.rows; ++i) {
		for (int j = 0; j < src.cols; ++j) {
			if (srcType == CV_8UC1) {
				tmp.at<uchar>(i+edge,j+edge) = src.at<uchar>(i,j);
			}
			else if (srcType == CV_32FC1) {
				tmp.at<float>(i+edge,j+edge) = src.at<float>(i,j);
			}
			else {
				abort();
			}
		}
	}
	MyMatConvolute1(tmp, kernel, res);
}

// 不扩充边缘的矩阵卷积,导致输出矩阵比输入矩阵小
void MyMatConvolute1(Mat& src, Mat& kernel, Mat& res) {
	if (src.channels() != 1) {
		return;
	}
	if ((kernel.channels() != 1) || (kernel.rows != kernel.cols) || (kernel.rows / 2 == 0)) {
		return;
	}

	// 数据类型转换:uint8_t转float32_t
	int srcType = src.type();
	int kernelType = kernel.type();
	if (srcType != CV_32FC1) {
		src.convertTo(src, CV_32FC1);
	}
	if (kernelType != CV_32FC1) {
		kernel.convertTo(kernel, CV_32FC1);
	}
	
	int left = kernel.rows / 2;
	res = Mat(src.rows-2*left, src.cols-2*left, CV_32FC1);

	int res_row = 0, res_col = 0;
	for (int i = 0; i <= src.rows-kernel.rows; ++i) {
		for (int j = 0; j <= src.cols-kernel.cols; ++j) {
			float out = 0.0;
			for (int p = 0; p < kernel.rows; ++p) {
				for (int q = 0; q < kernel.cols; ++q) {
					out += src.at<float>(i+p,j+q) * kernel.at<float>(p,q);
				}
			}
			res.at<float>(res_row,res_col) = out;
			++res_col;
			if (res_col >= res.cols) {
				res_col = 0;
				++res_row;
			}
		}
	}

	// 数据类型还原
	src.convertTo(src, srcType);
	kernel.convertTo(kernel, kernelType);
	res.convertTo(res, srcType);
}

// 图像增强之均值滤波
// 处理域:空间域
// 卷积核使用大小:3x3
void img_filter_average_test(void) {
	Mat src = imread("../source/lena.jpg", IMREAD_GRAYSCALE);
	// Mat src = imread("../source/lena.jpg");
	if (src.empty()) {
		printf("src empty\n");
		return;
	}
	Mat noiseMat(src.rows, src.cols, src.type(), Scalar(0));
	Mat added(src.rows, src.cols, src.type(), Scalar(0));
	Mat kernel = Mat::ones(3,3, CV_32FC1) / 9.0;
	Mat myfiltered(src.rows, src.cols, src.type(), Scalar(0));
	Mat opencvfiltered(src.rows, src.cols, src.type(), Scalar(0));

	namedWindow("src", WINDOW_NORMAL);
	namedWindow("noise", WINDOW_NORMAL);
	namedWindow("added", WINDOW_NORMAL);
	namedWindow("myfiltered", WINDOW_NORMAL);
	namedWindow("opencvfiltered", WINDOW_NORMAL);

	imshow("src", src);

	SaltPepperNoise(noiseMat, 1000);
	imshow("noise", noiseMat);

	add(src, noiseMat, added);
	imshow("added", added);

	MyMatConvolute2(added, kernel, myfiltered);
	imshow("myfiltered", myfiltered);

	filter2D(added, opencvfiltered, added.type(), kernel, Point(-1,-1), 0.0, BORDER_CONSTANT);
	imshow("opencvfiltered", opencvfiltered);

	MyWait();
}

test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值