离散傅里叶变化

傅里叶变换

对傅里叶变换了解不是很清楚的朋友推荐一下这个帖子,讲得很详细 傅里叶变换

源码

先看源码链接

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
 
#include <iostream>
 
using namespace cv;
using namespace std;
 
static void help(char ** argv)
{
    cout << endl
         << "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl
         << "The dft of an image is taken and it's power spectrum is displayed." << endl << endl
         << "Usage:" << endl
         << argv[0] << " [image_name -- default lena.jpg]" << endl << endl;
}
 
int main(int argc, char ** argv)
{
    help(argv);

    const char* filename = argc >=2 ? argv[1] : "lena.jpg";

    // 读取灰度图像
    Mat I = imread(samples::findFile(filename), IMREAD_GRAYSCALE);
    if(I.empty()){
        cout << "Error opening image" << endl;
        return EXIT_FAILURE;
    }

    // 扩展输入图像到最优尺寸
    Mat padded; 
    int m = getOptimalDFTSize(I.rows);
    int n = getOptimalDFTSize(I.cols); 
    copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));

    // 创建包含实部和虚部的平面
    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexI;
    merge(planes, 2, complexI); // 合并成一个复数矩阵

    // 进行DFT变换
    dft(complexI, complexI);

    // 计算幅度谱并转换为对数尺度
    split(complexI, planes); // 分离实部和虚部
    magnitude(planes[0], planes[1], planes[0]); // 计算幅度
    Mat magI = planes[0];

    magI += Scalar::all(1); // 转换为对数尺度
    log(magI, magI);

    // 如果频谱的行列是奇数,则进行裁剪
    magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));

    // 重新排列傅里叶图像的象限,使原点在图像中心
    int cx = magI.cols/2;
    int cy = magI.rows/2;

    Mat q0(magI, Rect(0, 0, cx, cy)); // 左上
    Mat q1(magI, Rect(cx, 0, cx, cy)); // 右上
    Mat q2(magI, Rect(0, cy, cx, cy)); // 左下
    Mat q3(magI, 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);

    // 归一化幅度图像到0-1之间
    normalize(magI, magI, 0, 1, NORM_MINMAX);

    // 显示原图像和频谱图像
    imshow("Input Image", I);
    imshow("spectrum magnitude", magI);
    waitKey();

    return EXIT_SUCCESS;
}
}

原理

傅里叶变换将图像分解为其正弦和余弦分量。这就意味着,傅里叶变换可以将复杂的图像表示为不同频率和振幅的正弦波和余弦波的组合,这些波的频率和相位描述了图像的周期性结构。低频成分对应图像中的大面积平滑区域,高频成分对应图像中的边缘和细节。
在这里插入图片描述

空间域和频域

  • f : 图像在空间域中的值,即图像像素的强度值。
  • F :图像在频域中的值,即通过傅里叶变换后的结果。

傅里叶变换结果

傅里叶变换将图像从空间域转换到频域,其结果是复数,这意味着每个频率分量有两个部分:实部和虚部。通过所保留地完整的复数信息,可以重新变回空间域。链接

显示频域图像

有两种方式来显示频域图像:

  1. 实部和虚部图像:分别显示傅里叶变换结果的实部和虚部
  2. 幅度和相位图像: 幅度图像和相位图像分别显示每个频率分量的强度和相位信息。

在图像处理中,通常情况下我们只会针对幅度图像做进一步研究,因为其包含了图像几何结构的所有信息。幅度图像显示了频率分量的强度,这与图像的结构和边缘有关。

对于数字图像来说,其经过傅里叶变换所获得的幅度图像是离散的,这也就意味着他们可以从指定的域值中取值,比如说,在基本的灰度图中,像素值通常在0到255之间,因此傅里叶变换也需要是离散类型的。

以下是一个以灰度图为输入例子的步骤详解。

Steps

  1. 将图像拓展到合适的大小
    DFT的性能主要取决于图像的大小,其会在当图像大小为2,3,5的倍数时达到最佳性能。因此,为了达到最佳性能,通常需要对图像的边界进行填充,使用 getOptimalDFTSize()copyMakeBorder() 进行拓展。
Mat padded;
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols);
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
  1. 存储复数和实数
    保留复数,可以通过复数来重新转换到空间域。
 Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
 Mat complexI;
 merge(planes, 2, complexI); // Add to the expanded another plane with zeros
  1. 做离散傅里叶变换
 dft(complexI, complexI); // this way the result may fit in the source matrix
  1. 将实值和复值转换为图像强度值
    在这里插入图片描述
    复数由实部和虚部组成,在图像处理和傅里叶变换中,复数表示在频域中的图像信息。
 split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
 magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
 Mat magI = planes[0];
  1. 切换到对数刻度
    结果是傅里叶系数的动态范围太大,无法在屏幕上显示。我们有一些小的和大的变化值我们不能像这样观察到。因此,高值将全部显示为白色点,而小的则显示为黑色点。为了使用灰度值进行可视化,我们可以将线性刻度转换为对数刻度:
    在这里插入图片描述
 magI += Scalar::all(1); // switch to logarithmic scale
 log(magI, magI);
  1. 裁剪和重新排列
    由于我们在一开始就拓展了图像,现在是时候将新引入的值去掉。为了可视化的目的,我们还可以重新排列结果的象限,使原点(0,0)与图像中心对应。
 // crop the spectrum, if it has an odd number of rows or columns
 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
 
 // rearrange the quadrants of Fourier image so that the origin is at the image center
 int cx = magI.cols/2;
 int cy = magI.rows/2;
 
 Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
 Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
 Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
 Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
 
 Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
 q0.copyTo(tmp);
 q3.copyTo(q0);
 tmp.copyTo(q3);
 
 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
 q2.copyTo(q1);
 tmp.copyTo(q2);
  1. 归一化
    再次这样做是为了可视化。我们现在有了大小,但是它仍然在0到1的图像显示范围之外。我们使用**cv::normalize()**函数将值规范化到这个范围。
 normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a
 // viewable image form (float between values 0 and 1).

应用示例:确定图像中的几何方向

我们可以利用傅里叶变换来确定图像中的几何方向。例如,我们可以判断文本是否是水平的。观察一些文本时,你会注意到文本行形成了水平线,而字母形成了垂直线。这两个主要组成部分也可以在傅里叶变换的结果中看到。我们可以使用水平和旋转的文本图像来实现这一点。

水平方向
在这里插入图片描述
旋转方向
在这里插入图片描述
可以看到,频域最具影响力的分量(星等图像上最亮的点)遵循图像上物体的几何旋转。由此,我们可以计算偏移量并执行图像旋转以纠正最终的未对准。

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

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

相关文章

FuTalk设计周刊-Vol.026

&#x1f525;&#x1f525;AI漫谈 热点捕手&#x1f525;&#x1f525; 1、Hotshot-XL AI文本转GIF Hotshot-XL 是一种 AI 文本转 GIF 模型&#xff0c;经过训练可与Stable Diffusion XL一起使用。能够使用任何现有或新微调的 SDXL 模型制作 GIF。 网页体验 网页http://htt…

git 初基本使用-----------笔记(结合idea)

Git命令 下载git 打开Git官网&#xff08;git-scm.com&#xff09;&#xff0c;根据自己电脑的操作系统选择相应的Git版本&#xff0c;点击“Download”。 基本的git命令使用 可以在项目文件下右击“Git Bash Here” &#xff0c;也可以命令终端下cd到指定目录执行初始化命令…

聚类算法(3)---K-means 算法

本篇文章是博主在人工智能等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学习笔记&#…

软件测试的目的和原则介绍,软件测试外包公司推荐

在当今信息技术迅速发展的时代&#xff0c;软件产品的质量和安全性对用户至关重要。而软件测试作为保障软件产品质量的关键一环&#xff0c;具有不可或缺的作用。 软件测试的目的是为了发现和解决软件产品中的缺陷和问题&#xff0c;确保软件的稳定和可靠性。软件测试帮助找出…

表格截图怎么转换成表格?6个软件帮助你快速进行表格转换

表格截图怎么转换成表格&#xff1f;6个软件帮助你快速进行表格转换 将表格截图转换为可编辑的表格文件是处理数据时常见的需求&#xff0c;特别是在需要分析或编辑图像中包含的信息时。以下是几款帮助你快速进行表格转换的软件和工具&#xff0c;它们提供了不同的功能和适用场…

揭秘!这款电路设计工具让学校师生都爱不释手——SmartEDA的魔力何在?

随着科技的飞速发展&#xff0c;电子设计已成为学校师生们不可或缺的技能之一。而在众多的电路设计工具中&#xff0c;有一款名为SmartEDA的工具&#xff0c;凭借其强大的功能和友好的用户体验&#xff0c;迅速赢得了广大师生的青睐。今天&#xff0c;就让我们一起探索SmartEDA…

游泳耳机入耳式好还是骨传导好?游泳教练力荐实力卓绝的四大热款

作为一名长期致力于游泳爱好者健康与运动体验提升的专业教练&#xff0c;我深知在水中听音乐的魅力&#xff0c;同时也深知选择正确的耳机对于水上运动的重要性。近年来&#xff0c;市场上的游泳耳机类型日益丰富&#xff0c;其中入耳式和骨传导两大主流各有千秋。今天&#xf…

系统运维面试题总结(网络基础类)

系统运维面试题总结&#xff08;网络基础类&#xff09; 网络基础类第七层&#xff1a;应用层第六层&#xff1a;表示层第五层&#xff1a;会话层第四层&#xff1a;传输层第三层&#xff1a;网络层第二层&#xff1a;数据链路层第一层&#xff1a;物理层 类似面试题1、TCP/IP四…

停更公告

由于csdn越来越流氓了&#xff0c;我永久停更&#xff0c;专注于网站建设&#xff08;亚运奥运素材网&#xff09;qdhca.asiahttp://qdhca.asia/

Linux之prometheus安装和使用简介(一)

一、prometheus简介 普罗米修斯Prometheus是一个开源系统监控和警报工具包&#xff0c;最初构建于SoundCloud。自2012年成立以来&#xff0c;许多公司和组织都采用了普罗米修斯&#xff0c;该项目拥有非常活跃的开发人员和用户社区。它现在是一个独立的开源项目&#xff0c;独立…

如何使用WxPusher向个人微信推送发送实时消息,比如定时任务等

wxpusher-sdk-java这个框架开源了&#xff1a;GitHub - wxpusher/wxpusher-sdk-java: 微信消息实时推送服务[WxPusher]的Java版本sdk&#xff0c;可以通过API实时给个人微信推送消息。wechat pusher. 文档地址&#xff1a;WxPusher微信推送服务 WxPusher (微信推送服务)是一个…

【启明智显分享】典型的HMI应用实现方案:帮你更好地主控选型!

HMI是操作者与机器/系统间资讯传递和交换的主要桥梁。HMI系统通常能提供丰富的资讯&#xff0c;例如温度、压力、制造流程步骤以及材料的计量数据。还能显示设备中物料的确切位置或储存槽内的液位数据等讯息。无论是在工业自动化还是医疗、商业等重要行业领域&#xff0c;HMI都…

使用Retrofit2+OkHttp监听上传或者下载进度会执行两次的问题

使用Retrofit2OkHttp监听上传或者下载进度RequestBody#writeTo/ResponseBody#source 会执行两次的问题 example&#xff1a; 问题原因&#xff1a; 使用了HttpLoggingInterceptor拦截器&#xff0c;并且日志等级为HttpLoggingInterceptor.Level.BODY 问题解决&#xff1a;

【Linux】环境基础开发工具使用(yum、vim、gcc/g++、gdb、make/Makefile)

文章目录 Linux 软件包管理器 yumLinux开发工具Linux编辑器-vim使用vim的基本概念vim下各模式的切换vim命令模式各命令汇总vim底行模式各命令汇总批量化注释和批量化去注释vim简单的配置解决一个小问题 Linux编译器-gcc/g作用gcc/g 语法预处理编译汇编链接什么是函数库 Linux调…

【第一周】认识小程序

目录 认识小程序发展历史发展前景发展优势个人企业/创业 账号申请开发工具下载流程使用说明 协作项目交流收益渠道 认识小程序 发展历史 微信小程序自2016年首次提出以来&#xff0c;经历了快速的发展和完善过程&#xff0c;以下是其主要发展历史节点&#xff1a; 2016年1月…

vue3 中的根据某些特定的文字来筛选数组数据

现在有一批这样的数据 这样的数据 我想根据 hallName 来筛选数据 比如关键字有 我不需要 带有下面字符换的数组数据 const importantData ref(["VIP", "CINITY", "杜比", "IMAX", "4DX", vip, Vip]) 使用some 方法 arr…

手机端调试工具 vconsole、eruda 使用方法

在手机端能正常查看log及网络请求。。 1.eruda: 在 index.html 中引入&#xff1a; /** 科学上网地址 */ <script src"https://cdn.jsdelivr.net/npm/eruda"></script> /** 国内访问地址 */ <script src"https://fastly.jsdelivr.net/npm/eru…

ARP欺骗

一、什么是ARP ARP欺骗是一种针对以太网地址解析协议&#xff08;ARP&#xff09;的攻击技术&#xff0c;通过伪造ARP数据包来篡改目标计算机的ARP缓存&#xff0c;实现中间人攻击或拒绝服务攻击。 ARP协议的基本功能是通过目标设备的IP地址查询其MAC地址&#xff0c;以保证网…

VMware虚拟机三种网络模式设置 - Host-Only(仅主机模式)

一、前言 在之前的《Bridged&#xff08;桥接模式&#xff09;》、《NAT&#xff08;网络地址转换模式&#xff09;》中&#xff0c;我详细介绍了虚拟机网络模式设置中的桥接模式与网络地址转换模式。今天详细讲解一下Host-Only&#xff08;仅主机模式&#xff09;。 在VMware虚…

为什么说展厅数字人是展览未来的趋势?

展厅数字人是利用数字化、智能化和网络化等信息技术手段提升展厅展览服务和游览体验的全新载体。随着人工智能和虚拟现实技术的应用发展&#xff0c;展厅数字人已成为展厅展览转型升级的重要趋势。 展厅数字人凭借其创新性、强可塑性&#xff0c;成为展厅新名片&#xff0c;为各…