6.motion_deblur_filter.cpp通过Wiener滤波器恢复运动模糊图像(参数难调)
您将学习如何使用维纳滤波器恢复具有运动模糊失真的图像
/**
* @brief 学习如何使用Wiener滤波器恢复运动模糊失真的图像。
* @author 混沌鱼, karpushin@ngs.ru, https://github.com/VladKarpushin
*/
#include
#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("LEN");
double THETA = parser.get("THETA");
int snr = parser.get("SNR");
string strInFileName = parser.get("image");
// 检查解析的命令行参数是否有误。
if (!parser.check())
{
parser.printErrors();
return 0;
}
// 加载图像文件
Mat imgIn;
imgIn = imread(strInFileName, IMREAD_GRAYSCALE);
// 如果图像为空,则载入失败,打印错误信息并退出。
if (imgIn.empty())
{
cout (inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
Mat complexI;
// 合并两个平面形成复数图像。
merge(planes, 2, complexI);
// 进行离散傅里叶变换。
dft(complexI, complexI, DFT_SCALE);
Mat planesH[2] = { Mat_(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_(h_PSF_shifted.clone()), Mat::zeros(h_PSF_shifted.size(), CV_32F) };
Mat complexI;
// 合并两个平面形成复数图像。
merge(planes, 2, complexI);
// 进行离散傅里叶变换。
dft(c服务器托管网omplexI, 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(0);
float* p2 = w2.ptr(0);
// dx是x方向的间隔参数,初始化为对应于-到的步长
float dx = float(2.0 * CV_PI / Nx);
// 初始化x的初始值为-
float x = float(-CV_PI);
// 计算每一列的权重,存入w1中
for (int i = 0; i
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
stm32服务器托管网学习笔记-STLINK使用 使用ST-LINK调试程序 进度表格 使用ST-LINK调试程序 说明 组成 总结 记录使用STLINK进行项目的烧写和调试,旨在高效的进行代码调试 学习工具包括笔记本、keil5MDK、stm32f030c8…