基于OpenCV完成离散傅里叶变换

目标

学会使用函数:  cv::copyMakeBorder() , cv::merge() , cv::dft() , cv::getOptimalDFTSize() , cv::log() 和 cv::normalize() .

源代码如下:

使用的 cv::dft() 的代码示例:

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"#include <iostream>using namespace cv;
using namespace std;static void help(char* progName)
{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<< progName << " [image_name -- default ../data/lena.jpg] "               << endl << endl;
}int main(int argc, char ** argv)
{help(argv[0]);const char* filename = argc >=2 ? argv[1] : "../data/lena.jpg";Mat I = imread(filename, IMREAD_GRAYSCALE);if( I.empty())return -1;Mat padded;                            //expand input image to optimal sizeint m = getOptimalDFTSize( I.rows );int n = getOptimalDFTSize( I.cols ); // on the border add zero valuescopyMakeBorder(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);         // Add to the expanded another plane with zerosdft(complexI, complexI);            // this way the result may fit in the source matrix// compute the magnitude and switch to logarithmic scale// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))split(complexI, planes);                   // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitudeMat magI = planes[0];magI += Scalar::all(1);                    // switch to logarithmic scalelog(magI, magI);// crop the spectrum, if it has an odd number of rows or columnsmagI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));// rearrange the quadrants of Fourier image  so that the origin is at the image centerint cx = magI.cols/2;int cy = magI.rows/2;Mat q0(magI, Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrantMat q1(magI, Rect(cx, 0, cx, cy));  // Top-RightMat q2(magI, Rect(0, cy, cx, cy));  // Bottom-LeftMat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-RightMat 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);normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a// viewable image form (float between values 0 and 1).imshow("Input Image"       , I   );    // Show the resultimshow("spectrum magnitude", magI);waitKey();return 0;
}

解释如下

离散傅里叶变换将会把一副图像分解为其正弦和余弦分量,也就是把一副图像从空间域转换到频率域。主要思想为任何函数都可以近似的精确地用无限的正弦和余弦函数的和表示。在数学上的一个二维图像的傅立叶变换为:

F(k,l)=∑i=0N−1∑j=0N−1f(i,j)e−i2π(kiN+ljN)
eix=cosx+isinx

这里, f 是图像在空间域的值, F为频率域的值. 变换的结果为复数.

Displaying this is possible either via a real image and a complex image or via a magnitude and a phase image. However, throughout the image processing algorithms only the magnitude image is interesting as this contains all the information we need about the images geometric structure. Nevertheless, if you intend to make some modifications of the image in these forms and then you need to retransform it you'll need to preserve both of these.

In this sample I'll show how to calculate and show the magnitude image of a Fourier Transform. In case of digital images are discrete. This means they may take up a value from a given domain value. For example in a basic gray scale image values usually are between zero and 255. Therefore the Fourier Transform too needs to be of a discrete type resulting in a Discrete Fourier Transform (DFT). You'll want to use this whenever you need to determine the structure of an image from a geometrical point of view. Here are the steps to follow (in case of a gray scale input imageI):


1 Expand the image to an optimal size. The performance of a DFT is dependent of the image size. It tends to be the fastest for image sizes that are multiple of the numbers two, three and five. Therefore, to achieve maximal performance it is generally a good idea to pad border values to the image to get a size with such traits. Thecv::getOptimalDFTSize() returns this optimal size and we can use the cv::copyMakeBorder() function to expand the borders of an image:

Mat padded;                            //expand input image to optimal size
int m = getOptimalDFTSize( I.rows );
int n = getOptimalDFTSize( I.cols ); // on the border add zero pixels
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));

2 Make place for both the complex and the real values. 傅里叶变换的结果为复数。这意味着对于图像的每一个像素值变换的结果位两个值(一个对应复数的实部一个对应虚部). 另外,频率阈值的范围相对空间阈是非常大的. 所以,数据的存储至少要用实数类型. 所以将会把输入图像转换为用实数表示 并扩展一个通道来保存复数:

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

3 进行离散傅里叶.计算中用输入存储输出结果

dft(complexI, complexI);            // this way the result may fit in the source matrix

4 转换虚部(complex)和实部(real)的值为级数(magnitude). 一个复数有一个real (Re)(实部)和一个 complex (imaginary -Im) 虚部. DFT变换的结果为一组复数.DFT变换的级数为: 
M=Re(DFT(I))2+Im(DFT(I))2‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾√2
 OpenCV 代码如下:

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];

5 Switch to a logarithmic scale. It turns out that the dynamic range of the Fourier coefficients is too large to be displayed on the screen. We have some small and some high changing values that we can't observe like this. Therefore the high values will all turn out as white points, while the small ones as black. To use the gray scale values to for visualization we can transform our linear scale to a logarithmic one:M1=log(1+M)

用 OpenCV 形式的代码实现为:

magI += Scalar::all(1);                    // switch to logarithmic scale
log(magI, magI);

6 Crop and rearrange. Remember, that at the first step, we expanded the image? Well, it's time to throw away the newly introduced values. For visualization purposes we may also rearrange the quadrants of the result, so that the origin (zero, zero) corresponds with the image center.

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));   // 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);

7 归一化. 目的是为了可视化. 现在已经有了一个级数图像,但是数据的范围超出了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).

结果(使用DFT检测文本的方向)

一个应用是在图像中存在的几何方向。例如,判断文字的方向是否是横向的?Looking at some text you'll notice that the text lines sort of form also horizontal lines and the letters form sort of vertical lines. These two main components of a text snippet may be also seen in case of the Fourier transform。 Let us usethis horizontal andthis rotated image about a text.

In case of the horizontal text(文字行在水平方向上排成一行):

In case of a rotated text(文字行被旋转了的情况):

You can see that the most influential components of the frequency domain (brightest dots on the magnitude image) follow the geometric rotation of objects on the image. From this we may calculate the offset and perform an image rotation to correct eventual miss alignments.lisanful

基于OpenCV完成离散傅里叶变换相关推荐

  1. 使用OpenCV实现离散傅里叶变换(DFT)

    使用OpenCV实现离散傅里叶变换(DFT) 傅里叶变换,妈呀这个东东好高级啊!真的高级吗?理解起来还真是有点困难,需要一些高等数学的基础.有了OpenCV,你不理解也没问题,会用就OK!就好比你会用 ...

  2. 基于CUDA的离散傅里叶变换(Discrete Fourier Transform,DFT)

    最近在做地震勘探的全波形反演,用分频反演的方法,需要对地震波场按照特定的频段进行傅里叶变换,这要用到DFT.在CPU上,DFT的计算非常耗时,当处理三维数据时耗时更加严重,所以,本人用CUDA+SU( ...

  3. 独家|OpenCV 1.7 离散傅里叶变换

    翻译:陈之炎 校对:李海明本文约2400字,建议阅读5分钟本文为大家介绍了OpenCV离散傅里叶变换. 目标 本小节将寻求以下问题的答案: 什么是傅立叶变换,为什么要使用傅立叶变换? 如何在OpenC ...

  4. Opencv 实现图像的离散傅里叶变换(DFT)、卷积运算(相关滤波)

    原文:http://blog.csdn.net/ikerpeng/article/details/41845545?utm_source=tuicool&utm_medium=referral ...

  5. 【OpenCV 例程200篇】72. 一维离散傅里叶变换

    [OpenCV 例程200篇]72. 一维离散傅里叶变换 欢迎关注 『OpenCV 例程200篇』 系列,持续更新中 欢迎关注 『Python小白的OpenCV学习课』 系列,持续更新中 1.3 一维 ...

  6. 基于离散傅里叶变换(DFT)的数字水印算法研究

    目 录 1 绪论 1 1.1 本文研究的背景及意义 1 1.2 数字水印的国内外研究现状 1 1.3 本文的研究主要内容 2 2 数字水印技术概述 3 2.1 数字水印的基本特点 3 2.2 数字水印 ...

  7. OPenCV:傅里叶变换、时域和频域、频谱和相位谱、傅里叶级数、离散傅里叶变换(DFT)、频域滤波、高通和低通滤波器、带通和带阻滤波器

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 快速了解傅立叶变换(播放PPT即能动态地显示gif图)    ...

  8. opencv学习:二维浮点数离散傅里叶变换及其扩展边界优化

    opencv中提供了傅里叶变换函数cvDFT,执行二维浮点数离散傅里叶变换的代码如下: void fft2(const IplImage* src, IplImage* dst) {//实部.虚部 I ...

  9. 【OpenCV】OpenCV实战从入门到精通之 -- 离散傅里叶变换相关函数详解

    目录 1.dft()函数 2.返回DFT最优尺寸大小:getOptimalDFTSize()函数 3.扩充图像边界:copyMakeBorder()函数 4.计算二维矢量的幅值:magnitude() ...

最新文章

  1. 条件随机场概率无向图模型的因子分解
  2. RuntimeError: cudnn64_7.dll not found.
  3. 转:WF中的跟踪服务(1):Sql跟踪数据库表,视图,存储过程等相关说明
  4. github 运行python_Github Actions教程:运行python代码并Push到远端仓库
  5. IBM推出云深度学习图形芯片Tesla P100 GPU加速器
  6. 找不到_我的圣诞礼物找不到了!
  7. asp.net core3.0 mvc 用 autofac
  8. css 动画类库Animate.css
  9. 面试第二弹-重点描述
  10. nodejs后台系列--第四篇--koa
  11. 字蛛(font-spider)教学——ttf/otf字体文件压缩
  12. python还可以这么玩?用Python把视频转换为字符动画(含音频、高清、彩图)【附源码】
  13. antd使用g2plot统计图表(7)
  14. 地图瓦片坐标系定义及计算原理
  15. java代码-zip解压不可预料的压缩文件末端一级压缩包中的文件为0kb以及目录创建流会报错
  16. [附源码]java+ssm计算机毕业设计java交通违章举报平台lxsqm【源码、数据库、LW、部署】
  17. springboot中参数校验(validation)使用
  18. Danar程序员之家
  19. 【安卓实验】实验五、广播实验
  20. 802.11网络协议细节(五)

热门文章

  1. OpenCV的示例程序在哪里?
  2. leetcode算法题--Minimum Number of Arrows to Burst Balloons
  3. leetcode算法题--最接近的三数之和
  4. OVS原理(四十二)
  5. leetcode算法题--逆波兰表达式求值
  6. CTF web总结--利用mysql日志getshell
  7. 计算机组成与结 读写数据实验,计算机组成与结构实验报告现实版.doc
  8. RESTful 规范
  9. Java反射之如何判断类或变量、方法的修饰符(Modifier解析)
  10. 源码阅读之Java栈的实现