Here is a mathematical model of the image degradation in frequency domain representation:
where \(S\) is a spectrum of blurred (degraded) image, \(U\) is a spectrum of original true (undegraded) image, \(H\) is a frequency response of point spread function (PSF), \(N\) is a spectrum of additive noise.
The circular PSF is a good approximation of out-of-focus distortion. Such a PSF is specified by only one parameter - radius \(R\). Circular PSF is used in this work.
The objective of restoration (deblurring) is to obtain an estimate of the original image. The restoration formula in frequency domain is:
where \(U'\) is the spectrum of estimation of original image \(U\), and \(H_w\) is the restoration filter, for example, the Wiener filter.
The Wiener filter is a way to restore a blurred image. Let's suppose that the PSF is a real and symmetric signal, a power spectrum of the original true image and noise are not known, then a simplified Wiener formula is:
where \(SNR\) is signal-to-noise ratio.
So, in order to recover an out-of-focus image by Wiener filter, it needs to know the \(SNR\) and \(R\) of the circular PSF.
#include <iostream>
void help();
void calcPSF(
Mat& outputImg,
Size filterSize,
int R);
void fftshift(
const Mat& inputImg,
Mat& outputImg);
void filter2DFreq(
const Mat& inputImg,
Mat& outputImg,
const Mat& H);
void calcWnrFilter(
const Mat& input_h_PSF,
Mat& output_G,
double nsr);
"{help h usage ? | | print this message }"
"{image |original.jpg | input image name }"
"{R |5 | radius }"
"{SNR |100 | signal to noise ratio}"
;
int main(
int argc,
char *argv[])
{
help();
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
int R = parser.get<int>("R");
int snr = parser.get<int>("SNR");
string strInFileName = parser.get<
String>(
"image");
if (!parser.check())
{
parser.printErrors();
return 0;
}
{
cout << "ERROR : Image cannot be loaded..!!" << endl;
return -1;
}
calcPSF(h, roi.size(), R);
calcWnrFilter(h, Hw, 1.0 / double(snr));
filter2DFreq(imgIn(roi), imgOut, Hw);
return 0;
}
void help()
{
cout << "2018-07-12" << endl;
cout << "DeBlur_v8" << endl;
cout << "You will learn how to recover an out-of-focus image by Wiener filter" << endl;
}
void calcPSF(
Mat& outputImg,
Size filterSize,
int R)
{
Point point(filterSize.width / 2, filterSize.height / 2);
circle(h, point, R, 255, -1, 8);
outputImg = h / summa[0];
}
void fftshift(
const Mat& inputImg,
Mat& outputImg)
{
outputImg = inputImg.
clone();
int cx = outputImg.
cols / 2;
int cy = outputImg.
rows / 2;
Mat q0(outputImg,
Rect(0, 0, cx, cy));
Mat q1(outputImg,
Rect(cx, 0, cx, cy));
Mat q2(outputImg,
Rect(0, cy, cx, cy));
Mat q3(outputImg,
Rect(cx, cy, cx, cy));
q3.copyTo(q0);
q1.copyTo(tmp);
q2.copyTo(q1);
}
void filter2DFreq(
const Mat& inputImg,
Mat& outputImg,
const Mat& H)
{
merge(planes, 2, complexI);
merge(planesH, 2, complexH);
idft(complexIH, complexIH);
split(complexIH, planes);
outputImg = planes[0];
}
void calcWnrFilter(
const Mat& input_h_PSF,
Mat& output_G,
double nsr)
{
fftshift(input_h_PSF, h_PSF_shifted);
merge(planes, 2, complexI);
pow(
abs(planes[0]), 2, denom);
denom += nsr;
divide(planes[0], denom, output_G);
}
Designed for command line parsing.
Definition utility.hpp:820
Template matrix class derived from Mat.
Definition mat.hpp:2230
n-dimensional dense array class
Definition mat.hpp:812
CV_NODISCARD_STD Mat clone() const
Creates a full copy of the array and the underlying data.
MatSize size
Definition mat.hpp:2160
void copyTo(OutputArray m) const
Copies the matrix to another one.
static CV_NODISCARD_STD MatExpr zeros(int rows, int cols, int type)
Returns a zero array of the specified size and type.
int cols
Definition mat.hpp:2138
bool empty() const
Returns true if the array has no elements.
int rows
the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
Definition mat.hpp:2138
void convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const
Converts an array to another data type with optional scaling.
void split(const Mat &src, Mat *mvbegin)
Divides a multi-channel array into several single-channel arrays.
void mulSpectrums(InputArray a, InputArray b, OutputArray c, int flags, bool conjB=false)
Performs the per-element multiplication of two Fourier spectrums.
void divide(InputArray src1, InputArray src2, OutputArray dst, double scale=1, int dtype=-1)
Performs per-element division of two arrays or a scalar by an array.
Scalar sum(InputArray src)
Calculates the sum of array elements.
void merge(const Mat *mv, size_t count, OutputArray dst)
Creates one multi-channel array out of several single-channel ones.
void normalize(InputArray src, InputOutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray())
Normalizes the norm or value range of an array.
void idft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0)
Calculates the inverse Discrete Fourier Transform of a 1D or 2D array.
void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0)
Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array.
void pow(InputArray src, double power, OutputArray dst)
Raises every array element to a power.
@ NORM_MINMAX
flag
Definition base.hpp:207
@ DFT_SCALE
Definition base.hpp:231
Rect2i Rect
Definition types.hpp:489
Point2i Point
Definition types.hpp:209
std::string String
Definition cvstd.hpp:151
Size2i Size
Definition types.hpp:370
Scalar_< double > Scalar
Definition types.hpp:702
#define CV_8U
Definition interface.h:73
#define CV_32F
Definition interface.h:78
cv::String findFile(const cv::String &relative_path, bool required=true, bool silentMode=false)
Try to find requested data file.
void addSamplesDataSearchSubDirectory(const cv::String &subdir)
Append samples search data sub directory.
void imshow(const String &winname, InputArray mat)
Displays an image in the specified window.
int waitKey(int delay=0)
Waits for a pressed key.
@ IMREAD_GRAYSCALE
If set, always convert image to the single channel grayscale image (codec internal conversion).
Definition imgcodecs.hpp:70
CV_EXPORTS_W bool imwrite(const String &filename, InputArray img, const std::vector< int > ¶ms=std::vector< int >())
Saves an image to a specified file.
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
Loads an image from a file.
void circle(InputOutputArray img, Point center, int radius, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
Draws a circle.
int main(int argc, char *argv[])
Definition highgui_qt.cpp:3
"black box" representation of the file storage associated with a file on disk.
Definition core.hpp:102
static uchar abs(uchar a)
Definition cvstd.hpp:66
An out-of-focus image recovering algorithm consists of PSF generation, Wiener filter generation and filtering a blurred image in frequency domain:
A function calcPSF() forms a circular PSF according to input parameter radius \(R\):
A function calcWnrFilter() synthesizes the simplified Wiener filter \(H_w\) according to the formula described above:
A function fftshift() rearranges the PSF. This code was just copied from the tutorial Discrete Fourier Transform:
And the following result has been computed with \(R\) = 53 and \(SNR\) = 5200 parameters:
The Wiener filter was used, and values of \(R\) and \(SNR\) were selected manually to give the best possible visual result. We can see that the result is not perfect, but it gives us a hint to the image's content. With some difficulty, the text is readable.