基本原理
圖像複原是圖像處理的重要組成部分,由于圖像在擷取和傳輸過程中通常不可避免的要受到一些噪聲的幹擾,是以在進行其他圖像處理以及圖像分析之前,應該盡量将圖像複原到其原始真實狀态。圖像複原的關鍵問題是在于建立退化模型。圖像退化模型如下:
維納濾波器是一種自适應最小均方誤差濾波器,它最終的目的是使得複原圖像和原始圖像的均方誤差最小。省去推導過程,給出頻率的維納濾波公式
示例示範
在下面例子中,我們對退化函數進行了簡化,将退化函數置為1,是以維納濾波公式簡化為:
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat GetSpectrum(const Mat &src)
{
Mat dst, cpx;
Mat planes[] = { Mat_<float>(src), Mat::zeros(src.size(), CV_32F) };
merge(planes, 2, cpx);
dft(cpx, cpx);
split(cpx, planes);
magnitude(planes[0], planes[1], dst);
//頻譜就是頻域幅度圖的平方
multiply(dst, dst, dst);
return dst;
}
Mat WienerFilter(const Mat &src, const Mat &ref, int stddev)
{
//這些圖檔是過程中會用到的,pad是原圖像0填充後的圖像,cpx是雙通道頻域圖,mag是頻域幅值圖,dst是濾波後的圖像
Mat pad, cpx, dst;
//擷取傅裡葉變化最佳圖檔尺寸,為2的指數
int m = getOptimalDFTSize(src.rows);
int n = getOptimalDFTSize(src.cols);
//對原始圖檔用0進行填充獲得最佳尺寸圖檔
copyMakeBorder(src, pad, 0, m - src.rows, 0, n - src.cols, BORDER_CONSTANT, Scalar::all(0));
//獲得參考圖檔頻譜
Mat tmpR(pad.rows, pad.cols, CV_8U);
resize(ref, tmpR, tmpR.size());
Mat refSpectrum = GetSpectrum(tmpR);
//獲得噪聲頻譜
Mat tmpN(pad.rows, pad.cols, CV_32F);
randn(tmpN, Scalar::all(0), Scalar::all(stddev));
Mat noiseSpectrum = GetSpectrum(tmpN);
//對src進行傅裡葉變換
Mat planes[] = { Mat_<float>(pad), Mat::zeros(pad.size(), CV_32F) };
merge(planes, 2, cpx);
dft(cpx, cpx);
split(cpx, planes);
//維納濾波因子
Mat factor = refSpectrum / (refSpectrum + noiseSpectrum);
multiply(planes[0], factor, planes[0]);
multiply(planes[1], factor, planes[1]);
//重新合并實部planes[0]和虛部planes[1]
merge(planes, 2, cpx);
//進行反傅裡葉變換
idft(cpx, dst, DFT_SCALE | DFT_REAL_OUTPUT);
dst.convertTo(dst, CV_8UC1);
return dst;
}
int main(int argc, char** argv)
{
char *imgName = "D:\\TestData\\lena.jpg";
Mat inputImg;
inputImg = imread(imgName, 0);
if (!inputImg.data)
{
cout << "No image data" << endl;
return -1;
}
imshow("OriginImage", inputImg);
cv::Mat noise(inputImg.size(), inputImg.type());
float m = (10);
float sigma = (50);
cv::randn(noise, m, sigma); //mean and variance
Mat noiseImg =inputImg + noise;
imshow("NoiseImage", noiseImg);
Mat resultImg = WienerFilter(noiseImg, inputImg, 50);
imwrite("./result.jpg", resultImg);
imshow("ResultImage", resultImg);
waitKey(0);
return 0;
}