zoukankan      html  css  js  c++  java
  • 图像傅里叶变换

    简单说一下图像傅里叶变换的思路。

    文章思路,先理解傅里叶级数,由连续傅里叶级数说明傅里叶变换。之后引入取样函数,对连续函数取样,就可以得到离散函数的傅里叶变换。由此推倒出单变量傅里叶变换。由一维傅里叶变换,就可以推导出二维傅里叶变换,及图像的傅里叶变换。下一篇博客再讲图像傅里叶变换性质。

    https://www.zhihu.com/question/19714540

    这篇文章很详细讲述了傅里叶变换公式

    https://zhuanlan.zhihu.com/p/19759362

    这篇文章没有公式,很清晰讲述了傅里叶变换的意义。就不再多说,这里只是简单列一下我理解的思路。

    对于连续变量t,傅里叶级数为

    其实Cn就是频域基的系数,频域就是以为基的坐标系。

    由傅里叶级数可知,连续变量的傅里叶变换如下:

    ,其实就是求的频率域的系数,反变换

    若对冲击函数对做傅里叶变换,其频率域的冲激函数也是冲激函数对。

    可由取样函数将连续函数傅里叶变换推广到离散傅里叶变换。使用冲激函数对连续傅里叶函数取样,就得到了离散傅里叶函数。对离散函数做傅里叶变换。

      

    对两个函数的积做傅里叶变换,相当于对两个函数的傅里叶变换做卷积。

     

    其实相当于将连续函数的傅里叶变换做无限平移,平移距离为1/T。此处插入取样定理, 1/T必须大于umax-umin,即频域率的一个周期。

    如图:

    由对连续函数取样,做傅里叶变换,可推广到单变量的傅里叶变换。

     

    其中,取样频率,若要在T内取M个样本,则取样频率为u=m/M,m=0,1,2,3,4

    图像就是将一维傅里叶变换扩展到二维。

     图像傅里叶变换特点

    平移和旋转

    若对图像进行傅里叶变换,在频域进行平移,需要在空间域乘一个系数,公式如下。单纯平移不影响傅里叶谱。

    旋转:

    周期性

    二维傅里叶变换及其反变换在u方向和v方向都是无限周期的,即

    由前面离散傅里叶变化可以得到该性质

    由周期性和平移特性可知,我们若想让图像在频域呈现一个完整的周期,需要对图像做一个平移。通常做法是在空间域乘-1

    对称性

    实函数的傅里叶变换频谱是共轭对称的,即F(u,v)=F(-u,-v)

    若要避免混淆,一般需要对图像做双倍的填充,之后再对图像进行裁剪。整个的图像傅里叶变换流程如下:

     最后,对某些图像做一些傅里叶变换,并附上代码:

    Mat get_freq(Mat src)
    {
    
    	Mat srcGray;
    	cvtColor(src, srcGray, CV_RGB2GRAY); //灰度图像做傅里叶变换
    
    	int m = getOptimalDFTSize(srcGray.rows); //2,3,5的倍数有更高效率的傅里叶变换
    	int n = getOptimalDFTSize(srcGray.cols);
    
    	Mat padded;
    	//把灰度图像放在左上角,在右边和下边扩展图像,扩展部分填充为0;
    	copyMakeBorder(srcGray, padded, 0, m - srcGray.rows, 0, n - srcGray.cols, BORDER_CONSTANT, Scalar::all(0));
    	//cout << padded.size() << endl;
    	//这里是获取了两个Mat,一个用于存放dft变换的实部,一个用于存放虚部,初始的时候,实部就是图像本身,虚部全为零
    	Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
    	Mat complexImg;
    	//将几个单通道的mat融合成一个多通道的mat,这里融合的complexImg既有实部又有虚部
    	merge(planes, 2, complexImg);
    
    	//对上边合成的mat进行傅里叶变换,支持原地操作,傅里叶变换结果为复数.通道1存的是实部,通道二存的是虚部
    	dft(complexImg, complexImg);
    	//把变换后的结果分割到两个mat,一个实部,一个虚部,方便后续操作
    	split(complexImg, planes);
    	//这一部分是为了计算dft变换后的幅值,傅立叶变换的幅度值范围大到不适合在屏幕上显示。高值在屏幕上显示为白点,而低值为黑点,高低值的变化无法有效分辨。
    	//为了在屏幕上凸显出高低变化的连续性,我们可以用对数尺度来替换线性尺度,以便于显示幅值,计算公式如下:
    	//=> log(1 + sqrt(Re(DFT(I))^2 +Im(DFT(I))^2))
    	magnitude(planes[0], planes[1], planes[0]);
    	Mat mag = planes[0];
    	mag += Scalar::all(1);
    	log(mag, mag);
    
    	//crop the spectrum, if it has an odd number of rows or columns
    	//修剪频谱,如果图像的行或者列是奇数的话,那其频谱是不对称的,因此要修剪
    	//这里为什么要用  &-2这个操作,我会在代码后面的 注2 说明
    	mag = mag(Rect(0, 0, mag.cols & -2, mag.rows & -2));
    	Mat _magI = mag.clone();
    	//这一步的目的仍然是为了显示,但是幅度值仍然超过可显示范围[0,1],我们使用 normalize() 函数将幅度归一化到可显示范围。
    	normalize(_magI, _magI, 0, 1, CV_MINMAX);
    	//imshow("before rearrange", _magI);
    
    	//rearrange the quadrants of Fourier image
    	//so that the origin is at the image center
    	//重新分配象限,使(0,0)移动到图像中心,  
    	//在《数字图像处理》中,傅里叶变换之前要对源图像乘以(-1)^(x+y)进行中心化。  
    	//这是是对傅里叶变换结果进行中心化
    	int cx = mag.cols / 2;
    	int cy = mag.rows / 2;
    
    	Mat tmp;
    	Mat q0(mag, Rect(0, 0, cx, cy));   //Top-Left - Create a ROI per quadrant
    	Mat q1(mag, Rect(cx, 0, cx, cy));  //Top-Right
    	Mat q2(mag, Rect(0, cy, cx, cy));  //Bottom-Left
    	Mat q3(mag, Rect(cx, cy, cx, cy)); //Bottom-Right
    
    	//swap quadrants(Top-Left with Bottom-Right)
    	q0.copyTo(tmp);
    	q3.copyTo(q0);
    	tmp.copyTo(q3);
    
    	// swap quadrant (Top-Rightwith Bottom-Left)
    	q1.copyTo(tmp);
    	q2.copyTo(q1);
    	tmp.copyTo(q2);
    
    
    	normalize(mag, mag, 0, 1, CV_MINMAX);
    	return mag;
    
    }
    

      图像变换结果:

     

    条纹状,观察其对称性:

    可以看到中心的斜线与原图像条纹垂直。这和条纹的明暗变化方向一致。

  • 相关阅读:
    mitmproxy抓包工具
    java基础|int和Integer的区别
    Vue|退出功能
    Vue|分页处理
    apt-get本地软件源搭建
    rqt_plot报错
    创建ROS 工作空间时出现:程序“catkin_init_workspace”尚未安装,程序“catkin_make”尚未安装。
    ubuntu16.04安装ROS
    debian及Ubuntu各版本下载地址获取
    解决sudo rosdep init和rosdep update的错误
  • 原文地址:https://www.cnblogs.com/the-home-of-123/p/11012783.html
Copyright © 2011-2022 走看看