OpenCV的周期性噪声去除滤波器(70)

返回:OpenCV系列文章目录(持续更新中......)
上一篇:OpenCV如何通过梯度结构张量进行各向异性图像分割(69)
下一篇 :OpenCV如何为我们的应用程序添加跟踪栏(71)

目录

目标

理论

如何消除傅里叶域中的周期性噪声?

源代码

解释

结果

目标

在本教程中,您将学习:

  • 如何消除傅里叶域中的周期性噪声

理论

注意

解释基于该书[108]。此页面上的图像是真实世界的图像。

周期性噪声在傅里叶域中产生尖峰,通常可以通过视觉分析检测到。

如何消除傅里叶域中的周期性噪声?

通过频域滤波可以显著降低周期性噪声。在此页面上,我们使用具有适当半径的陷波抑制滤波器来完全封闭傅里叶域中的噪声尖峰。陷波滤波器抑制中心频率附近预定义邻域中的频率。陷波滤波器的数量是任意的。缺口区域的形状也可以是任意的(例如矩形或圆形)。在此页面上,我们使用三个圆形陷波抑制滤光片。图像的功率谱致密化用于噪声尖峰的视觉检测。

源代码

您可以在 OpenCV 源代码库中找到源代码。samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp

#include <iostream>
#include "opencv2/highgui.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
 
using namespace cv;
using namespace std;
 
void fftshift(const Mat& inputImg, Mat& outputImg);
void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H);
void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius);
void calcPSD(const Mat& inputImg, Mat& outputImg, int flag = 0);
 
const String keys =
"{help h usage ? | | print this message }"
"{@image |period_input.jpg | input image name }"
;
 
int main(int argc, char* argv[])
{
 CommandLineParser parser(argc, argv, keys);
 string strInFileName = parser.get<String>("@image");
 samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/periodic_noise_removing_filter/images");
 
 Mat imgIn = imread(samples::findFile(strInFileName), IMREAD_GRAYSCALE);
 if (imgIn.empty()) //check whether the image is loaded or not
 {
 cout << "ERROR : Image cannot be loaded..!!" << endl;
 return -1;
 }
 
 imshow("Image corrupted", imgIn);
 imgIn.convertTo(imgIn, CV_32F);
 
 // it needs to process even image only
 Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2);
 imgIn = imgIn(roi);
 
 // PSD calculation (start)
 Mat imgPSD;
 calcPSD(imgIn, imgPSD);
 fftshift(imgPSD, imgPSD);
 normalize(imgPSD, imgPSD, 0, 255, NORM_MINMAX);
 // PSD calculation (stop)
 
 //H calculation (start)
 Mat H = Mat(roi.size(), CV_32F, Scalar(1));
 const int r = 21;
 synthesizeFilterH(H, Point(705, 458), r);
 synthesizeFilterH(H, Point(850, 391), r);
 synthesizeFilterH(H, Point(993, 325), r);
 //H calculation (stop)
 // filtering (start)
 Mat imgOut;
 fftshift(H, H);
 filter2DFreq(imgIn, imgOut, H);
 // filtering (stop)
 
 imgOut.convertTo(imgOut, CV_8U);
 normalize(imgOut, imgOut, 0, 255, NORM_MINMAX);
 imwrite("result.jpg", imgOut);
 imwrite("PSD.jpg", imgPSD);
 fftshift(H, H);
 normalize(H, H, 0, 255, NORM_MINMAX);
 imshow("Debluring", imgOut);
 imwrite("filter.jpg", H);
 waitKey(0);
 return 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;
 merge(planesH, 2, complexH);
 Mat complexIH;
 mulSpectrums(complexI, complexH, complexIH, 0);
 
 idft(complexIH, complexIH);
 split(complexIH, planes);
 outputImg = planes[0];
}
 
void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius)
{
 Point c2 = center, c3 = center, c4 = center;
 c2.y = inputOutput_H.rows - center.y;
 c3.x = inputOutput_H.cols - center.x;
 c4 = Point(c3.x,c2.y);
 circle(inputOutput_H, center, radius, 0, -1, 8);
 circle(inputOutput_H, c2, radius, 0, -1, 8);
 circle(inputOutput_H, c3, radius, 0, -1, 8);
 circle(inputOutput_H, c4, radius, 0, -1, 8);
}
 
// Function calculates PSD(Power spectrum density) by fft with two flags
// flag = 0 means to return PSD
// flag = 1 means to return log(PSD)
void calcPSD(const Mat& inputImg, Mat& outputImg, int flag)
{
 Mat planes[2] = { Mat_<float>(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
 Mat complexI;
 merge(planes, 2, complexI);
 dft(complexI, complexI);
 split(complexI, planes); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
 
 planes[0].at<float>(0) = 0;
 planes[1].at<float>(0) = 0;
 
 // compute the PSD = sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)^2
 Mat imgPSD;
 magnitude(planes[0], planes[1], imgPSD); //imgPSD = sqrt(Power spectrum density)
 pow(imgPSD, 2, imgPSD); //it needs ^2 in order to get PSD
 outputImg = imgPSD;
 
 // logPSD = log(1 + PSD)
 if (flag)
 {
 Mat imglogPSD;
 imglogPSD = imgPSD + Scalar::all(1);
 log(imglogPSD, imglogPSD);
 outputImg = imglogPSD;
 }
}

解释

通过频域滤波进行周期性降噪,包括功率谱密度计算(用于噪声尖峰视觉检测)、陷波抑制滤波器合成和频率滤波:

 // it needs to process even image only
 Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2);
 imgIn = imgIn(roi);
 
 // PSD calculation (start)
 Mat imgPSD;
 calcPSD(imgIn, imgPSD);
 fftshift(imgPSD, imgPSD);
 normalize(imgPSD, imgPSD, 0, 255, NORM_MINMAX);
 // PSD calculation (stop)
 
 //H calculation (start)
 Mat H = Mat(roi.size(), CV_32F, Scalar(1));
 const int r = 21;
 synthesizeFilterH(H, Point(705, 458), r);
 synthesizeFilterH(H, Point(850, 391), r);
 synthesizeFilterH(H, Point(993, 325), r);
 //H calculation (stop)
 // filtering (start)
 Mat imgOut;
 fftshift(H, H);
 filter2DFreq(imgIn, imgOut, H);
 // filtering (stop)

函数 calcPSD()计算图像的功率谱密度:

void calcPSD(const Mat& inputImg, Mat& outputImg, int flag)
{
 Mat planes[2] = { Mat_<float>(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
 Mat complexI;
 merge(planes, 2, complexI);
 dft(complexI, complexI);
 split(complexI, planes); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
 
 planes[0].at<float>(0) = 0;
 planes[1].at<float>(0) = 0;
 
 // compute the PSD = sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)^2
 Mat imgPSD;
 magnitude(planes[0], planes[1], imgPSD); //imgPSD = sqrt(Power spectrum density)
 pow(imgPSD, 2, imgPSD); //it needs ^2 in order to get PSD
 outputImg = imgPSD;
 
 // logPSD = log(1 + PSD)
 if (flag)
 {
 Mat imglogPSD;
 imglogPSD = imgPSD + Scalar::all(1);
 log(imglogPSD, imglogPSD);
 outputImg = imglogPSD;
 }
}

函数 synthesizeFilterH()根据中心频率和半径形成理想圆形陷波抑制滤波器的传递函数:

void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius)
{
 Point c2 = center, c3 = center, c4 = center;
 c2.y = inputOutput_H.rows - center.y;
 c3.x = inputOutput_H.cols - center.x;
 c4 = Point(c3.x,c2.y);
 circle(inputOutput_H, center, radius, 0, -1, 8);
 circle(inputOutput_H, c2, radius, 0, -1, 8);
 circle(inputOutput_H, c3, radius, 0, -1, 8);
 circle(inputOutput_H, c4, radius, 0, -1, 8);
}

函数 filter2DFreq()过滤频域中的图像。函数 fftshift()和 filter2DFreq()是从教程 Out-of-focus Deblur Filter 中复制的。

结果

下图显示了被各种频率的周期性噪声严重损坏的图像。

噪声分量很容易被看作是下图所示的功率谱密度中的亮点(尖峰)。

下图显示了具有适当半径的陷波抑制滤波器,以完全封闭噪声尖峰。

使用陷波抑制滤波器处理图像的结果如下所示。

这种改进是显而易见的。与原始图像相比,此图像包含的可见周期性噪声要少得多。

您还可以在 YouTube 上找到此过滤理念的快速视频演示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/594249.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDEA--debug

1. 单点调试的三个级别 Step into&#xff1a;在单步执行时&#xff0c;遇到子函数就进入并且继续单步执行。Step over&#xff1a;在单步执行时&#xff0c;在函数内遇到子函数时不会进入子函数内单步执行&#xff0c;而是将子函数整个执行完再停止&#xff0c;也就是把子函数…

用树莓派2B当web服务器

树莓派2&#xff0c;卡片大小&#xff0c;arm 32位cpu&#xff0c;512G内存。我找了一下购买记录&#xff0c;2013年12月15日买的。带网线接头。属于树莓派2B。以前下载的操作系统还在。是2014年的操作系统&#xff0c;文件名是&#xff1a;2014-09-09-wheezy-raspbian_shumeip…

C语言之整形提升和算术转换

目录 前言 一、整形提升 二、算术转换 总结 前言 本文主要介绍C语言中的整形提升和算术转换的概念和意义&#xff0c;以及例题帮助理解&#xff0c;了解之后&#xff0c;我们就能知道在C语言中&#xff0c;字符型变量如何计算以及如果变量的类型、字节大小不一致的情况下&am…

前端工程化06-JavaScript模块化CommonJS规范ES Module

7、JavaScript模块化 在js开发中&#xff0c;他并没有拆分的概念&#xff0c;并不像java一样他可以拆分很多的包&#xff0c;很多的类&#xff0c;像搭积木一样完成一个大型项目的开发&#xff0c;所以js在前期的时候并不适合大型后端的项目开发&#xff0c;但是这些问题在后来…

Android 10.0 Launcher3 app页面调整workspace边距app行距变小功能实现

1.前言 在10.0的系统rom定制化开发中,在launcher3的一些开发定制功能中,在对于大分辨率比如1600*2560的设备进行开发的时候, 会在竖屏的时候,在默认7*4的布局的时候,显得行距有点宽,这样就需要调整整个CellLayout的上下左右边距,然后就 会显得行距会小一点,接下来具体…

ASP.NET网上书店

摘要 本设计尝试用ASP.NET在网络上架构一个电子书城&#xff0c;以使每一位顾客不用出门在家里就能够通过上网来轻松购书。本文从理论和实践两个角度出发&#xff0c;对一个具有数据挖掘功能电子书城进行设计与实现分析。论文首先较为详尽地介绍了面向对象分析与设计的有关概念…

基于Springboot的房屋租赁管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的房屋租赁管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

图中有几个三角形

让我们先把三角形进行分类&#xff1a;1块组成的三角形、2块组成的三角形、依此类推。 1块组成的三角形有4个&#xff1a; 2块组成的三角形有&#xff1a;12,13,14,23,24,34.其中&#xff0c;14&#xff0c;23构不成三角形. 3块组成的三角形有&#xff1a;123,124,134,234。但…

贪心算法(活动选择、分数背包问题)

一、贪心算法 贪心算法是指&#xff1a;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择&#xff0c;而不从整体最优考虑&#xff0c;做出的仅是在某种意义上的局部最优解。 …

流畅的Python阅读笔记

五一快乐的时光总是飞快了&#xff0c;不知多久没有拿起键盘写文章了&#xff0c;最近公司有Python的需求&#xff0c;想着复习下Python吧&#xff0c;然后就买了本Python的书籍 书名&#xff1a; 《流畅的Python》 下面是整理的一个阅读笔记&#xff0c;大家自行查阅&#xf…

Python 全栈系列241 GFGo Lite迭代

说明 随着整个算网开发逐渐深入&#xff0c;各个组件、微服务的数量、深度在不断增加。由于算网是个人项目&#xff0c;我一直按照MVP(Minimum Viable Product )的原则在推进。由于最初的时候对架构、算法和业务的理解并没有那么深刻&#xff0c;所以MVP的内容还是在不断变化&…

选择深度学习框架:TensorFlow 2 vs PyTorch

TensorFlow 2 vs PyTorch 选择深度学习框架&#xff1a;TensorFlow 2 vs PyTorchTensorFlow 2概述TensorFlow 2的优点TensorFlow 2的缺点 PyTorch概述PyTorch的优点PyTorch的缺点 选择建议对于选择困难症的人&#xff0c;我给你们的答案——PyTorch选择理由&#xff1a;结论&am…

数据结构(C):玩转链表

&#x1f37a;0.前言 言C之言&#xff0c;聊C之识&#xff0c;以C会友&#xff0c;共向远方。各位博友的各位你们好啊&#xff0c;这里是持续分享数据结构知识的小赵同学&#xff0c;今天要分享的数据结构知识是链表&#xff0c;在这一章&#xff0c;小赵将会向大家展开聊聊链表…

常用语音识别开源四大工具:Kaldi,PaddleSpeech,WeNet,EspNet

无论是基于成本效益还是社区支持&#xff0c;我都坚决认为开源才是推动一切应用的动力源泉。下面推荐语音识别开源工具&#xff1a;Kaldi&#xff0c;Paddle&#xff0c;WeNet&#xff0c;EspNet。 1、最成熟的Kaldi 一个广受欢迎的开源语音识别工具&#xff0c;由Daniel Pove…

Servlet框架

简介 Servlet是运行在web服务器或应用服务器上的程序&#xff0c;他是作为来自web浏览器或其他http客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。 使用Servlet可以手机来自网页表单的用户输入&#xff0c;呈现来自数据库或者其他源记录&#xff0c;还可以动态创…

IDEA访问不到静态资源

背景 我在resources下创建static文件夹&#xff0c;再创建front文件夹放前端资源&#xff0c;里面有index.html&#xff0c;游览器输入localhost:8011/front没反应。&#xff08;resources/static/front/index.html&#xff09; 解决办法 重启idea&#xff0c;清楚idea缓存&am…

设计模式之服务定位器模式

想象一下&#xff0c;你的Java应用是一座庞大的迷宫&#xff0c;里面藏着无数宝贵的服务宝藏&#xff0c;而你正需要一张精确的藏宝图来指引方向&#xff0c;迅速找到并利用这些宝藏。服务定位器模式&#xff0c;正是这样一张神奇的地图&#xff0c;它帮你动态定位并获取应用中…

stl容器 string类的基本操作

目录 一.string类的构造 二.string类的输出 1.传统字符串输出 2.通过迭代器进行输出 ​编辑 3.C11标准的范围for输出加auto推导类型 三.string类的各种迭代器 begin(&#xff09;和end() 利用迭代器遍历输出 利用迭代器修改字符串的字符 rbgin()和rend() 利用迭代器遍…

[论文阅读]Adversarial Autoencoders(aae)和代码

In this paper, we propose the “adversarial autoencoder” (AAE), which is a probabilistic autoencoder that uses the recently proposed generative adversarial networks (GAN) to perform variational inference by matching the aggregated posterior of the hidden …

【人工智能基础】RNN实验

一、RNN特性 权重共享 wordi weight bais 持久记忆单元 wordi weightword baisword hi weighth baish 二、公式化表达 ht</sub f(ht - 1, xt) ht tanh(Whhht - 1 Wxhxt) yt Whyht 三、RNN网络正弦波波形预测 环境准备 import numpy as np import torch …