opencv自带例子学习-图像的傅里叶变换

栏目: 编程工具 · 发布时间: 6年前

内容简介:关于傅里叶变换,作为信息工程学院的同学一定不会陌生。从最开始的高等数学到复变函数再到数字信号处理再到数字图像处理,傅里叶是一直伴随着的。没办法,入了这个坑,想躲傅里叶是不可能了。关于傅里叶变换,看看维基百科的解释

关于傅里叶变换,作为信息工程学院的同学一定不会陌生。从最开始的高等数学到复变函数再到数字信号处理再到数字图像处理,傅里叶是一直伴随着的。没办法,入了这个坑,想躲傅里叶是不可能了。

关于傅里叶变换,看看维基百科的解释

opencv自带例子学习-图像的傅里叶变换

有梯子的同学可以点击链接 傅里叶变换 查看详情。

没有梯子,可以阅读知乎上大佬们的解释,很多答案都很好。 知乎-傅里叶变换

简单地说,首先傅里叶变换是一种变换公式,作用是把信号在时域(或者空域)和频域间的转换。不同应用场景具体分类又不一样,比如有时域上的电信号转到频域,这是连续的。有图像的空域变换到频域,这是离散的,即下面要学习的程序例子。

关于图像处理里面的离散傅里叶变换,同样可以看看知乎上面的回答。 图像傅里叶变换的频率怎么理解

下面直接上代码

//discrete fourier tranform, 离散傅里叶变换

//头文件
#include "opencv2/core.hpp"     //Core functionality,核心函数相关
#include "opencv2/imgproc.hpp"  //Image processing, 图像处理相关
#include "opencv2/imgcodecs.hpp"//Image file reading and writing, 图像的加载和写出相关
#include "opencv2/highgui.hpp"  //High-level GUI,图形界面GUI相关

#include <iostream>

/**
 * 程序流程
 * 1、加载图像,格式为灰度图
 * 2、获取图片dft变换的最佳大小
 * 3、边框加0的方式填充图片,即非0部分为dft变换的最佳大小 
 * 4、创建数组储存图像实部虚部,且合并到complexI
 * 5、傅里叶变换 dft(complexI, complexI)
 * 6、重新分离实部虚部,并且计算幅度
 * 7、将幅度映射到对数域
 * 8、以图像中心为原点划分象限,每个象限创建一个ROI
 * 9、对角象限互换
 * 10、显示结果
 */

//命名空间
using namespace cv;
using namespace std;

//帮助函数,输出程序的信息
static void help(void)
{
    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   //离散傅里叶变换后显示功率谱
        <<  "Usage:"                                                                      << endl
        <<  "./discrete_fourier_transform [image_name -- default ../data/lena.jpg]"       << endl;  //默认加载图片路径
}

int main(int argc, char ** argv)
{
    help();

    //获取图像路径(文件名),命令行输入否则默认
    const char* filename = argc >=2 ? argv[1] : "../data/lena.jpg";

    //加载图像,方式为加载灰度图
    Mat I = imread(filename, IMREAD_GRAYSCALE);
    //检查是否成功加载
    if( I.empty()){
        cout << "Error opening image" << endl;
        return -1;
    }

//! [expand]
    Mat padded;                            
    //expand input image to optimal size, 将输入图像扩展到最佳大小
    int m = getOptimalDFTSize( I.rows );
    int n = getOptimalDFTSize( I.cols ); 

    // on the border add zero values,在边框上添加零值,使用copyMakeBorder函数
    copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
//! [expand]

//! [complex_and_real] 实部和虚部
    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; //Mat 数组储存图像的实部和虚部
    Mat complexI; 
    merge(planes, 2, complexI);         // Add to the expanded another plane with zeros,用零添加到扩展的另一平面

//! [complex_and_real]

//! [dft]
    //离散傅里叶变换
    dft(complexI, complexI);            // this way the result may fit in the source matrix,这种方式的结果可能适合在源矩阵

//! [dft]

    // compute the magnitude and switch to logarithmic scale,计算幅度并映射到对数刻度
    //公式 => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) 
//! [magnitude] 幅度
    split(complexI, planes);                   // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)),分离实部和虚部
    magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude,计算幅度且存放到planes[0]
    Mat magI = planes[0]; //幅度 
//! [magnitude]

//! [log]
    magI += Scalar::all(1);                    // switch to logarithmic scale,映射到对数刻度
    log(magI, magI);
//! [log]

//! [crop_rearrange]裁剪重新排列
    // 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;

    //每个象限新建一个ROI
    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);
//! [crop_rearrange]

//! [normalize]
    //归一化,像素值都映射到[0,1]之间
    normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a
                                            // viewable image form (float between values 0 and 1).
//! [normalize]

    //显示结果
    imshow("Input Image"       , I   );    // Show the result
    imshow("spectrum magnitude", magI);
    waitKey();

    return 0;
}

/**
 * 要点总结:
 * 加载图片格式为灰度图
 * getOptimalDFTSize()函数获取最佳大小
 * copyMakeBorder()加框函数
 * 实部虚部
 * merge()合并函数
 * dft()函数
 * 幅度公式sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)
 * split()分离函数
 * magnitude()计算幅度
 * log()对数函数
 * normalize()归一化函数
 * /

下面放上所用函数的声明信息

int cv::getOptimalDFTSize	(	int 	vecsize	)
void cv::copyMakeBorder ( InputArray  src, 
  OutputArray  dst, 
  int  top, 
  int  bottom, 
  int  left, 
  int  right, 
  int  borderType, 
  const Scalar &  value = Scalar()  
 )
void cv::merge ( const Mat *  mv, 
  size_t  count, 
  OutputArray  dst  
 )
void cv::magnitude ( InputArray  x, 
  InputArray  y, 
  OutputArray  magnitude  
 )
softfloat cv::log ( const softfloat &  a )
void cv::normalize ( InputArray  src, 
  InputOutputArray  dst, 
  double  alpha = 1, 
  double  beta = 0, 
  int  norm_type = NORM_L2, 
  int  dtype = -1, 
  InputArray  mask = noArray()  
 )

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

调试九法

调试九法

David J.Agans / 赵俐 / 人民邮电出版社 / 2010-12-7 / 35.00元

硬件缺陷和软件错误是“技术侦探”的劲敌,它们负隅顽抗,见缝插针。本书提出的九条简单实用的规则,适用于任何软件应用程序和硬件系统,可以帮助软硬件调试工程师检测任何bug,不管它们有多么狡猾和隐秘。 作者使用真实示例展示了如何应用简单有效的通用策略来排查各种各样的问题,例如芯片过热、由蛋酒引起的电路短路、触摸屏失真,等等。本书给出了真正能够隔离关键因素、运行测试序列和查找失败原因的技术。 ......一起来看看 《调试九法》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具