OpenCV3.0中的离散傅里叶变换

来源:互联网 发布:seo教程 百度云 编辑:程序博客网 时间:2024/06/06 05:44

图像中的离散傅里叶变换的相关理论较为简单,频域里面,对于一幅图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。
这里我们直接讲解OpenCV3.0中的离散傅里叶变换
1.dft()函数详解
dft()函数的作用是对一维或者二维浮点数组进行正向或反向离散傅里叶变换。
C++:void dft(InputArray src,OutputArray dst,int flags = 0,int nonzerRows = 0)
参数一:InputArray类型的src,输入矩阵,可以为实数或者虚数
参数二:OutputArray类型的dst,函数调用后的运算结果存在这里,其尺寸和类型取决于标识符,也就是第三个参数flags
参数三:int 类型的flags,转换的标识符,有默认值为0,取值为下表:
这里写图片描述
参数四:int 类型的nonzeroRows,有默认值0,当此参数设置为非0,函数会假设只有输入的第一个非零行包含非零元素(没有设置DFT_INVERSE)或只有输出矩阵的第一个非零行包含非零元素(设置了DFT_INVERSE标识符)。
2.返回DFT最优尺寸大小:getOptimalDFTSize()函数
getOptimalDFTSize()函数返回给定尺寸的傅里叶最优尺寸大小。为了提高离散傅里叶变换的运行速度,需要扩充图像,而具体扩充多少,就由函数来计算得到
C++:int getOptimalDFTSize(int vecsize)
参数vecsize,向量尺寸,即图片的rows,cols
3.扩充边界:copyMakeBorder()函数
copyMakeBorder()函数的作用是扩充图像边界
C++:void copyMakeBorder(InputArray src,OutputArray dst,int top,int bottom,int left,int right,int borderType,const Scalar& value = Scalar())
参数一:同上
参数二:函数调用后的结果存放在这里,需要和源图片有一样的尺寸和类型,且size应该为Size(src.cols+left+right,src.rows+top+bottom)
接下来的四个参数top,bottom,left,right,分别表示在源图像的四个方向上扩充多少像素,例如top = 2,bottom = 2,left = 2,right = 2就意味着在源图像的上下左右各扩充两个像素宽度的边界
参数七:borderType类型的,边界类型,常见的取值为BORDER_CONSTANT
参数八:有默认的Scalar(),可以理解为有默认值0,当borderType取值为BORDER_CONSTANT时,这个参数表示边界值
4.计算二维矢量的幅值:magnitude()函数
C++:void magnitude(InputArray x,InputArray y,OutputArray magnitude)
参数一:表示矢量浮点型X坐标值,也就是实部
参数二:表示矢量浮点型Y坐标值,也就是虚部
参数三:输出的幅值,塔河第一个参数X有着相同的尺寸和类型
5.计算自然对数:log()函数
C++:void log(InputArray src,OutputArray dst)
参数一:输入图像
参数二:得到的对数值
6.矩阵归一化:normalize()函数
C++:void normalize(InputArray src,OutArray dst,double alpha = 1,double beta = 0,int norm_type = NORM_L2,int dtype = -1,InputArray mask = noArray())
参数一:输入图像,填Mat类的对象即可
参数二:输出图像,和输入图像有一样的尺寸和类型
参数三:归一化后的最大值,有默认值1
参数四:归一化后的最大值,有默认值0
参数五:归一化类型,有NORMAL_INF,NORMAL_L1,NORMAL_L2,和NORMAL_MINMAX等参数可选,默认值是NORM_L2,、
参数六:有默认值-1,当此参数取值为复数时,输出矩阵和src有相同的类型,否则和src有同样的通道数,且此时图像深度为CV_MAT_DEPTH(dtype)
参数七:可选的操作掩膜,有默认值noArray()
下面通过代码详细讲解(使用的是OpenCV3.0+VS2010):

关于包含.hpp,其实质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的调用者只需要include该。hpp文件即可,无需再 将cpp加入到project中进行编译
另外关于常用的几个头文件:
1.core.hpp
【core】–核心功能模块,包含以下内容:
OpenCV基本数据结构
动态数据结构
绘图函数
数组操作相关函数
辅助功能与系统函数和宏
与OpenGL的互操作
2.improc.hpp
【improc】–Image和Process这两个单词的缩写组合,图像处理模块,包含:
线性和非线性的图像滤波
图像的几何变换
其他(Miscellaneous)图像转换
直方图相关
结构分析和形状描述
运动分析和对象跟踪
特征检测
目标检测等内容
3.highgui.hpp
【highgui】–高层GUI图形用户界面,包含媒体的输入输出、视频捕捉、图像和视频的编码解码、图像交互界面的借口等内容

// DFT.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "stdafx.h"#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>using namespace std;using namespace cv;int _tmain(int argc, _TCHAR* argv[]){    //以灰度图像模式读入原始图像    Mat srcImage = imread("1.jpg",0);    if(!srcImage.data){printf("图像读入失败!\n");return false;}    imshow("原始图像",srcImage);    //将图像扩展到最佳尺寸,边界用0补充    int m = getOptimalDFTSize(srcImage.rows);    int n = getOptimalDFTSize(srcImage.cols);    //将添加的像素初始化为0    Mat padded;    copyMakeBorder(srcImage,padded,0,m-srcImage.rows,0,n-srcImage.cols,BORDER_CONSTANT,Scalar::all(0));    //为傅里叶变换的结果(实部和虚部)分配存储空间    //将planes数组组合合并成一个多通道的数组complexI    Mat planes[] = {Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F)};    Mat complexI;    merge(planes,2,complexI);    //进行傅里叶变换    dft(complexI,complexI);    //将复数转换为幅值,即=> log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))    split(complexI, planes); // 将多通道数组complexI分离成几个单通道数组,planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))    magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude      Mat magnitudeImage = planes[0];    //进行对数尺度缩放    magnitudeImage += Scalar::all(1);    log(magnitudeImage,magnitudeImage);//求自然对数    //剪切和充分不幅度图象限    //若有奇数行或者奇数列,进行频谱裁剪    magnitudeImage = magnitudeImage(Rect(0,0,magnitudeImage.cols &-2,magnitudeImage.rows & -2));    //重新排列傅里叶图像中的象限,使得原点位于图像的中心    int cx = magnitudeImage.cols / 2;    int cy = magnitudeImage.rows / 2;    Mat q0(magnitudeImage,Rect(0,0,cx,cy));//ROI区域的左上    Mat q1(magnitudeImage,Rect(cx,0,cx,cy));//ROI区域的右上    Mat q2(magnitudeImage,Rect(0,cy,cx,cy));//ROI区域的左下    Mat q3(magnitudeImage,Rect(cx,cy,cx,cy));//ROI区域的右下    //交换象限(左上与右下)    Mat tmp;    q0.copyTo(tmp);    q3.copyTo(q0);    tmp.copyTo(q3);    //交换象限(右上与左下)    q1.copyTo(tmp);    q2.copyTo(q1);    tmp.copyTo(q2);    //归一化    normalize(magnitudeImage,magnitudeImage,0,1,CV_MINMAX);    //显示    imshow("频谱幅值",magnitudeImage);    waitKey();    return 0;}

下面为源图像和频谱图像
这里写图片描述
这里写图片描述

1 0