当前位置: 首页 > article >正文

数字图像处理(c++ opencv):图像复原与重建-常见的滤波方法--自适应滤波器

自适应局部降噪滤波器

自适应局部降噪滤波器(Adaptive, Local Noise Reduction Filter)原理步骤

步骤

(1)计算噪声图像的方差 在这里插入图片描述

(2)计算滤波器窗口内像素的均值 在这里插入图片描述和方差 在这里插入图片描述

(3)利用原理公式:在这里插入图片描述

在这里插入图片描述

原理

(1)若 在这里插入图片描述为零,则滤波器仅返回(x, y)处的值g。因为噪声为零时,(x, y)处的g等于f.

(2)若局部方差与高度相关,则滤波器返回(x, y)处的一个接近于g的值。高局部方差通常与边缘相关,且应保留这些边缘。

(3)若两个方差相等,则希望滤波器返回Sxy中像素的算术平均值。当局部区域的性质与整个图像的性质相同时会出现这个条件,且平均运算会降低局部噪声。

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

//定义滤波函数
void AdaptiveLocalNoiseReductionFilter(Mat img_input, Mat& img_output, int m, int n); //输入图像,输出图像,m,n为滤波器大小。

int main()
{
	Mat image, image_gray, image_output;   //定义输入图像,灰度图像,输出图像
	image = imread("高斯噪声.png");  //读取图像;
	if (image.empty())
	{
		cout << "读取错误" << endl;
		return -1;
	}
	imshow("image", image);

	//转换为灰度图像
	cvtColor(image, image_gray, COLOR_BGR2GRAY);
	imshow("image_gray", image_gray);

	//自己编写的滤波函数
	AdaptiveLocalNoiseReductionFilter(image_gray, image_output, 7, 7);
	imshow("image_output", image_output);

	waitKey(0);  //暂停,保持图像显示,等待按键结束
	return 0;
}


//实现滤波函数
void AdaptiveLocalNoiseReductionFilter(Mat img_input, Mat& img_output, int m, int n)
{
	img_output = img_input.clone();
	Mat sortarray(1, m * n, CV_8U);  //局部像素灰度矩阵

	//1、为了保证图像的边缘也能够被滤波,这里首先扩展图像边缘,扩展方法为镜像
	copyMakeBorder(img_input, img_input, (m - 1) / 2, (m - 1) / 2, (n - 1) / 2, (n - 1) / 2, BORDER_REFLECT);

	//2、计算图像方差
	Mat mat_mean1, mat_stddev1, mat_mean2, mat_stddev2; //图像均值标准差矩阵,局部均值标准差矩阵
	meanStdDev(img_input, mat_mean1, mat_stddev1); //meanStdDev获取矩阵的平均值和标准差
	double stddev1, mean2, stddev2;  //图像标准差,局部均值和标准差
	stddev1 = mat_stddev1.at<double>(0, 0);//图像标准差


	//3、自适应局部降噪滤波
	for (int i = (m - 1) / 2; i < img_input.rows - (m - 1) / 2; i++)
	{
		for (int j = (n - 1) / 2; j < img_input.cols - (n - 1) / 2; j++)
		{
			int h = 0;
			for (int x = -(m - 1) / 2; x <= (m - 1) / 2; x++)
			{
				for (int y = -(n - 1) / 2; y <= (n - 1) / 2; y++)
				{
					sortarray.at<uchar>(h) = img_input.at<uchar>(i + x, j + y);
					h++;
				}
			}

			//计算局部均值和方差
			meanStdDev(sortarray, mat_mean2, mat_stddev2);
			stddev2 = mat_stddev2.at<double>(0, 0);  //局部标准差
			mean2 = mat_mean2.at<double>(0, 0);  //局部均值

			//滤波器
			double k = (stddev1 * stddev1) / (stddev2 * stddev2 + 0.00001);
			if (k <= 1)
			{
				img_output.at<uchar>(i - (m - 1) / 2, j - (n - 1) / 2) = img_input.at<uchar>(i, j) - k * (img_input.at<uchar>(i, j) - mean2);
			}
			else
			{
				img_output.at<uchar>(i - (m - 1) / 2, j - (n - 1) / 2) = mean2;
			}
		}
	}
}

在这里插入图片描述

自适应中值滤波器

原理

在这里插入图片描述

与中值滤波不同之处在于判定原灰度值是否为噪声,若不是噪声,则灰度值不变,这样可以减少图像的失真

最大最小值比较判定是否为噪声

#include<iostream>
#include<opencv2/opencv.hpp>
#include "Salt.h"

using namespace cv;
using namespace std;

//定义滤波函数
void AdaptiveMedianFilter(Mat img_input, Mat& img_output, int size_max); //输入图像,输出图像,size_max为滤波器最大尺寸。
//定义判定输出函数
uchar AdaptiveMedian(Mat img_input, int i, int j, int filter_size, int size_max);

int main()
{
	Mat image, image_gray, image_output;   //定义输入图像,灰度图像,输出图像
	image = imread("lena.png");  //读取图像;
	if (image.empty())
	{
		cout << "读取错误" << endl;
		return -1;
	}
	imshow("image", image);

	//转换为灰度图像
	cvtColor(image, image_gray, COLOR_BGR2GRAY);
	imshow("image_gray", image_gray);

	//添加盐粒噪声
	Salt(image_gray, 10000);
	imshow("image_gray2", image_gray);

	//自己编写的滤波函数
	AdaptiveMedianFilter(image_gray, image_output, 7);
	imshow("image_output", image_output);

	waitKey(0);  //暂停,保持图像显示,等待按键结束
	return 0;
}


//实现滤波函数
void AdaptiveMedianFilter(Mat img_input, Mat& img_output, int size_max)
{
	img_output = img_input.clone();

	//1、为了保证图像的边缘也能够被滤波,这里首先扩展图像边缘,扩展方法为镜像
	copyMakeBorder(img_input, img_input, (size_max - 1) / 2, (size_max - 1) / 2, (size_max - 1) / 2, (size_max - 1) / 2, BORDER_REFLECT);

	//2、滤波
	for (int i = (size_max - 1) / 2; i < img_input.rows - (size_max - 1) / 2; i++)
	{
		for (int j = (size_max - 1) / 2; j < img_input.cols - (size_max - 1) / 2; j++)
		{
			int filter_size = 3;  //起始滤波器尺寸
			img_output.at<uchar>(i - (size_max - 1) / 2, j - (size_max - 1) / 2) = AdaptiveMedian(img_input, i, j, filter_size, size_max);
		}
	}
}

//通过判定,找到输出值
uchar AdaptiveMedian(Mat img_input,int i, int j, int filter_size, int size_max)
{
	int num = filter_size * filter_size;
	vector<uchar> sortarray(num);
	int h = 0;
	for (int x = -(filter_size - 1) / 2; x <= (filter_size - 1) / 2; x++)
	{
		for (int y = -(filter_size - 1) / 2; y <= (filter_size - 1) / 2; y++)
		{
			sortarray[h] = img_input.at<uchar>(i + x, j + y);
			h++;
		}
	}
	sort(sortarray.begin(), sortarray.end()); //排序
	int z_min = sortarray[0];
	int z_med = sortarray[(num - 1) / 2];
	int z_max = sortarray[num - 1];
	int z_xy = img_input.at<uchar>(i, j);

	if (z_med > z_min && z_med < z_max)
	{
		if (z_xy > z_min && z_xy < z_max)
			return z_xy;
		else
			return z_med;
	}
	else
	{
		filter_size += 2;
		if (filter_size <= size_max)
			return AdaptiveMedian(img_input, i, j, filter_size, size_max);
		else
			return z_med;
	}
}

添加盐粒噪声h文件:

#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
#include <random>


using namespace cv;
using namespace std;

void Salt(Mat image, int n);

添加盐粒噪声cpp文件:

#include "Salt.h"

void Salt(Mat image, int n)
{
	default_random_engine generater;
	uniform_int_distribution<int>randomRow(0, image.rows - 1);
	uniform_int_distribution<int>randomCol(0, image.cols - 1);

	int i, j;
	for (int k = 0; k < n; k++)
	{
		i = randomCol(generater);
		j = randomRow(generater);
		if (image.channels() == 1)
		{
			image.at<uchar>(j, i) = 255;
		}
		else if (image.channels() == 3)
		{
			image.at<Vec3b>(j, i)[0] = 255;
			image.at<Vec3b>(j, i)[1] = 255;
			image.at<Vec3b>(j, i)[2] = 255;
		}
	}
}

在这里插入图片描述


http://www.kler.cn/a/393999.html

相关文章:

  • 1.两数之和-力扣(LeetCode)
  • DIP switch是什么?
  • Llama微调测试记录
  • JVM 中的完整 GC 流程
  • SystemVerilog学习笔记(六):控制流
  • 免费,WPS Office教育考试专用版
  • 传奇996_20——Ui对应的id介绍
  • 软件测试面试题(800道)【附带答案】持续更新...
  • Ubuntu 18.04 配置sources.list源文件(无法安全地用该源进行更新,所以默认禁用该源)
  • 中仕公考怎么样?事业编面试不去有影响吗?
  • 力扣题解(统计满足k约束的子字符串数目)
  • kafka中topic的数据抽取不到hdfs上问题解决
  • 什么是‌‌‌‌‌‌C#,有什么特点
  • 怎么选择香港服务器的线路?解决方案
  • Flutter Getx状态管理
  • React中常用的hook函数(四)——useRef、useNavigate、useLocation和useSearchParams
  • 后端-实现excel的导出功能(超详细讲解)
  • 【Pytorch】神经网络介绍|激活函数|使用pytorch搭建方法
  • .Net Core根据文件名称自动注入服务
  • Vim 编辑器学习笔记
  • wordpress functions文件的作用及详细说明
  • 网络安全:守护数字世界的坚固防线
  • 3D编辑器教程:如何实现3D模型多材质定制效果?
  • opencv常用api
  • python 编程 在 Matplotlib 中 默认预定的所有颜色,可以使用多种方法来指定颜色,包括预定义的颜色名称、十六进制颜色代码、
  • HarmonyOS Next 组件或页面之间的所有通信(传参)方法总结