C++实现,基于opencv的均值滤波器


C++实现,基于opencv的均值滤波器


目的:用于图像去除图像的颗粒噪声,使图像平滑.
原理: 即以当前像素点为中心,求相邻的8领域和自身的值的和,以其平均值作为中心像素新的值。
在这里插入图片描述
数学公式
在这里插入图片描述

伪代码:
输入:原图像,输出图像,核的大小
(1).判断原图像是否为空,为空就直接返回
(2).判断卷积核是否为奇数
(3).准备一个新的对象来存放边界填充后的图像
(4).边界填充,并清空目标图像
(5).均值滤波处理
①、三通道的处理
定义RGB三个通道的核的和以及平均数,并置0
求核的总和
求平均数
写入目标图像
核和平均数置0
②、单通道的处理
定义核的和以及平均数,并置0
求核的总和
求平均数
写入目标图像
核和平均数置0

版本:
opencv4.5.1+vs2017

源代码:
只处理单通道和三通道

// ConsoleApplication3.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>

using namespace cv;
using namespace std;

// 均值滤波对话框值滤波
void MeanFilter(Mat& src, Mat& dst, Size wsize) {
	// 判断原图像是否为空
	if (src.empty()) {
		return;
	}
	//判断矩阵的行列数为奇数
	if (wsize.height % 2 == 0 || wsize.width % 2 == 0) {
		fprintf(stderr, "Please enter odd size!");
		exit(-1);
	}
	int hh = (wsize.height - 1) / 2;
	int hw = (wsize.width - 1) / 2;

	Mat Newsrc;
	copyMakeBorder(src, Newsrc, hh, hh, hw, hw, BORDER_REFLECT_101);//以边缘为轴,对称
	dst = Mat::zeros(src.size(), src.type());

	//第二种方法:指针方法
	// 三通道彩色图片处理
	if (Newsrc.channels() == 3) {
		//int q = 0;//test
		// 定义每个通道的核的总数和平均值,并置0
		int sumR = 0, sumG = 0, sumB = 0;
		int averageR = 0, averageG = 0, averageB = 0;
		for (int i = hh; i < src.rows + hh; i++)
			for (int j = hw; j < src.cols + hw; j++) {

				for (int r = i - hh; r <= i + hh; r++) {
					Vec3b* data_New = Newsrc.ptr<Vec3b>(r);
					// 求核的总数
					for (int k = j - hh; k <= j + hh; k++) {
						sumR += data_New[k][0];
						sumG += data_New[k][1];
						sumB += data_New[k][2];
					}
				}
				// 求平均数
				averageR = sumR / (wsize.area());
				averageG = sumG / (wsize.area());
				averageB = sumB / (wsize.area());
				// 写入目标图像
				Vec3b* dataDst = dst.ptr<Vec3b>(i - hh);
				dataDst[j - hw][0] = averageR;
				dataDst[j - hw][1] = averageG;
				dataDst[j - hw][2] = averageB;

				// 总和和平均数置0
				sumR = 0; sumG = 0; sumB = 0;
				averageR = 0; averageG = 0; averageB = 0;
			}
	}
	// 单通道图片处理
	else if (Newsrc.channels() == 1) {
		int sum = 0;
		int average = 0;
		for (int i = hh; i < src.rows + hh; i++) {
			for (int j = hw; j < src.cols + hw; j++) {

				for (int r = i - hh; r <= i + hh; r++) {
					uchar* data = Newsrc.ptr<uchar>(r);
					for (int k = j - hh; k <= j + hh; k++) {
						sum += data[k];
					}
				}
				average = sum / (wsize.area());
				uchar* data_dst = dst.ptr<uchar>(i - hh);
				data_dst[j - hw] = average;
				sum = 0;
				average = 0;
			}
		}
	}
	else
	{
		return;
	}

}


int main()
{
	Mat src = imread("C:/Users/vmyf16/Desktop/1.jpg");
	if (src.empty()) {
		return -1;
	}
	
	imshow("原图", src);
	Mat dst2 = Mat::zeros(src.size(), src.type());

	MeanFilter(src, dst2, Size(5, 5));
	imshow("自己写的", dst2);


	Mat dst1 = Mat::zeros(src.size(), src.type());

	blur(src, dst1, Size(5, 5));

	imshow("opencv自带的", dst1);

	imshow("两者差值", dst1 - dst2);


	waitKey(0);

	return 0;

}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

结果图像:
原图像:

在这里插入图片描述

结果图:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值