自适应局部降噪滤波器
自适应局部降噪滤波器(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;elsereturn z_med;}else{filter_size += 2;if (filter_size <= size_max)return AdaptiveMedian(img_input, i, j, filter_size, size_max);elsereturn 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;}}
}