C++ OpenCV 理想滤波

理想低通滤波

在这里插入图片描述
通过设置频率半径,半径内的频率大小不变,半径外的频率置为0,即保留了低频区,滤除了高频区,达到滤波的目的。

#include<iostream>
#include<opencv2/opencv.hpp>
#include "MY_DFT.h"
#include "Salt.h"using namespace cv;
using namespace std;int main()
{ Mat image, image_gray, image_output, image_transform;   //定义输入图像,灰度图像,输出图像image = imread("lena.png");  //读取图像;if (image.empty()){cout << "读取错误" << endl;return -1;}imshow("image", image);cvtColor(image, image_gray, COLOR_BGR2GRAY); //转换为灰度图imshow("image_gray", image_gray); //显示灰度图Salt(image_gray, 1000);imshow("image_gray", image_gray); //显示噪声图//1、傅里叶变换,image_output为可显示的频谱图,image_transform为傅里叶变换的复数结果My_DFT(image_gray, image_output, image_transform);imshow("image_output", image_output);//2、理想低通滤波Mat planes[] = { Mat_<float>(image_output), Mat::zeros(image_output.size(),CV_32F) };split(image_transform, planes);//分离通道,获取实部虚部Mat image_transform_real = planes[0];Mat image_transform_imag = planes[1];int core_x = image_transform_real.rows / 2;//频谱图中心坐标int core_y = image_transform_real.cols / 2;int r = 80;  //滤波半径for (int i = 0; i < image_transform_real.rows; i++){for (int j = 0; j < image_transform_real.cols; j++){//距离中心的距离大于设置半径r的点所在值设为0if (((i- core_x) * (i - core_x) + (j- core_y) * (j - core_y)) > r * r){image_transform_real.at<float>(i, j) = 0;image_transform_imag.at<float>(i, j) = 0;}}}planes[0] = image_transform_real;planes[1] = image_transform_imag;Mat image_transform_ilpf;//定义理想低通滤波矩阵merge(planes, 2, image_transform_ilpf);//3、傅里叶逆变换Mat iDft[] = { Mat_<float>(image_output), Mat::zeros(image_output.size(),CV_32F) };idft(image_transform_ilpf, image_transform_ilpf);//傅立叶逆变换split(image_transform_ilpf, iDft);//分离通道,主要获取0通道magnitude(iDft[0], iDft[1], iDft[0]); //计算复数的幅值,保存在iDft[0]normalize(iDft[0], iDft[0], 0, 1, NORM_MINMAX);//归一化处理imshow("idft", iDft[0]);//显示逆变换图像waitKey(0);  //暂停,保持图像显示,等待按键结束return 0;
}

噪声代码(.h文件)

#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
#include <random>using namespace cv;
using namespace std;void Salt(Mat image, int n);

噪声代码(.cpp文件):

#include "Salt.h"void Salt(Mat image, int n)
{default_random_engine generater;uniform_int_distribution<int>randomRow(0, image.rows - 1);uniform_int_distribution<int>randomCol(0, image.cols - 1);int i, j;for (int k = 0; k < n; k++){i = randomCol(generater);j = randomRow(generater);if (image.channels() == 1){image.at<uchar>(j, i) = 255;}else if (image.channels() == 3){image.at<Vec3b>(j, i)[0] = 255;image.at<Vec3b>(j, i)[1] = 255;image.at<Vec3b>(j, i)[2] = 255;}}
}

傅里叶变换代码(.h文件):

#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
#include<cmath>using namespace cv;
using namespace std;void My_DFT(Mat input_image, Mat& output_image, Mat& transform_array);

傅里叶变换代码(.cpp文件):

#include "MY_DFT.h"//傅里叶变换得到频谱图和复数域结果
void My_DFT(Mat input_image, Mat& output_image, Mat& transform_image)
{//1.扩展图像矩阵,为2,3,5的倍数时运算速度快int m = getOptimalDFTSize(input_image.rows);int n = getOptimalDFTSize(input_image.cols);copyMakeBorder(input_image, input_image, 0, m - input_image.rows, 0, n - input_image.cols, BORDER_CONSTANT, Scalar::all(0));//2.创建一个双通道矩阵planes,用来储存复数的实部与虚部Mat planes[] = { Mat_<float>(input_image), Mat::zeros(input_image.size(), CV_32F) };//3.从多个单通道数组中创建一个多通道数组:transform_image。函数Merge将几个数组合并为一个多通道阵列,即输出数组的每个元素将是输入数组元素的级联merge(planes, 2, transform_image);//4.进行傅立叶变换dft(transform_image, transform_image);//5.计算复数的幅值,保存在output_image(频谱图)split(transform_image, planes); // 将双通道分为两个单通道,一个表示实部,一个表示虚部Mat transform_image_real = planes[0];Mat transform_image_imag = planes[1];magnitude(planes[0], planes[1], output_image); //计算复数的幅值,保存在output_image(频谱图)//6.前面得到的频谱图数级过大,不好显示,因此转换output_image += Scalar(1);   // 取对数前将所有的像素都加1,防止log0log(output_image, output_image);   // 取对数normalize(output_image, output_image, 0, 1, NORM_MINMAX); //归一化//7.剪切和重分布幅度图像限output_image = output_image(Rect(0, 0, output_image.cols & -2, output_image.rows & -2));// 重新排列傅里叶图像中的象限,使原点位于图像中心int cx = output_image.cols / 2;int cy = output_image.rows / 2;Mat q0(output_image, Rect(0, 0, cx, cy));   // 左上区域Mat q1(output_image, Rect(cx, 0, cx, cy));  // 右上区域Mat q2(output_image, Rect(0, cy, cx, cy));  // 左下区域Mat q3(output_image, 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);//右上与左下进行交换Mat q00(transform_image_real, Rect(0, 0, cx, cy));   // 左上区域Mat q01(transform_image_real, Rect(cx, 0, cx, cy));  // 右上区域Mat q02(transform_image_real, Rect(0, cy, cx, cy));  // 左下区域Mat q03(transform_image_real, Rect(cx, cy, cx, cy)); // 右下区域q00.copyTo(tmp); q03.copyTo(q00); tmp.copyTo(q03);//左上与右下进行交换q01.copyTo(tmp); q02.copyTo(q01); tmp.copyTo(q02);//右上与左下进行交换Mat q10(transform_image_imag, Rect(0, 0, cx, cy));   // 左上区域Mat q11(transform_image_imag, Rect(cx, 0, cx, cy));  // 右上区域Mat q12(transform_image_imag, Rect(0, cy, cx, cy));  // 左下区域Mat q13(transform_image_imag, Rect(cx, cy, cx, cy)); // 右下区域q10.copyTo(tmp); q13.copyTo(q10); tmp.copyTo(q13);//左上与右下进行交换q11.copyTo(tmp); q12.copyTo(q11); tmp.copyTo(q12);//右上与左下进行交换planes[0] = transform_image_real;planes[1] = transform_image_imag;merge(planes, 2, transform_image);//将傅里叶变换结果中心化
}

在这里插入图片描述

理想低通滤波会导致振铃效应,因此现实很少使用理想低通滤波器,多使用高斯低通滤波或巴特沃斯低通滤波。

理想高通滤波

在这里插入图片描述

#include<iostream>
#include<opencv2/opencv.hpp>
#include "MY_DFT.h"using namespace cv;
using namespace std;int main()
{Mat image, image_gray, image_output, image_transform;   //定义输入图像,灰度图像,输出图像image = imread("lena.png");  //读取图像;if (image.empty()){cout << "读取错误" << endl;return -1;}imshow("image", image);cvtColor(image, image_gray, COLOR_BGR2GRAY); //转换为灰度图imshow("image_gray", image_gray); //显示灰度图//1、傅里叶变换,image_output为可显示的频谱图,image_transform为傅里叶变换的复数结果My_DFT(image_gray, image_output, image_transform);imshow("image_output", image_output);//2、理想高通滤波Mat planes[] = { Mat_<float>(image_output), Mat::zeros(image_output.size(),CV_32F) };split(image_transform, planes);//分离通道,获取实部虚部Mat image_transform_real = planes[0];Mat image_transform_imag = planes[1];int core_x = image_transform_real.rows / 2;//频谱图中心坐标int core_y = image_transform_real.cols / 2;int r = 20;  //滤波半径for (int i = 0; i < image_transform_real.rows; i++){for (int j = 0; j < image_transform_real.cols; j++){//距离中心的距离大于设置半径r的点所在值设为0if (((i - core_x) * (i - core_x) + (j - core_y) * (j - core_y)) < r * r){image_transform_real.at<float>(i, j) = 0;image_transform_imag.at<float>(i, j) = 0;}}}planes[0] = image_transform_real;planes[1] = image_transform_imag;Mat image_transform_ilpf;//定义理想高通滤波矩阵merge(planes, 2, image_transform_ilpf);//3、傅里叶逆变换Mat iDft[] = { Mat_<float>(image_output), Mat::zeros(image_output.size(),CV_32F) };idft(image_transform_ilpf, image_transform_ilpf);//傅立叶逆变换split(image_transform_ilpf, iDft);//分离通道,主要获取0通道magnitude(iDft[0], iDft[1], iDft[0]); //计算复数的幅值,保存在iDft[0]normalize(iDft[0], iDft[0], 0, 1, NORM_MINMAX);//归一化处理imshow("idft", iDft[0]);//显示逆变换图像waitKey(0);  //暂停,保持图像显示,等待按键结束return 0;
}

傅里叶变换代码(.h文件):

#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
#include<cmath>using namespace cv;
using namespace std;void My_DFT(Mat input_image, Mat& output_image, Mat& transform_array);

傅里叶变换代码(.cpp文件):

#include "MY_DFT.h"//傅里叶变换得到频谱图和复数域结果
void My_DFT(Mat input_image, Mat& output_image, Mat& transform_image)
{//1.扩展图像矩阵,为2,3,5的倍数时运算速度快int m = getOptimalDFTSize(input_image.rows);int n = getOptimalDFTSize(input_image.cols);copyMakeBorder(input_image, input_image, 0, m - input_image.rows, 0, n - input_image.cols, BORDER_CONSTANT, Scalar::all(0));//2.创建一个双通道矩阵planes,用来储存复数的实部与虚部Mat planes[] = { Mat_<float>(input_image), Mat::zeros(input_image.size(), CV_32F) };//3.从多个单通道数组中创建一个多通道数组:transform_image。函数Merge将几个数组合并为一个多通道阵列,即输出数组的每个元素将是输入数组元素的级联merge(planes, 2, transform_image);//4.进行傅立叶变换dft(transform_image, transform_image);//5.计算复数的幅值,保存在output_image(频谱图)split(transform_image, planes); // 将双通道分为两个单通道,一个表示实部,一个表示虚部Mat transform_image_real = planes[0];Mat transform_image_imag = planes[1];magnitude(planes[0], planes[1], output_image); //计算复数的幅值,保存在output_image(频谱图)//6.前面得到的频谱图数级过大,不好显示,因此转换output_image += Scalar(1);   // 取对数前将所有的像素都加1,防止log0log(output_image, output_image);   // 取对数normalize(output_image, output_image, 0, 1, NORM_MINMAX); //归一化//7.剪切和重分布幅度图像限output_image = output_image(Rect(0, 0, output_image.cols & -2, output_image.rows & -2));// 重新排列傅里叶图像中的象限,使原点位于图像中心int cx = output_image.cols / 2;int cy = output_image.rows / 2;Mat q0(output_image, Rect(0, 0, cx, cy));   // 左上区域Mat q1(output_image, Rect(cx, 0, cx, cy));  // 右上区域Mat q2(output_image, Rect(0, cy, cx, cy));  // 左下区域Mat q3(output_image, 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);//右上与左下进行交换Mat q00(transform_image_real, Rect(0, 0, cx, cy));   // 左上区域Mat q01(transform_image_real, Rect(cx, 0, cx, cy));  // 右上区域Mat q02(transform_image_real, Rect(0, cy, cx, cy));  // 左下区域Mat q03(transform_image_real, Rect(cx, cy, cx, cy)); // 右下区域q00.copyTo(tmp); q03.copyTo(q00); tmp.copyTo(q03);//左上与右下进行交换q01.copyTo(tmp); q02.copyTo(q01); tmp.copyTo(q02);//右上与左下进行交换Mat q10(transform_image_imag, Rect(0, 0, cx, cy));   // 左上区域Mat q11(transform_image_imag, Rect(cx, 0, cx, cy));  // 右上区域Mat q12(transform_image_imag, Rect(0, cy, cx, cy));  // 左下区域Mat q13(transform_image_imag, Rect(cx, cy, cx, cy)); // 右下区域q10.copyTo(tmp); q13.copyTo(q10); tmp.copyTo(q13);//左上与右下进行交换q11.copyTo(tmp); q12.copyTo(q11); tmp.copyTo(q12);//右上与左下进行交换planes[0] = transform_image_real;planes[1] = transform_image_imag;merge(planes, 2, transform_image);//将傅里叶变换结果中心化
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

25-RVIZ CARLA插件

RVIZ插件(RVIZ plugin)提供了一个基于RVIZ(RVIZ) ROS包的可视化工具。 用RVIZ运行ROS桥接 RVIZ插件需要一个名为ego_vehicle的自车。要查看ROS-bridge使用RVIZ的示例&#xff0c;请在运行CARLA服务器的情况下执行以下命令&#xff1a; 1. 启用RVIZ启动ROS桥接&#xff1a; # …

鸿蒙OS带来前端的机遇:ArkTS与Typescript+ArkUI与SwiftUI的简单对比你就知道了

随着鸿蒙系统的不断发展&#xff0c;它已逐渐成为智能设备领域的第三大操作系统&#xff0c;与安卓和iOS形成三足鼎立之势。鸿蒙系统不仅在智能手机领域崭露头角&#xff0c;其在智能穿戴、车载、家居等领域的应用也在不断扩展。对于开发者而言&#xff0c;鸿蒙生态的崛起不仅带…

Java+Swing实现的五子棋游戏

JavaSwing实现的五子棋游戏 一、系统介绍二、功能展示1.游戏展示 三、系统实现1.ChessFrame .java 四、其它1.其他系统实现 一、系统介绍 五子棋游戏实现人机对战、人人对战两个模式。 二、功能展示 1.游戏展示 三、系统实现 1.ChessFrame .java package five;import java…

C语言实验 顺序结构

时间&#xff1a;2024.11.1 实验一、7-1 逆序的三位数 #include<stdio.h> int main(){int n,a,b,c;scanf("%d",&n);an%10;bn/10%10;cn/100;printf("%d",a*100b*10c);return 0; }实验二、7-2 求整数均值 #include<stdio.h> int main(){int…

图形几何之美系列:三维实体结构表达

“ 图形几何库提供丰富的几何工具算法&#xff0c;如基础的仿射变换、向量运算、关系计算及高阶的布尔运算、网格剖分、实体造型、曲线曲面等&#xff0c;这离不开基础的三维实体结构表达&#xff0c;而三维实体结构表达的方式有多种&#xff0c;各具特点。” ​ 1.背景简述 …

华为OD机试真题(Python/JS/C/C++)- 考点 - 细节

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题 点这里。 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。

CTFshow之信息收集第1关到10关。详细讲解

得而不惜就该死&#xff01; --章总 开始新的篇章&#xff01; 零、目录 一、实验准备 1、ctf网站&#xff1a;ctf.show 2、工具&#xff1a;chrome浏览器、hackbar插件 3、burpsuite抓包工具 二、实验技巧 &#xff08;一&#xff09;F12摸奖 源码泄露 &#xff08;二…

AI驱动的医疗创新:信息抽取与知识图谱在临床应用中的转变

一、思通数科平台支持多种输入格式&#xff0c;如电子病历、临床数据和医学文献等&#xff0c;并能将这些信息快速转换为结构化数据&#xff0c;包括自动360度不同角度的旋转识别&#xff0c;提升数据的可操作性和可检索性。通过我们的解决方案&#xff0c;医疗机构能够有效整合…

js | undefined vs null vs void 0

背景 你就说为啥吧&#x1f447; console.log(nullundefined,nullundefined); // true false console.log(null false,undefinedfalse) // fasle false console.log(0false,NaNfalse) // true falseconsole.log(0null,0<null); // false true console.log(0false,0<fa…

【YOLOv11[基础]】实例分割Seg | 导出ONNX模型 | ONN模型推理以及检测结果可视化 | python

本文将导出YOLO-Seg.pt模型对应的ONNX模型,并且使用ONNX模型推理以及结果的可视化。话不多说,先看看效果图吧!!! 目录 一 导出ONNX模型 二 推理及检测结果可视化 1 代码 2 效果图

qt QDataStream详解

1. 概述 QDataStream是Qt框架中的一个核心类&#xff0c;主要用于处理二进制数据的序列化和反序列化。它提供了高效、跨平台的方式&#xff0c;将C数据结构转化为字节流&#xff0c;便于在网络传输、持久化存储等场景下使用。QDataStream可以处理包括整数、浮点数、布尔值、字…

云专线优势有哪些?对接入网络有什么要求?

云专线是一种连接企业本地数据中心与云服务提供商之间的专用网络连接方式&#xff0c;具有以下优势&#xff1a; 高安全性&#xff1a;云专线提供了物理隔离的数据传输通道&#xff0c;减少了数据在公共互联网上传输时可能遭遇的安全风险。 低延迟&#xff1a;由于是直接连接&a…

使用python向钉钉群聊发送消息

使用python向钉钉群聊发送消息 一、在钉钉群中新建机器人二、使用代码发送消息 一、在钉钉群中新建机器人 在群设置中添加机器人 选择自定义 勾选对应的安全设置 完成后会展示webhook&#xff0c;将地址复制出来&#xff0c;并记录&#xff0c;后面会用到 二、使用代码发送消…

简单又便宜的实现电脑远程开机唤醒方法

现有的远程开机方案 1&#xff09;使用向日葵开机棒 缺点是比较贵一点&#xff0c;开机棒要一百多&#xff0c;而且查了评论发现挺多差评说不稳定&#xff0c;会有断联和无法唤醒的情况&#xff0c;而且设置也麻烦&#xff0c;还需要网卡支持WOL 2&#xff09;使用远程开机卡 …

Netty ByteBuf 分配 | 池化复用 、直接内存

Netty ByteBuf 分配 本文主要内容关于 ByteBuf 分配介绍&#xff0c;为了更好的理解本文&#xff0c;我们可以带着几个问题思考 在IO密集型业务场景下&#xff0c;可能涉及大量ByteBuf分配&#xff0c;这时我们需 要考虑会不会产生OOM会不会出现频繁GC会不会内存泄露 根据上…

推荐一款windows右键管理工具:ContextMenuManager

Windows右键菜单管理工具是一款可以为系统打造一个异常丰富的右键菜单组&#xff0c;能自定义添加右键菜单项和管理“发送到”及第三方程序添加的右键菜单项目。 主要功能 一个纯粹的Windows右键菜单管理程序 • 管理常见位置右键菜单、自定义添加右键菜单 • 启用或禁用文件…

#渗透测试#SRC漏洞挖掘#自动化脚本的编写01

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

个人学习记录平台的

摘 要 随着互联网的不断发展&#xff0c;人们由Web 1.0以静态、单向阅读为主的只读式网络走向了以分享为内核的实时现代化网络&#xff0c;即Web 2.0时代逐渐向着Web 3.0迈进。 随着技术的不断更新迭代&#xff0c;互联网从业者也必须处于终身学习的状态&#xff0c;他们要不…

算法日记 14—16 day 二叉树

前两天没有更新&#xff0c;这次把之前的补上&#xff0c;大篇章。 直接冲&#xff01;&#xff01;&#xff01; 题目&#xff1a;找树坐下角的值 513. 找树左下角的值 - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最…

第三十一章 Vue之路由(VueRouter)

目录 一、引言 1.1. 路由介绍 二、VueRouter 三、VueRouter的使用 3.1. 使用步骤&#xff08;52&#xff09; 3.2. 完整代码 3.2.1. main.js 3.2.2. App.vue 3.2.3. Friend.vue 3.2.4. My.vue 3.2.5. Find.vue 一、引言 1.1. 路由介绍 Vue中路由就是路径和组件的映…