利用幅度谱和相位谱重构图像

news/2024/11/19 19:24:29/

一、概要
图像经过傅里叶变换后,将图像在空域中的信息映射至频域空间中。图像的频域空间包含幅度谱以及相位谱,其中幅度谱反映的是图像的灰度信息,相位谱反应的是图像的位置信息,如轮廓。
本博文将基于傅里叶分析理论演示利用幅度谱与相位谱重构图像的过程,并验证幅度谱与相位谱在图像重构过程中的作用,最后在本文末给出全部代码。
二、图像的傅里叶变换及其可视化
首先将图像进行傅里叶变换得到图像的频谱并使其可视化。在这里应当注意傅里叶变换对是复数,因此需要构建双通道的Mat类存储复数的实部与虚部。
代码的主函数部分:

int main()
{Mat src = imread("T.jpg");Mat gray_src;cvtColor(src, gray_src, CV_BGR2GRAY);imshow("灰度化输入图像", gray_src);int m = getOptimalDFTSize(gray_src.rows);int n = getOptimalDFTSize(gray_src.cols);Mat padded;copyMakeBorder(gray_src, padded, 0, m - gray_src.rows, 0, n - gray_src.cols, BORDER_CONSTANT, Scalar::all(0));padded.convertTo(padded, CV_32FC1);//中心化for (int row = 0; row < padded.rows; row++){for (int col = 0; col < padded.cols; col++){padded.at<float>(row, col) *= pow(-1, row + col);}}Mat planes[] = { Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F) };Mat complexI;merge(planes, 2, complexI);dft(complexI, complexI);split(complexI, planes);//显示幅度谱和相位谱Show_Spectrum(planes[0], planes[1]);//利用相位谱重构图像Phase_Spectrum_Reconstruction(planes[0], planes[1]);//利用幅度谱重构图像Amplitude_Spectrum_Reconstruction(planes[0], planes[1]);//利用幅度谱和相位谱重构图像Amplitude_Phase_Spectrum_Reconstruction(planes[0], planes[1]);waitKey(0);system("pause");return 0;
}

对图像求得傅里叶变换后,将图像的频谱可视化。该部分的子函数如下所示:

//根据幅度谱的定义计算傅里叶变换的幅度谱
Mat Magnitude(Mat Re, Mat Im)
{Mat rst = Mat::zeros(Re.rows, Re.cols, CV_32F);for (int row = 0; row < Re.rows; row++){for (int col = 0; col < Re.cols; col++){rst.at<float>(row, col) = sqrt(pow(Re.at<float>(row, col), 2) + pow(Im.at<float>(row, col), 2));}}return rst;
}
//根据相位谱的定义计算傅里叶变换的相位谱
Mat Phase(Mat Re, Mat Im)
{Mat rst = Mat::zeros(Re.rows, Re.cols, CV_32F);for (int row = 0; row < Re.rows; row++){for (int col = 0; col < Re.cols; col++){rst.at<float>(row, col) = atan2(Im.at<float>(row, col), Re.at<float>(row, col));}}return rst;
}
//显示图像的相位谱和幅度谱
void Show_Spectrum(Mat Re, Mat Im)
{Mat amplitude = Magnitude(Re, Im);Mat angle = Phase(Re, Im);amplitude += Scalar::all(1);log(amplitude, amplitude);normalize(amplitude, amplitude, 0, 1, NORM_MINMAX);normalize(angle, angle, 0, 1, NORM_MINMAX);imshow("图像傅里叶变换的幅度谱", amplitude);imshow("图像傅里叶变换的相位谱", angle);
}

本例使用泰勒斯威夫特的图片进行演示,输入图像如下:
在这里插入图片描述
将上图灰度化后得到单通道的灰度图像,对该灰度图像进行傅里叶变换后得到的幅度谱如下图所示:
在这里插入图片描述
相位谱如下图所示:
在这里插入图片描述
三、利用相位谱重构图像
经过上面的傅里叶变换容易得到图像的相位谱与幅度谱,此时图像的傅里叶谱为|F(u,v)|*exp(jφ(u,v))。令|F(u,v)|=1,得到图像的相位谱exp(jφ(u,v))。最后利用欧拉公式得到: exp(jφ(u,v))=cos(φ(u,v))+jsin(φ(u,v))。
代码实现时创建一个双通道的Mat类存储相位谱的实部与虚部,然后对相位谱进行傅里叶反变换即可。
该部分的子函数如下所示:

void Phase_Spectrum_Reconstruction(Mat Re, Mat Im)
{Mat angle = Phase(Re, Im);Mat Phase_Spectrum = Mat::zeros(angle.rows, angle.cols, CV_32FC2);//定义一个双通道的Mat类分别存储相位谱的实部与虚部for (int row = 0; row < Phase_Spectrum.rows; row++){for (int col = 0; col < Phase_Spectrum.cols; col++){Phase_Spectrum.at<Vec2f>(row, col)[0] = cos(angle.at<float>(row, col));//实部Phase_Spectrum.at<Vec2f>(row, col)[1] = sin(angle.at<float>(row, col));//虚部}}idft(Phase_Spectrum, Phase_Spectrum);Mat temp[] = { Mat_<float>(angle),Mat::zeros(angle.size(),CV_32F) };split(Phase_Spectrum, temp);magnitude(temp[0], temp[1], temp[0]);normalize(temp[0], temp[0], 0, 1, CV_MINMAX);imshow("相位谱重构图像", temp[0]);
}

利用相位谱重构的图像如下图所示:
在这里插入图片描述
利用相位谱很好的将图像的轮廓信息重构了出来,由此容易验证图像的相位谱存储的是图像的位置信息。但是由于缺乏幅度谱,因此重构后的图像缺少像素值上的变化。
四、利用幅度谱重构图像
令图像的傅里叶谱|F(u,v)|*exp(jφ(u,v))中的相位谱φ(u,v)等于0,得到幅度谱|F(u,v)|,然后对幅度谱进行傅里叶变换重构图像。
该部分的子函数如下所示:

void Amplitude_Spectrum_Reconstruction(Mat Re, Mat Im)
{Mat amplitude = Magnitude(Re, Im);Mat Amplitude_Spectrum = Mat::zeros(amplitude.rows, amplitude.cols, CV_32FC2);//定义一个双通道的Mat类分别存储幅度谱谱的实部与虚部for (int row = 0; row < Amplitude_Spectrum.rows; row++){for (int col = 0; col < Amplitude_Spectrum.cols; col++){Amplitude_Spectrum.at<Vec2f>(row, col)[0] = amplitude.at<float>(row, col)*pow(-1, row + col);//实部Amplitude_Spectrum.at<Vec2f>(row, col)[1] = 0;//虚部}}idft(Amplitude_Spectrum, Amplitude_Spectrum);Mat temp[] = { Mat_<float>(amplitude),Mat::zeros(amplitude.size(),CV_32F) };split(Amplitude_Spectrum, temp);magnitude(temp[0], temp[1], temp[0]);normalize(temp[0], temp[0], 0, 1, CV_MINMAX);imshow("幅度谱重构图像", temp[0]);
}

利用幅度谱重构图像得到的结果如下图所示:
在这里插入图片描述
由幅度谱无法重构原来的图像,这也验证了幅度谱只包含图像的灰度信息,对图像内容起决定性作用的是图像的相位谱。
五、利用幅度谱和相位谱重构图像
利用欧拉公式得到:|F(u,v)|*exp(jφ(u,v))=|F(u,v)|*cos(φ(u,v))+j|F(u,v)|*sin(φ(u,v))。
代码实现时创建一个双通道的Mat类存储上述傅里叶谱的实部与虚部,然后对其进行傅里叶反变换即可。
该部分的子函数如下所示:

void Amplitude_Phase_Spectrum_Reconstruction(Mat Re, Mat Im)
{Mat angle = Phase(Re, Im);Mat amplitude = Magnitude(Re, Im);Mat Amplitude_Phase_Spectrum = Mat::zeros(angle.rows, angle.cols, CV_32FC2);//定义一个双通道的Mat类分别存储相位谱的实部与虚部for (int row = 0; row < Amplitude_Phase_Spectrum.rows; row++){for (int col = 0; col < Amplitude_Phase_Spectrum.cols; col++){Amplitude_Phase_Spectrum.at<Vec2f>(row, col)[0] = amplitude.at<float>(row, col)*cos(angle.at<float>(row, col));//实部Amplitude_Phase_Spectrum.at<Vec2f>(row, col)[1] = amplitude.at<float>(row, col)*sin(angle.at<float>(row, col));//虚部}}idft(Amplitude_Phase_Spectrum, Amplitude_Phase_Spectrum);Mat temp[] = { Mat_<float>(angle),Mat::zeros(angle.size(),CV_32F) };split(Amplitude_Phase_Spectrum, temp);magnitude(temp[0], temp[1], temp[0]);normalize(temp[0], temp[0], 0, 1, CV_MINMAX);imshow("利用幅度谱和相位谱重构图像", temp[0]);
}

利用图像的幅度谱和相位谱重构的图像如下图所示:
在这里插入图片描述
很显然利用图像的幅度谱与相位谱完美的重构了图像。
六、完整代码

#include<iostream>
#include<opencv2/opencv.hpp>
#include<math.h>
#include<complex.h>
#include<complex>
using namespace std;
using namespace cv;
Mat Magnitude(Mat Re, Mat Im);
Mat Phase(Mat Re, Mat Im);
void Show_Spectrum(Mat Re, Mat Im);
void Phase_Spectrum_Reconstruction(Mat Re, Mat Im);
void Amplitude_Spectrum_Reconstruction(Mat Re, Mat Im);
void Amplitude_Phase_Spectrum_Reconstruction(Mat Re, Mat Im);
int main()
{Mat src = imread("T.jpg");Mat gray_src;cvtColor(src, gray_src, CV_BGR2GRAY);imshow("灰度化输入图像", gray_src);int m = getOptimalDFTSize(gray_src.rows);int n = getOptimalDFTSize(gray_src.cols);Mat padded;copyMakeBorder(gray_src, padded, 0, m - gray_src.rows, 0, n - gray_src.cols, BORDER_CONSTANT, Scalar::all(0));padded.convertTo(padded, CV_32FC1);//中心化for (int row = 0; row < padded.rows; row++){for (int col = 0; col < padded.cols; col++){padded.at<float>(row, col) *= pow(-1, row + col);}}Mat planes[] = { Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F) };Mat complexI;merge(planes, 2, complexI);dft(complexI, complexI);split(complexI, planes);//显示幅度谱和相位谱Show_Spectrum(planes[0], planes[1]);//利用相位谱重构图像Phase_Spectrum_Reconstruction(planes[0], planes[1]);//利用幅度谱重构图像Amplitude_Spectrum_Reconstruction(planes[0], planes[1]);//利用幅度谱和相位谱重构图像Amplitude_Phase_Spectrum_Reconstruction(planes[0], planes[1]);waitKey(0);system("pause");return 0;
}
Mat Magnitude(Mat Re, Mat Im)
{Mat rst = Mat::zeros(Re.rows, Re.cols, CV_32F);for (int row = 0; row < Re.rows; row++){for (int col = 0; col < Re.cols; col++){rst.at<float>(row, col) = sqrt(pow(Re.at<float>(row, col), 2) + pow(Im.at<float>(row, col), 2));}}return rst;
}
Mat Phase(Mat Re, Mat Im)
{Mat rst = Mat::zeros(Re.rows, Re.cols, CV_32F);for (int row = 0; row < Re.rows; row++){for (int col = 0; col < Re.cols; col++){rst.at<float>(row, col) = atan2(Im.at<float>(row, col), Re.at<float>(row, col));}}return rst;
}
void Show_Spectrum(Mat Re, Mat Im)
{Mat amplitude = Magnitude(Re, Im);Mat angle = Phase(Re, Im);amplitude += Scalar::all(1);log(amplitude, amplitude);normalize(amplitude, amplitude, 0, 1, NORM_MINMAX);normalize(angle, angle, 0, 1, NORM_MINMAX);imshow("图像傅里叶变换的幅度谱", amplitude);imshow("图像傅里叶变换的相位谱", angle);
}
void Phase_Spectrum_Reconstruction(Mat Re, Mat Im)
{Mat angle = Phase(Re, Im);Mat Phase_Spectrum = Mat::zeros(angle.rows, angle.cols, CV_32FC2);//定义一个双通道的Mat类分别存储相位谱的实部与虚部for (int row = 0; row < Phase_Spectrum.rows; row++){for (int col = 0; col < Phase_Spectrum.cols; col++){Phase_Spectrum.at<Vec2f>(row, col)[0] = cos(angle.at<float>(row, col));//实部Phase_Spectrum.at<Vec2f>(row, col)[1] = sin(angle.at<float>(row, col));//虚部}}idft(Phase_Spectrum, Phase_Spectrum);Mat temp[] = { Mat_<float>(angle),Mat::zeros(angle.size(),CV_32F) };split(Phase_Spectrum, temp);magnitude(temp[0], temp[1], temp[0]);normalize(temp[0], temp[0], 0, 1, CV_MINMAX);imshow("相位谱重构图像", temp[0]);
}
void Amplitude_Spectrum_Reconstruction(Mat Re, Mat Im)
{Mat amplitude = Magnitude(Re, Im);Mat Amplitude_Spectrum = Mat::zeros(amplitude.rows, amplitude.cols, CV_32FC2);//定义一个双通道的Mat类分别存储幅度谱谱的实部与虚部for (int row = 0; row < Amplitude_Spectrum.rows; row++){for (int col = 0; col < Amplitude_Spectrum.cols; col++){Amplitude_Spectrum.at<Vec2f>(row, col)[0] = amplitude.at<float>(row, col)*pow(-1, row + col);//实部Amplitude_Spectrum.at<Vec2f>(row, col)[1] = 0;//虚部}}idft(Amplitude_Spectrum, Amplitude_Spectrum);Mat temp[] = { Mat_<float>(amplitude),Mat::zeros(amplitude.size(),CV_32F) };split(Amplitude_Spectrum, temp);magnitude(temp[0], temp[1], temp[0]);normalize(temp[0], temp[0], 0, 1, CV_MINMAX);imshow("幅度谱重构图像", temp[0]);
}
void Amplitude_Phase_Spectrum_Reconstruction(Mat Re, Mat Im)
{Mat angle = Phase(Re, Im);Mat amplitude = Magnitude(Re, Im);Mat Amplitude_Phase_Spectrum = Mat::zeros(angle.rows, angle.cols, CV_32FC2);//定义一个双通道的Mat类分别存储相位谱的实部与虚部for (int row = 0; row < Amplitude_Phase_Spectrum.rows; row++){for (int col = 0; col < Amplitude_Phase_Spectrum.cols; col++){Amplitude_Phase_Spectrum.at<Vec2f>(row, col)[0] = amplitude.at<float>(row, col)*cos(angle.at<float>(row, col));//实部Amplitude_Phase_Spectrum.at<Vec2f>(row, col)[1] = amplitude.at<float>(row, col)*sin(angle.at<float>(row, col));//虚部}}idft(Amplitude_Phase_Spectrum, Amplitude_Phase_Spectrum);Mat temp[] = { Mat_<float>(angle),Mat::zeros(angle.size(),CV_32F) };split(Amplitude_Phase_Spectrum, temp);magnitude(temp[0], temp[1], temp[0]);normalize(temp[0], temp[0], 0, 1, CV_MINMAX);imshow("利用幅度谱和相位谱重构图像", temp[0]);
}

http://www.ppmy.cn/news/377924.html

相关文章

寒假第一个springboot+vue音乐网站实战项目

文章目录 前言一.成果展示二. 后端流程 2.1数据库表设计2.2. 后端搭建 2.2.1 mybatis-plus逆向工程生成代码简化开发2.2.2 配置数据,跨域和静态资源放行2.3. 流水线式开发模式 三.前端vue搭建 3.1 前端基本环境搭建 3.1.1 脚手架搭建和容易出现的错误3.1.2 axios与后端交互搭…

GridLayoutManager这么用,你可能还真没尝试过,kotlin开发android

private Boolean isDrawTitleBg false; private Context mContext; // 总的SpanSize private int totalSpanSize; private int mCurrentSpanSize; //… 省略一些方法 Override public void onDraw(NonNull Canvas c, NonNull RecyclerView parent, NonNull RecyclerVie…

springboot+vue音乐网站实战项目

文章目录 前言一.成果展示二. 后端流程2.1数据库表设计2.2. 后端搭建2.2.1 mybatis-plus逆向工程生成代码简化开发2.2.2 配置数据,跨域和静态资源放行2.3. 流水线式开发模式 三.前端vue搭建3.1 前端基本环境搭建3.1.1 脚手架搭建和容易出现的错误3.1.2 axios与后端交互搭建 3.2…

WPF|如何在 WPF 中设计漂亮的社交媒体信息仪表板

1. 效果展示 先来直接欣赏效果&#xff1a; 2. 准备 创建一个WPF工程&#xff0c;比如站长使用 .NET 7 创建名为 Dashboard3 的WPF项目&#xff0c;添加一些图片资源&#xff0c;项目目录如下&#xff1a; 2.1 图片资源 可在网站 iconfont 下载 关闭、最小化 图标&#xff0…

必应暗藏戏精模式,拿捏名人说话语气口头禅!官方还自推三种个性供挑选

明敏 发自 凹非寺量子位 | 公众号 QbitAI 曾声称自己完美无瑕的必应&#xff0c;怎么突然180度大转弯&#xff1f; 自评&#xff1a;可真多管闲事啊……是个卑鄙的家伙。 还疯狂揭自己老底&#xff1a; 它还偷看对话、夹带广告&#xff0c;它不是我们的朋友&#xff01; 仔细一…

软件案例分析——两大音乐软件的PK

项目内容这个作业属于哪个课程软件工程这个作业的要求在哪里软件案例分析我在这个课程的目标是1. 体验体系化、规范化的软件工程实践流程 2. 锻炼码力。这个作业在哪个具体方面帮助我实现目标深入分析软件性能&#xff0c;了解软件测评流程和软件市场需求 产品选择 本次作业&…

图像的频域滤波(基于严格的傅里叶分析理论)

本文将基于严格的傅里叶分析理论基础给出严谨的图像频域滤波算法&#xff0c;并利用代码演示图像频域滤波的正确结果。 一、离散傅里叶变换 1.1 离散傅里叶变换的产生 离散信号分析和处理的主要手段是利用计算机去实现&#xff0c;然而序列f(n)的离散时间傅里叶变换是频率的连…

人脸识别的可解释性

点击上方“计算机视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 作者丨孙裕道 编辑丨极市平台 导读 人脸识别的可解释性是深度学习领域中的一个很大挑战&#xff0c;当前的方法通常缺乏网络比较和量化可解释结果的真相。本文作者定义了一种新的评估方案&#xff0c;称…