赞
踩
6. motion_deblur_filter.cpp通过Wiener滤波器恢复运动模糊图像(参数难调)
您将学习如何使用维纳滤波器恢复具有运动模糊失真的图像
- /**
- * @brief 学习如何使用Wiener滤波器恢复运动模糊失真的图像。
- * @author 混沌鱼, karpushin@ngs.ru, https://github.com/VladKarpushin
- */
- #include <iostream>
- #include "opencv2/imgproc.hpp"
- #include "opencv2/imgcodecs.hpp"
-
-
- // 使用OpenCV和标准库的命名空间
- using namespace cv;
- using namespace std;
-
-
- // 函数声明
- void help();
- void calcPSF(Mat& outputImg, Size filterSize, int len, double theta);
- 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);
- void edgetaper(const Mat& inputImg, Mat& outputImg, double gamma = 5.0, double beta = 0.2);
-
-
- // 定义程序可能接受的命令行参数。
- const String keys =
- "{help h usage ? | | print this message }"
- "{image |input.png | input image name }"
- "{LEN |125 | length of a motion }"
- "{THETA |0 | angle of a motion in degrees }"
- "{SNR |700 | signal to noise ratio }"
- ;
-
-
- // 主函数
- int main(int argc, char *argv[])
- {
- // 显示帮助信息
- help();
- // 解析命令行参数
- CommandLineParser parser(argc, argv, keys);
- // 如果请求帮助,则打印帮助信息并退出程序。
- if (parser.has("help"))
- {
- parser.printMessage();
- return 0;
- }
-
- // 从命令行参数中获取LEN, THETA, SNR和图像文件名的值。
- int LEN = parser.get<int>("LEN");
- double THETA = parser.get<double>("THETA");
- int snr = parser.get<int>("SNR");
- string strInFileName = parser.get<String>("image");
-
-
- // 检查解析的命令行参数是否有误。
- if (!parser.check())
- {
- parser.printErrors();
- return 0;
- }
-
-
- // 加载图像文件
- Mat imgIn;
- imgIn = imread(strInFileName, IMREAD_GRAYSCALE);
- // 如果图像为空,则载入失败,打印错误信息并退出。
- if (imgIn.empty())
- {
- cout << "ERROR : Image cannot be loaded..!!" << endl;
- return -1;
- }
- // 图像处理后保存的输出图像。
- Mat imgOut;
-
-
- // 主要的图像处理过程开始
- // 只处理偶数大小的图像
- Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2);
-
-
- // 计算Hw(滤波器),过程开始
- Mat Hw, h;
- calcPSF(h, roi.size(), LEN, THETA);
- calcWnrFilter(h, Hw, 1.0 / double(snr));
- // 计算Hw(滤波器),过程结束
-
-
- // 将图像转换为浮点型并进行边缘锥化处理。
- imgIn.convertTo(imgIn, CV_32F);
- edgetaper(imgIn, imgIn);
-
-
- // 开始滤波处理
- filter2DFreq(imgIn(roi), imgOut, Hw);
- // 结束滤波处理
- // 主要的图像处理过程结束
-
-
- // 将处理后的图像转换回8位无符号整数型并进行归一化。
- imgOut.convertTo(imgOut, CV_8U);
- normalize(imgOut, imgOut, 0, 255, NORM_MINMAX);
- // 将处理后的图像保存至文件。
- imwrite("result.jpg", imgOut);
- return 0;
- }
-
-
- // 显示帮助信息的函数实现。
- void help()
- {
- cout << "2018-08-14" << endl;
- cout << "Motion_deblur_v2" << endl;
- cout << "You will learn how to recover an image with motion blur distortion using a Wiener filter" << endl;
- }
-
-
- // 计算点扩散函数(PSF)的函数实现。
- void calcPSF(Mat& outputImg, Size filterSize, int len, double theta)
- {
- // 创建图像并用0填充。
- Mat h(filterSize, CV_32F, Scalar(0));
- // 获取滤波器的中心点。
- Point point(filterSize.width / 2, filterSize.height / 2);
- // 在图像中绘制椭圆(运动模糊PSF)。
- ellipse(h, point, Size(0, cvRound(float(len) / 2.0)), 90.0 - theta, 0, 360, Scalar(255), FILLED);
- // 对图像求和得到总和。
- Scalar summa = sum(h);
- // 将图像h除以总和summa[0]来规格化PSF。
- 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));
- // 交换这四块图像,实现中心化。
- Mat tmp;
- q0.copyTo(tmp);
- q3.copyTo(q0);
- tmp.copyTo(q3);
- q1.copyTo(tmp);
- q2.copyTo(q1);
- tmp.copyTo(q2);
- }
-
-
- // 在频率域上应用滤波器的函数实现。
- void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H)
- {
- // 创建两个平面的数组,其中一个为浮点型的输入图像,另一个为和输入图像同等大小的零矩阵。
- Mat planes[2] = { Mat_<float>(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
- Mat complexI;
- // 合并两个平面形成复数图像。
- merge(planes, 2, complexI);
- // 进行离散傅里叶变换。
- dft(complexI, complexI, DFT_SCALE);
-
-
- Mat planesH[2] = { Mat_<float>(H.clone()), Mat::zeros(H.size(), CV_32F) };
- Mat complexH;
- // 为H矩阵也创建复数形式。
- merge(planesH, 2, complexH);
- Mat complexIH;
- // 对输入图像和滤波器进行逐个元素的复数乘法。
- mulSpectrums(complexI, complexH, complexIH, 0);
-
-
- // 进行离散傅里叶逆变换。
- idft(complexIH, complexIH);
- // 分离平面得到结果图像。
- split(complexIH, planes);
- outputImg = planes[0];
- }
-
-
- // 计算维纳滤波器的函数实现。
- void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr)
- {
- Mat h_PSF_shifted;
- // 对输入的PSF进行中心化。
- fftshift(input_h_PSF, h_PSF_shifted);
- // 为h_PSF_shifted创建两个平面,其中一个为浮点型形式的h_PSF_shifted,另一个为同等大小的零矩阵。
- Mat planes[2] = { Mat_<float>(h_PSF_shifted.clone()), Mat::zeros(h_PSF_shifted.size(), CV_32F) };
- Mat complexI;
- // 合并两个平面形成复数图像。
- merge(planes, 2, complexI);
- // 进行离散傅里叶变换。
- dft(complexI, complexI);
- // 分离平面得到h_PSF的幅度。
- split(complexI, planes);
- Mat denom;
- // 计算|h_PSF|的平方和加上噪声功率谱比(nsr)。
- pow(abs(planes[0]), 2, denom);
- denom += nsr;
- // 对h_PSF除以denom得到Wiener滤波器。
- divide(planes[0], denom, output_G);
- }
-
-
- // 对图像边缘执行锥形衰减的函数实现。
- //! [edgetaper]
- // 执行边缘渐变处理的功能,减少频谱泄露
- void edgetaper(const Mat& inputImg, Mat& outputImg, double gamma, double beta)
- {
- // 获取输入图像的列数Nx和行数Ny
- int Nx = inputImg.cols;
- int Ny = inputImg.rows;
-
- // 创建两个类型为浮点型的Mat矩阵w1和w2,w1的大小是1xNx,w2的大小是Nyx1
- // 并使用无效的黑色标量像素初始化(初始化为0)
- Mat w1(1, Nx, CV_32F, Scalar(0));
- Mat w2(Ny, 1, CV_32F, Scalar(0));
-
-
- // 获取w1和w2的指针,以便后面直接修改其值
- float* p1 = w1.ptr<float>(0);
- float* p2 = w2.ptr<float>(0);
-
- // dx是x方向的间隔参数,初始化为对应于-π到π的步长
- float dx = float(2.0 * CV_PI / Nx);
- // 初始化x的初始值为-π
- float x = float(-CV_PI);
- // 计算每一列的权重,存入w1中
- for (int i = 0; i < Nx; i++)
- {
- p1[i] = float(0.5 * (tanh((x + gamma / 2) / beta) - tanh((x - gamma / 2) / beta)));
- x += dx;
- }
-
- // dy是y方向的间隔参数,初始化为对应于-π到π的步长
- float dy = float(2.0 * CV_PI / Ny);
- // 初始化y的初始值为-π
- float y = float(-CV_PI);
- // 计算每一行的权重,存入w2中
- for (int i = 0; i < Ny; i++)
- {
- p2[i] = float(0.5 * (tanh((y + gamma / 2) / beta) - tanh((y - gamma / 2) / beta)));
- y += dy;
- }
-
- // 创建矩阵w,它是w1和w2的外积,代表整个图像的每个像素的权重
- Mat w = w2 * w1;
- // 使用权重矩阵w对输入图像进行点乘,以便对图像进行边缘渐变处理,结果存入输出图像outputImg
- multiply(inputImg, w, outputImg);
- }
- //! [edgetaper]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。