图像傅立叶频谱分析
参考:http://cns-alumni.bu.edu/~slehar/fourier/fourier.html#filtering 很棒
分析:
如果输入二维图像数据,则显示的图像是输入的灰度分布,傅立叶频谱是输入的频率分布,频谱图中心对称。
图像频谱即二维频谱图通过对原图像进行水平和竖直两个方向的所有扫描线处一维傅立叶变换的叠加得到
频谱图中以图中心为圆心,圆的相位对应原图中频率分量的相位,半径对应频率高低,低频半径小,高频半径大,中心为直流分量,某点亮度对应该频率能量高低。
从测试案例中更清楚的提现以上几点
以下为几个测试案例:
1.水平方向为sin函数,竖直方向没有变化,对应频谱如图为零相位相对低频的一个亮点,而其他位置基本为黑色,说明没有其他频率分量(水平方向其他小亮点是由于原图不是严格的sin函数而产生的噪声)
2.相对1频率变高,频谱图中亮点位置半径变大
3.sin函数方向改变,频谱图的方向也改变,两种解释。可以理解为水平方向和竖直方向单独扫描都是sin函数,对应频谱叠加所得。也可是理解为原图sin函数方向(相位)改变,频谱图相位变化
4.3图叠加1图
5.频率再次升高,频谱图半径再次增大
6.1图叠加2图,频谱图也叠加
7.原图为一条竖直线,每个行扫描需要若干频率(几乎所有频率)正弦曲线去叠加逼近,所以频谱图包含了所有频率,竖直扫描依然没有变化,频谱图只有一条横线。
8.以下两图对比,第一个图变化不明显,对比度低,频谱图中心亮周围暗,主要为低频分量
第二个图相对对比度高,频谱周围部分比第一张图的频谱要亮的多,第二张图高频分量更多,但原图背景仍然是灰色图,所以频谱图也是中心最亮,低频分量最高。
代码:
1.图像的傅里叶频谱的意义
之前的博文其实已经归纳过这方面的内容了。我们常用的图像平滑处理,其实就是一个低通滤波,一定程度上去除高频信号,可以使得图像变得柔和(也就是平滑)。但是,在去除周期性噪声时候,空间域内的滤波(卷积)就不是那么好操作了。所以,这里时候,无论是理解起来方便,还是其他原因,都需要在频域内进行滤波。
详细的叙述还是在下面的博文里面啦!!!!
[数字图像处理]频域滤波(1)–基础与低通滤波器
[数字图像处理]频域滤波(2)–高通滤波器,带阻滤波器与陷波滤波器
2. 傅里叶频谱的计算
这部分的内容,主要就是使用OpenCV自带的函数
void cvDFT( const CvArr* src, CvArr* dst, int flags, int nonzero_rows=0 )
去求取图像的傅里叶变换。这里,输出结果CvArr* dst由两个通道组成,分别代表了实部与虚部。我们再根据如下算式,就可以得到傅里叶频谱了。
|F(u,v)|=R2(u,v)+F2(u,v)‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾√2
我自己也参考了很多人的代码,然后实现的代码如下。
<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">IplImage* fft2(IplImage* image_input) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dftWidth = getOptimalDFTSize(image_input->width); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dftHeight = getOptimalDFTSize(image_input->height); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//cout<< " Width" << image_input->width << " " << dftWidth << "\n";</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//cout<< "Height" << image_input->height << " " << dftHeight << "\n";</span> IplImage* image_padded = cvCreateImage(cvSize(dftWidth,dftHeight), IPL_DEPTH_8U, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); cvCopyMakeBorder( image_input, image_padded, cvPoint(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>), IPL_BORDER_CONSTANT,cvScalarAll(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)); IplImage *image_Re =<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> , *image_Im = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, *image_Fourier = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; image_Re = cvCreateImage(cvSize(dftWidth,dftHeight),IPL_DEPTH_64F,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); image_Im = cvCreateImage(cvSize(dftWidth,dftHeight),IPL_DEPTH_64F,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); image_Fourier = cvCreateImage(cvSize(dftWidth,dftHeight),IPL_DEPTH_64F,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//image_Re <--- image_padded </span> cvConvertScale(image_padded,image_Re); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//image_Im <--- 0</span> cvZero(image_Im); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//image_Fourier[0] <--- image_Re</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//image_Fourier[1] <--- image_Im</span> cvMerge(image_Re,image_Im,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,image_Fourier); cvDFT(image_Fourier,image_Fourier,CV_DXT_FORWARD); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//image_Fourier[0] ---> image_Re</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//image_Fourier[1] ---> image_Im</span> cvSplit(image_Fourier,image_Re,image_Im,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//Mag = sqrt(Re^2 + Im^2)</span> cvPow(image_Re,image_Re,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2.0</span>); cvPow(image_Im,image_Im,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2.0</span>); cvAdd(image_Re,image_Im,image_Re); cvPow(image_Re,image_Re,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// log (1 + Mag)</span> cvAddS(image_Re,cvScalar(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>),image_Re ); cvLog (image_Re,image_Re); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// |-----|-----| |-----|-----| </span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// | 1 | 3 | | 4 | 2 |</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// |-----|-----| ---> |-----|-----|</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// | 2 | 4 | | 3 | 1 |</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// |-----|-----| |-----|-----|</span> IplImage *Fourier = cvCreateImage(cvSize(dftWidth,dftHeight),IPL_DEPTH_64F,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); cvZero(image_Fourier); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> cx = image_Re->width/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> cy = image_Re->height/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; cvSetImageROI(image_Re,cvRect( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1 </span> cvSetImageROI( Fourier,cvRect(cx,cy,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 4 </span> cvAddWeighted(image_Re,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,Fourier,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,Fourier); cvSetImageROI(image_Re,cvRect(cx,cy,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 4 </span> cvSetImageROI( Fourier,cvRect( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1 </span> cvAddWeighted(image_Re,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,Fourier,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,Fourier); cvSetImageROI(image_Re,cvRect(cx, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3 </span> cvSetImageROI( Fourier,cvRect( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,cy,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2 </span> cvAddWeighted(image_Re,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,Fourier,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,Fourier); cvSetImageROI(image_Re,cvRect( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,cy,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2 </span> cvSetImageROI( Fourier,cvRect(cx, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,cx,cy)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3 </span> cvAddWeighted(image_Re,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,Fourier,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,Fourier); cvResetImageROI(image_Re); cvResetImageROI( Fourier); cvNormalize(Fourier,Fourier,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,CV_C,<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>(Fourier); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0