opencv图像分析与处理(12)-逆滤波、维纳滤波、约束最小二乘方滤波和几何均值滤波
本节为opencv数字图像处理(12):图像复原与重建的第三小节,逆滤波、维纳滤波、约束最小二乘方滤波和几何均值滤波,主要包括:四种滤波复原图像的数学推导以及维纳滤波的C++实现。
1. 逆滤波器
emsp; 若退化函数已知或可以得到一个估计,最简单的图像复原方法就是直接做逆滤波,用退化函数除退化图像的傅立叶变换来计算原始图形的傅立叶变换的估计即:
展开计算为:
如果退化噪声为0或很小,噪声就会支配估计值F^(u,v)\hat F(u,v)F^(u,v),这时候经常需要限制滤波的频率,使其接近原点。
1. 最小均方误差滤波/维纳滤波
这种滤波方法建立在图像和噪声都是随机变量的基础上,目标是找出未污染图像f(x,y)f(x,y)f(x,y)的一个估计f^\hat ff^,使它们之间的均方误差最小,误差度量由下式给出:
假设噪声和图像不相关,二者中有一个有零均值且估计中的灰度级是退化图像中灰度级的线性函数,则误差函数的最小值在频率与中由下式给出:
这个结果就是维纳滤波,方括号中的项组成的滤波器称为最小均方差滤波器或最小二乘误差滤波器。式子中:H(u,v)=H(u,v)=H(u,v)=退化函数;H∗(u,v)H*(u,v)H∗(u,v)=H(u,v)H(u,v)H(u,v)的复共轭;∣H(u,v)∣2=H∗(u,v)H(u,v)|H(u,v)|^2=H*(u,v)H(u,v)∣H(u,v)∣2=H∗(u,v)H(u,v);Seta(u,v)=∣N(u,v)∣2=S_{eta}(u,v)=|N(u,v)|^2=Seta(u,v)=∣N(u,v)∣2=噪声的功率谱。
如果噪声为0,那么噪声功率谱消失,维纳滤波简化为逆滤波。
信噪比是一个基于噪声和未退化图像的功率谱为基础的,频率域可用下式近似:
携带低噪声的图像SNR较高,是表征复原算法的性能的一个重要量度。
均方误差也可以这样描述:
而如果把复原图像考虑为“信号”,复原图像和原图像的差考虑为噪声,则空间域中信噪比可定义如下:
fff和f^\hat ff^越接近,这个比值越大。【这个定量与感觉上的图像质量没有很好的必然关系】
当处理白噪声时∣N(u,v)∣2|N(u,v)|^2∣N(u,v)∣2是一个常数,但是未退化图像和噪声的功率谱通常未知或不能估计,则可用下式近似:
C++实现来自这篇博文:
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;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);int LEN = 50;
int THETA = 360;
int snr = 8000;
Mat imgIn;
Rect roi;
static void onChange(int pos, void* userInput);int main(int argc, char* argv[])
{string strInFileName = "1.JPG";imgIn = imread(strInFileName, IMREAD_GRAYSCALE);if (imgIn.empty()) //check whether the image is loaded or not{cout << "ERROR : Image cannot be loaded..!!" << endl;return -1;}imshow("src", imgIn);// it needs to process even image onlyroi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2);imgIn = imgIn(roi);cv::namedWindow("inverse");createTrackbar("LEN", "inverse", &LEN, 200, onChange, &imgIn);onChange(0, 0);createTrackbar("THETA", "inverse", &THETA, 360, onChange, &imgIn);onChange(0, 0);createTrackbar("snr", "inverse", &snr, 10000, onChange, &imgIn);onChange(0, 0);imshow("inverse", imgIn);cv::waitKey(0);return 0;
}void calcPSF(Mat& outputImg, Size filterSize, int len, double theta)
{Mat h(filterSize, CV_32F, Scalar(0));Point point(filterSize.width / 2, filterSize.height / 2);ellipse(h, point, Size(0, cvRound(float(len) / 2.0)), 90.0 - theta,0, 360, Scalar(255), FILLED);Scalar summa = sum(h);outputImg = h / summa[0];Mat tmp;normalize(outputImg, tmp, 1, 0, NORM_MINMAX);imshow("psf", tmp);
}
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;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;fftshift(input_h_PSF, 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);split(complexI, planes);Mat denom;pow(abs(planes[0]), 2, denom);denom += nsr;divide(planes[0], denom, output_G);
}
void edgetaper(const Mat& inputImg, Mat& outputImg, double gamma, double beta)
{int Nx = inputImg.cols;int Ny = inputImg.rows;Mat w1(1, Nx, CV_32F, Scalar(0));Mat w2(Ny, 1, CV_32F, Scalar(0));float* p1 = w1.ptr<float>(0);float* p2 = w2.ptr<float>(0);float dx = float(2.0 * CV_PI / Nx);float x = float(-CV_PI);for (int i = 0; i < Nx; i++){p1[i] = float(0.5 * (tanh((x + gamma / 2) / beta) - tanh((x - gamma / 2) / beta)));x += dx;}float dy = float(2.0 * CV_PI / Ny);float y = float(-CV_PI);for (int i = 0; i < Ny; i++){p2[i] = float(0.5 * (tanh((y + gamma / 2) / beta) - tanh((y - gamma / 2) / beta)));y += dy;}Mat w = w2 * w1;multiply(inputImg, w, outputImg);
}// Trackbar call back function
static void onChange(int, void* userInput)
{Mat imgOut;//Hw calculation (start)Mat Hw, h;calcPSF(h, roi.size(), LEN, (double)THETA);calcWnrFilter(h, Hw, 1.0 / double(snr));//Hw calculation (stop)imgIn.convertTo(imgIn, CV_32F);edgetaper(imgIn, imgIn);// filtering (start)filter2DFreq(imgIn(roi), imgOut, Hw);// filtering (stop)imgOut.convertTo(imgOut, CV_8U);normalize(imgOut, imgOut, 0, 255, NORM_MINMAX);// imwrite("result.jpg", imgOut);imshow("inverse", imgOut);
}
2. 约束最小二乘方滤波
虽然维纳滤波中可以根据上式来进行估计,但是很少得到合适的解,我们将图像受噪声污染表达为如下的矩阵形式:
g=Hf+ηg=Hf+\eta g=Hf+η
考虑一个带约束的最小准则函数CCC,定义如下:
约束为:
在频率域这个最佳化问题的解决方案由如下公式给出:
γ\gammaγ是一个参数,调整以满足上2式,P(u,v)P(u,v)P(u,v)是函数:
的傅立叶变换,当γ=0\gamma=0γ=0时最小二乘方滤波退化为直接逆滤波。
γ\gammaγ可以交互地手动调整,当然也可以迭代计算,步骤如下。
定义一个残差向量rrr为:
由上3式知,F^(u,v)\hat F(u,v)F^(u,v)是γ\gammaγ的函数,所以rrr是该参数的函数,可以证明:
是γ\gammaγ的单调递增函数,我们需要调整γ\gammaγ使得:
若∣∣r∣∣2=∣∣η∣∣2||r||^2=||\eta||^2∣∣r∣∣2=∣∣η∣∣2,那么可以严格满足上述约束,具体地,寻找一个γ\gammaγ值得方法:
- 指定γ\gammaγ的初始值
- 计算∣∣r∣∣2||r||^2∣∣r∣∣2
- 满足上1式则停止;否则,若∣∣r∣∣2<∣∣η∣∣2−a||r||^2<||\eta||^2-a∣∣r∣∣2<∣∣η∣∣2−a,增大γ\gammaγ,若∣∣r∣∣2=∣∣η∣∣2+a||r||^2=||\eta||^2+a∣∣r∣∣2=∣∣η∣∣2+a,则减少γ\gammaγ。然后返回步骤2。重新计算最佳估计F^(u,v)\hat F(u,v)F^(u,v)
上面步骤中,为了计算∣∣r∣∣2||r||^2∣∣r∣∣2,由上式3【从此处向上数第三个列出的公式】有:
计算R(u,v)R(u,v)R(u,v)的傅里叶反变换得r(x,y)r(x,y)r(x,y),有:
计算∣∣η∣∣2||\eta||^2∣∣η∣∣2的话,首先考虑正负图像的噪声方差:
其中:
为样本均值。注意到上2式【从此处向上数第二个列出的公式】的双重求和即为∣∣η∣∣2||\eta||^2∣∣η∣∣2,给出如下表达式:
也就是说,仅仅使用噪声的均值和方差的知识,就可以实现一个最佳复原算法,但必须假设噪声和图像灰度值不相关。但是需要指出,约束最小二乘方意义小的最佳复原并不是视觉效果上最好。
3. 几何均值滤波
几何均值滤波是维纳滤波的推广:
当α=1\alpha=1α=1,退化为直接逆滤波,当α=0\alpha=0α=0,参数维纳滤波器,参数维纳滤波器在β=1\beta=1β=1时还原为标准的维纳滤波器。如果α=1/2\alpha=1/2α=1/2,则滤波器变成相同幂次的两个量的积,也就是几何均值的定义。当β=1\beta=1β=1,随着α\alphaα减小到1/21/21/2以下,滤波器性能越来越接近逆滤波器,增大到1/21/21/2以上,越来越接近维纳滤波器。当α=1/2\alpha=1/2α=1/2且β=1\beta=1β=1时,称为谱均衡滤波器。
欢迎扫描二维码关注微信公众号 深度学习与数学 [每天获取免费的大数据、AI等相关的学习资源、经典和最新的深度学习相关的论文研读,算法和其他互联网技能的学习,概率论、线性代数等高等数学知识的回顾]
opencv图像分析与处理(12)-逆滤波、维纳滤波、约束最小二乘方滤波和几何均值滤波相关推荐
- 【地震波滤波】保边滤波、傅氏变换干扰波去噪滤波、基于小波分解和重建的干扰波去噪、基于维纳滤波的去噪、中值滤波、视速度滤波
1.保边滤波 保护边缘滤波器,通常有四种类型,其中性能较为优良的是双边滤波器,其主要原理为: 双边滤波方法(Bilateral filtering)是基于Gsuss滤波方法提出的,主要是针对Gauss ...
- matlab怎样实现滤波,【转】matlab七种滤波方法实现和测试
创建两个混合信号,便于更好测试滤波器效果.同时用七中滤波方法测试. 混合信号Mix_Signal_1 = 信号Signal_Original_1+白噪声. 混合信号Mix_Signal_2 = 信号S ...
- 第5章 Python 数字图像处理(DIP) - 图像复原与重建16 - 约束最小二乘方滤波、几何均值滤波
标题 约束最小二乘方滤波 几何均值滤波 约束最小二乘方滤波 F^(u,v)=[H∗(u,v)∣H(u,v)∣2+γ∣P(u,v)∣2]G(u,v)(5.89)\hat{F}(u,v) = \bigg[ ...
- matlab实现频域率滤波,基于Matlab的图像的频域滤波实现及研究.doc
摘要:图像的频域滤波是图像增强的一种方法.图像增强是图像处理的方法之一,有频率域法和空间域法.频率域法把图像看成一种二维信号,对其进行二维傅里叶变换的信号增强,采用低通滤波法可以去掉图像的噪声:采用高 ...
- 滑动平均滤波c语言_11种经典软件滤波算法及其波形效果图(附C语言程序)
(后页附带C语言程序) 注意注意注意:(图像中红线都是经过滤波的)1.限幅滤波法(又称程序判断滤波法) A.方法: 根据经验判断,确定两次采样允许的最大偏差值(设为 A) 每次检测到新值时判断: 如果 ...
- 简单常用滤波算法c语言实现,简单常用滤波算法C语言实现
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/xiao2yizhizai/article/details/51026151 1.限幅滤波算法(程序判 ...
- OpenCV中的对极几何和对极约束
OpenCV中的对极几何和对极约束 1. 原理 参考 这篇博客将学习多视图几何的基础知识,如什么是对极.对极线.对极约束等. 1. 原理 当使用针孔相机拍摄图像时会丢失一个重要的信息,即图像的深度.或 ...
- matlab中基于十字形窗口的滤波算法,#215;字形滤波窗口在Matlab自适应中值滤波算法中的应用 - 21ic中国电子网...
由于种种原因,图像在生成.传输.变换等过程中往往会受到各种噪声的污染,从而导致图像质量退化.噪声信号的滤波是图像处理的基本任务之一,主要有线性滤波和非线性滤波两种方法.线性滤波方法一般具有低通特性,而 ...
- 采用Matlab编程实现 高频强调滤波,[转载]MATLAB图像处理-基于高频强调滤波和直方均衡化图像增强...
摘要: 现代医学非常发达,能通过各种手段来获取人体的各种信息,例如,X光可以拍摄人的骨头等图片.但是,这些图片效果不一定很好,所以在使用着大量的数字成像和数字图片处理设备.那么,现在,我用Matlab ...
- 滤波算法、中值和均值滤波区别
滤波算法: 这里所讲的算法都是针对图像空间的滤波算法,其中模板,可以理解为图像形态学中的结构元素,是用来选取图像中的那些像素点被用来操作的.空间滤波根据其功能划分为平滑滤波和锐化滤波.平滑滤波:能减 ...
最新文章
- 计算机书籍- 网络爬虫开发实战
- Oracle 验证A表的2个字段组合不在B表2个字段组合里的数据
- 【数字信号处理】傅里叶变换性质 ( 序列傅里叶变换共轭对称性质 | x(n) 分解为实部序列与虚部序列 | 实部傅里叶变换 | 虚部傅里叶变换 | 共轭对称傅里叶变换 | 共轭反对称傅里叶变换 )
- 简明机器学习教程——实践篇(一):从感知机入手
- mybatis-plus自定义mapper报org.apache.ibatis.binding.BindingException: Invalid bound statement(not found)
- 天天算法 LeetCode-938-二叉搜索树的范围和
- android10唯一识别,Android 10 如何获取唯一值?
- python 十进制与二进制以及位运算
- java 数据流对比_Java IO流之字符流字节流区别
- Java 使用SAX解析XML文档
- Java Spring AOP
- python 输入一行、加密y变成a_下面程序实现如下功能:输入一行字母将字母加密输出(a变成c,b变成d, 一直到z变成b)...
- 为什么不推荐使用BeanUtils属性转换工具,老程序员都不使用!
- Icons8 Cube4Nano专业外置声卡设备与windows event log无法启动
- toolchain - 工具链
- oracle数据库按中文拼音排序,以及提取中文字符串拼音首字母函数
- 统计学三大相关性系数(pearson、spearman、kendall)的区别。
- 双核不可阻挡!首款双核处理器Tegra2详解
- 十大api接口平台(接口商)
- 【小程序背景图之海贼王篇】