根据噪声图像和先验知识,我们能够使用一些基于滤波图像的局部细节方法。其中一个方法就是局部方差。随空间变化的滤波器h(n1,n2)是由图像局部信息和附加先验知识决定的函数。基于局部图像信息的特殊的方法改进了算法,空变滤波器h(n1,n2)是由图像局部信息和可获得的先验知识决定的函数。在9.2.1节讨论了一种自适应的维纳滤波器。
我们用OpenCV实现该算法。头文件如下
#pragma once
#include
#include
#include
#include
/** @brief Implementation of the adaptive Wiener filter
This function applies to the src image the adaptive Wiener filter and
store the result in the dst image. The formula that will be apply is
the following one:
dst(x, y) = u + max(0, s^2 - v^2)(src(x, y) - u) / max(s^2, v^2)
where u is the local mean, s^2 is the variance at NxM neighborhood
around each pixel (they depend on block dimension) e v^2 is the noise
variance calculated as the average of all the local estimated variances
if not given.
@param[in] src input grayscale image (Mat1b)
@param[out] dst output grayscale image (Mat1b)
@param[in] block dimension of the block (width, height) to use in order
to compute the filtering process, default is 5x5
@return estimated noise variance
*/
double WienerFilter(const cv::Mat& src, cv::Mat& dst, const cv::Size& block = cv::Size(5, 5));
/** @overload
@param[in] src input grayscale image (Mat1b)
@param[out] dst output grayscale image (Mat1b)
@param[in] noiseVariance noise variance to use in order to calculate Wiener filter (must be positive)
@param[in] block dimension of the block (width, height) to use in order
to compute the filtering process, default is 5x5
@return estimated noise variance
*/
void WienerFilter(const cv::Mat& src, cv::Mat& dst, double noiseVariance, const cv::Size& block = cv::Size(5, 5));
源文件如下
#include "WienerFilter.h"
using namespace cv;
double WienerFilterImpl(const Mat& src, Mat& dst, double noiseVariance, const Size& block){
assert(("Invalid block dimensions", block.width % 2 == 1 && block.height % 2 == 1 && block.width > 1 && block.height > 1));
assert(("src and dst must be one channel grayscale images", src.channels() == 1, dst.channels() == 1));
int h = src.rows;
int w = src.cols;
dst = Mat1b(h, w);
Mat1d means, sqrMeans, variances;
Mat1d avgVarianceMat;
boxFilter(src, means, CV_64F, block, Point(-1, -1), true, BORDER_REPLICATE);
sqrBoxFilter(src, sqrMeans, CV_64F, block, Point(-1, -1), true, BORDER_REPLICATE);
Mat1d means2 = means.mul(means);
variances = sqrMeans - (means.mul(means));
if (noiseVariance < 0){
// I have to estimate the noiseVariance
reduce(variances, avgVarianceMat, 1, REDUCE_SUM, -1);
reduce(avgVarianceMat, avgVarianceMat, 0, REDUCE_SUM, -1);
noiseVariance = avgVarianceMat(0, 0) / (h*w);
}
for (int r = 0; r < h; ++r){
// get row pointers
uchar const * const srcRow = src.ptr<uchar>(r);
uchar * const dstRow = dst.ptr<uchar>(r);
double * const varRow = variances.ptr<double>(r);
double * const meanRow = means.ptr<double>(r);
for (int c = 0; c < w; ++c) {
dstRow[c] = saturate_cast<uchar>(
meanRow[c] + max(0., varRow[c] - noiseVariance) / max(varRow[c], noiseVariance) * (srcRow[c] - meanRow[c])
);
}
}
return noiseVariance;
}
void WienerFilter(const Mat& src, Mat& dst, double noiseVariance, const Size& block){
WienerFilterImpl(src, dst, noiseVariance, block);
return;
}
double WienerFilter(const Mat& src, Mat& dst, const Size& block){
return WienerFilterImpl(src, dst, -1, block);
}