图像处理开发需求、图像处理接私活挣零花钱,请加微信/QQ 2487872782
图像处理开发资料、图像处理技术交流请加QQ群,群号 271891601

灰度图像的二维傅里叶变换(cv_gray_fft2[我用C语言写成]和DFT[用C++写成]),二维傅里叶变换结果的幅值计算(cv_abs),频谱平移(cv_gray_fft2shift)【频谱平移的作用详见我的博文在二维离散傅里叶变换中进行频谱平移(MATLAB::fft2shift)的作用_昊虹图像算法-CSDN博客_fft2shift】,将数值归一化到0到255区间(cv_range_0to255)是非常常用的四个功能!所以写成四个函数,方便将来调用。

傅里叶变换的意义这里就不多说了,大家在高等数学、信号与系统中应该都学过,不清楚的可以去查阅相关资料!这里我简单说两点!①图像的频率是表征图像中灰度变化剧烈程序的指标;②图像低频分量表示背景和缓慢变化区域,高频分量表示图像的边缘、细节及相关噪声。

源码如下:

源码下载链接:在OpenCV环境下写的灰度图像二维傅里叶换,幅值计算,频谱平移和将数值归一化到0到255区间的四个函数.rar_免费高速下载|百度网盘-分享无限制

源码中用到的图片下载链接:coins.png_免费高速下载|百度网盘-分享无限制

#include <opencv2/opencv.hpp>
#include <opencv2/legacy/compat.hpp>
#include <fstream>
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")  void cv_gray_fft2(IplImage *src, IplImage *dst)  //注意:此函数仅适用灰度图像,src因为是灰度图像,所以通道数要求为1,dst的属性为:IPL_DEPTH_64F,2(两通道)
{
IplImage *image_Re = 0, *image_Im = 0, *Fourier = 0;
image_Re = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1);  //实部
image_Im = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1);  //虚部
Fourier = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 2);//2 channels,分别存储image_Re、image_Im// Real part conversion from u8 to 64f (double)
cvConvertScale(src, image_Re);// Imaginary part (zeros)
cvZero(image_Im);// Join real and imaginary parts and stock them in Fourier image
cvMerge(image_Re, image_Im, 0, 0, Fourier);// Application of the forward Fourier transform
cvDFT(Fourier, dst, CV_DXT_FORWARD);
cvReleaseImage(&image_Re);
cvReleaseImage(&image_Im);
cvReleaseImage(&Fourier);
}void cv_abs(IplImage *src,IplImage *fft2_out, IplImage *dst)//src就是灰度图像原始数据,fft2_out要求是cv_gray_fft2的dst数据类型,即"64F, 2";dst为"64F, 1"
{
IplImage *image_Re = 0, *image_Im = 0;
image_Re = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1);  //实部
image_Im = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1);  //虚部
cvSplit(fft2_out,image_Re,image_Im,0,0);
cvPow(image_Re,image_Re,2);                 cvPow(image_Im,image_Im,2);
cvAdd(image_Re,image_Im,image_Re,NULL);
cvPow(image_Re,dst,0.5);cvReleaseImage(&image_Re);
cvReleaseImage(&image_Im);
}void cv_gray_fft2shift(IplImage *src)//参数是"64F, 2"
{
int nRow, nCol, i, j, cy, cx;
double tmp13, tmp24;//Rearrange the quadrants of Fourier image so that the origin is at the image center  nRow = src->height;  nCol = src->width;  cy = nRow/2; // image center  cx = nCol/2;  //CV_IMAGE_ELEM为OpenCV定义的宏,用来读取图像的像素值,这一部分就是进行中心变换  for( j = 0; j < cy; j++ ){  for( i = 0; i < cx; i++ ){  //中心化,将整体份成四块进行对角交换  tmp13 = CV_IMAGE_ELEM( src, double, j, i);  CV_IMAGE_ELEM( src, double, j, i) = CV_IMAGE_ELEM(  src, double, j+cy, i+cx);  CV_IMAGE_ELEM( src, double, j+cy, i+cx) = tmp13;  tmp24 = CV_IMAGE_ELEM( src, double, j, i+cx);  CV_IMAGE_ELEM( src, double, j, i+cx) =  CV_IMAGE_ELEM( src, double, j+cy, i);  CV_IMAGE_ELEM( src, double, j+cy, i) = tmp24;  }  }
}void cv_range_0to255(IplImage *src, IplImage *dst)//两个参数都是"64F, 2"
{
double m,M;
double scale;
double shift;  cvMinMaxLoc(src,&m,&M,NULL,NULL);
scale = 255/(M - m);
shift = -m * scale;
cvConvertScale(src,dst,scale,shift);
}int main()
{
int i=0;//循环变量
//从文件中加载原图
IplImage *pSrcImage = cvLoadImage("coins.png", CV_LOAD_IMAGE_UNCHANGED);  //创建输出的图像
IplImage *pOutImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_64F,1);//创建中间结果图像
IplImage *cv_gray_fft2_out = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_64F,2);//注意这里是二通道!
IplImage *cv_abs_out = cvCreateImage(cvGetSize(pSrcImage),  IPL_DEPTH_64F, 1);cv_gray_fft2(pSrcImage,cv_gray_fft2_out);double watch_cv_gray_fft2_out_Re[100];//利用调试时的局部变量窗口观察cvDFTOut实部的前100个值,看与MATLAB运行的结果否相同
double watch_cv_gray_fft2_out_Im[100];//利用调试时的局部变量窗口观察cvDFTOut虚部的前100个值,看与MATLAB运行的结果否相同
for(i=0;i<10;i++)//一般情况下观察10个值就够了
{
watch_cv_gray_fft2_out_Re[i]=cvGet2D(cv_gray_fft2_out,0,i).val[0];
}
for(i=0;i<10;i++)//一般情况下观察10个值就够了
{
watch_cv_gray_fft2_out_Im[i]=cvGet2D(cv_gray_fft2_out,0,i).val[1];
}cv_abs(pSrcImage,cv_gray_fft2_out,cv_abs_out);
double watch_cv_abs_out[100];//利用调试时的局部变量窗口观察cv_abs_out的前100个值,看与MATLAB运行的结果否相同
for(i=0;i<10;i++)//一般情况下观察10个值就够了
{
watch_cv_abs_out[i]=cvGet2D(cv_abs_out,0,i).val[0];
}cv_gray_fft2shift(cv_abs_out);
double watch_cv_gray_fft2shift_out[100];//利用调试时的局部变量窗口观察cv_gray_fft2shift_out的前100个值,看与MATLAB运行的结果否相同
for(i=0;i<10;i++)//一般情况下观察10个值就够了
{
watch_cv_gray_fft2shift_out[i]=cvGet2D(cv_abs_out,0,i).val[0];
}cv_range_0to255(cv_abs_out,pOutImage);
double watch_cv_range_0to255_out[100];//利用调试时的局部变量窗口观察cv_range_0to255_out的前100个值,看与MATLAB运行的结果否相同
for(i=0;i<10;i++)//一般情况下观察10个值就够了
{
watch_cv_range_0to255_out[i]=cvGet2D(pOutImage,0,i).val[0];
}
return 0;
}

上面四个函数与MATLAB运行的结果一致,MATLAB程序如下:

clear all;
clc;
I=imread('coins.png');
F=fft2(I);
MatlabFFt2Out=F;
MatlabAbsOut=abs(F);
MatlabFftshiftOut=fftshift(MatlabAbsOut);
T=MatlabFftshiftOut;
max_T=max(max(T));
min_T=min(min(T));
shift_T=-min_T*255/(max_T-min_T);
MatlabRange0to255=T.*255/(max_T-min_T)+shift_T;

运行结果截图如下:

cv_gray_fft2

cv_abs

cv_gray_fft2shift

cv_range_0to255

下面再给出OpenCV下的C++代码实现,代码中的DFT函数已经包含了上述函数的功能:

//OpenCV版本2.4.9
//交流QQ2487872782   # include <opencv2/core/core.hpp>
# include <opencv2/highgui/highgui.hpp>
# include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
cv::Mat DFT(cv::Mat srcImage)
{  cv::Mat srcGray;  cvtColor(srcImage,srcGray,CV_RGB2GRAY);  // 将输入图像延扩到最佳的尺寸(快速傅里叶变换是基于图像尺寸是2、3或5的倍数完成的,因此对于输入源图像,首先应将其转换成DFTsize,OpenCV中提供了函数getOptimalDFTSize来实现尺寸转换)  int nRows = getOptimalDFTSize(srcGray.rows);  int nCols = getOptimalDFTSize(srcGray.cols);  cv::Mat resultImage;  // 把灰度图像放在左上角,在右边和下边扩展图像,  // 添加的像素初始化为0  copyMakeBorder(srcGray, resultImage, 0,  nRows - srcGray.rows,   0, nCols - srcGray.cols,   BORDER_CONSTANT, Scalar::all(0));  // 为傅立叶变换的结果(实部和虚部)分配存储空间  cv::Mat planes[] = { cv::Mat_<float>(resultImage),   cv::Mat::zeros(resultImage.size(), CV_32F)};//这里实际上是建立MAT数组,数组有两个成员:  //第一个就是sizeConvMat这个对象(只是数据类型转换成了float类型)  //第二个是全0的类型为32F的对象  Mat completeI;  // 为延扩后的图像增添一个初始化为0的通道  merge(planes,2,completeI); //把groupMats的第0和第1个对象合并到mergeMat,通过这个操作mergeMat是双通道的数据阵列了  // 进行离散傅立叶变换  dft(completeI,completeI);  // 将复数转换为幅度  split(completeI,planes);  magnitude(planes[0],planes[1],planes[0]);//0中存的是实部值,1中存的是虚部值  cv::Mat dftResultImage = planes[0];   // 对数尺度(logarithmic scale)缩放  dftResultImage += 1;//阵列加1作对数变换,以扩大频域动态显示范围  log(dftResultImage,dftResultImage);//作对数变换  // 剪切和重分布幅度图象限  dftResultImage= dftResultImage(Rect(0,  0,srcGray.cols,srcGray.rows));  // 归一化图像  normalize(dftResultImage,dftResultImage,  0,1,CV_MINMAX);  int cx = dftResultImage.cols/2;  int cy = dftResultImage.rows/2;   Mat tmp;  // Top-Left - 为每一个象限创建ROI  Mat q0(dftResultImage,Rect(0,0,cx,cy));  // Top-Right  Mat q1(dftResultImage,Rect(cx,0,cx,cy));  // Bottom-Left  Mat q2(dftResultImage,Rect(0,cy,cx,cy));  // Bottom-Right  Mat q3(dftResultImage,Rect(cx,cy,cx,cy));   // 交换象限 (Top-Left with Bottom-Right)      q0.copyTo(tmp);  q3.copyTo(q0);  tmp.copyTo(q3);  // 交换象限 (Top-Right with Bottom-Left)  q1.copyTo(tmp);  q2.copyTo(q1);  tmp.copyTo(q2);  return dftResultImage;
}
int main()
{  cv::Mat srcImage = imread("coins.png");  if(srcImage.empty())  return-1;  imshow("srcImage", srcImage);  cv::Mat resultImage = DFT(srcImage);  imshow("resultImage", resultImage);  cv::waitKey(0);  return 0;
}  

运行结果如下图所示:

图像处理开发需求、图像处理接私活挣零花钱,请加微信/QQ 2487872782
图像处理开发资料、图像处理技术交流请加QQ群,群号 271891601

在OpenCV环境下写的灰度图像二维傅里叶换,幅值计算,频谱平移和将数值归一化到0到255区间的四个函数相关推荐

  1. 在MATLAB和OpenCV环境下写的灰度图像分段线性变换源码

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 分段线性变换的理论基础这里我就不多打字了,如有需 ...

  2. opencv 计算二维矢量的幅值—magnitude()函数

    计算二维矢量的幅值:magnitude()函数 该函数用来计算二维矢量的幅值 void magnitude(InputArray x,InputArray y,OutputArray magnitud ...

  3. 在OpenCV环境下写的两个图像平移C和C++源代码

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 图像平移的概念就不用多说了,直接上经实测无误的代 ...

  4. Node.js:浏览器环境下使用qrcode生成二维码

    github: https://github.com/soldair/node-qrcode npmjs: https://www.npmjs.com/package/qrcode cdn: http ...

  5. 灰度图像归一化到0~255(对比度拉伸)的OpenCV代码实现

    如题,代码的功能很简单,这里就不多做解释了,直接上源代码吧!其实这个代码我之前就已经写过C的版本了,详情可参见我写的博文在OpenCV环境下写的灰度图像二维傅里叶换,幅值计算,频谱平移和将数值归一化到 ...

  6. 利用循环,使得10 * 10的二维数组具有以下值,并按以下结构输出在屏幕上

    <程序设计基础-c语言>杨莉 刘鸿翔 ISBN-978-7-03-032903-5 p113 习题4 5.利用循环,使得10 * 10的二维数组具有以下值,并按以下结构输出在屏幕上 0 1 ...

  7. 在OpenCV环境下对图像做Gamma校正

    什么是Gamma校正? Gamma校正是对输入图像灰度值进行的非线性操作,使输出图像灰度值与输入图像灰度值呈指数关系. 上面中的指数γ即为Gamma. 经过Gamma校正后的输入和输出图像灰度值关系如 ...

  8. 手撸的C#.net2.0环境下写的快手小店开放平台的SDK提供下载

    由于近期要做快手小店开放平台的对接,获取快手小店的订单,商品等进行管理.所以就需要用到接口.但是快手小店开放平台open.kwaixiaodian.com只有java的sdk,我们开发的后端都是用的C ...

  9. Jetson Nano 从入门到实战(转载)(案例:Opencv配置、人脸检测、二维码检测)

    目录 1. Jetson Nano简介 2. Jetson Nano环境配置 2.1 开箱配件介绍 2.2 烧录系统 2.3 开机和基本设置 2.4 开发环境配置 2.4.1 更新源和软件 2.4.2 ...

最新文章

  1. 人脸识别数据集bin解压
  2. vue创建二:引入本地图片
  3. LA3266田忌赛马
  4. 09.ws复杂数据类型数据传输
  5. python输出箭头代码_python matplotlib 注释文本箭头简单代码示例
  6. CentOS7安装 MySQL主从集群
  7. JavaScript学习笔记(一)--JS基础【入门必看】
  8. Python程序-离散和线性图形
  9. 一个简单的flask程序
  10. Oracle的三种高可用集群方案
  11. 解决办法:defined but not used [-Werror=unused-variable]
  12. 颜色空间 ---HSI
  13. 什么是透视变形的opencv和python
  14. ruby中的符号_Ruby中的凡人和不朽符号
  15. 编程练习:编写一个函数,用于计算某长方形面积的函数
  16. HTML5七夕情人节表白网页(粉色的情人节爱心飞出ui特效) HTML+CSS+JavaScript 求婚示爱代码 520情人节告白代码 程序员表白源码 3D旋转相册 js烟花代码 css爱心
  17. Activiti判断流程是否结束
  18. Bjarne Stroustrup 语录1
  19. 计算机毕业设计JAVA的影视资讯管理系统mybatis+源码+调试部署+系统+数据库+lw
  20. C++ Primer(第5版) 课后答案 第四章

热门文章

  1. python 3读取文件-python3的txt文件读写
  2. python3.6手册中文版-Python3.6.5标准库 参考文档 完整pdf中文版
  3. python中数据分析的流程为-python数据分析011_数据分析流程
  4. python3爬虫实例代码-Python3爬虫带上cookie的实例代码
  5. python从入门到精通怎么样-《Python编程从入门到精通》
  6. python 为什么每次代码运行时间不同-为什么你写的Python运行的那么慢呢?
  7. python好找工作么-python和django掌握到什么水平才好找工作?
  8. 零基础自学python的建议-【老男孩Python课堂安排】零基础Python学习方法
  9. Intel深度摄像头RealSense D345(实感双目摄像头)和目标检测结合使用
  10. PIL实现两张图片合成一张,和图片加文字