由DFT的性质知,输入为实信号(图像)的时候,频域输出为复数,因此将频域信息分为幅值和相位。频域的幅值高的代表高频分量,幅值低的地方代表低频分量,因此程序中使用
// => log(1+sqrt(Re(DFT(I))^2+Im(DFT(I))^2)) magI += Scalar::all(1); log(magI, magI); // crop the spectrum magI = magI(Rect(0, 0, magI.cols & (-2), magI.rows & (-2))); Mat _magI = magI.clone(); normalize(_magI, _magI, 0, 1, CV_MINMAX);进行log幅值计算及归一化幅值(归一化目的主要是方便将频域通过图像的形式进行显示)。
关于频域中心平移:将图像的高频分量平移到图像的中心,便于观测。
int cx = magI.cols/2; int cy = magI.rows/2; Mat q0(magI, Rect(0,0,cx,cy)); // Top-Left 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 // exchange Top-Left and Bottom-Right Mat tmp; q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); // exchange Top-Right and Bottom-Left q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2);其原理就是将左上角的频域和右下角的互换,右上角和左下角互换。
请注意:频域点和空域点的坐标没有一一对应的关系,两者的关系只是上面的DFT公式所见到的。
本程序因为使用到图像处理相关的函数,所以包含了头文件imgproc/imgproc.hpp,该文件位于opencv安装目录的include/opencv2/目录下,在编写Makefile时也要增加相关的头文件路径和库,本程序使用的Makefile如下:
TARG=fft2 SRC=fft2.cpp LIB=-L/usr/local/lib/ INC=-I/usr/local/include/opencv/ -I/usr/local/include/opencv2 CFLAGS= $(TARG):$(SRC) g++ -g -o $@ ${CFLAGS} $(LIB) $(INC) \ -lopencv_core -lopencv_highgui -lopencv_imgproc \ $^ .PHONY:clean clean: -rm $(TARG) tags -f其中Makefile中的\表示换行(反斜杠后不能再有任何字符,包括空格),如上库增加了-lopencv_imgproc,头文件路径增加了-I/usr/local/include/opencv2。
效果
上图从左到右分别是:原始灰度图(我大爱的杨过啊)、频域平移前的频域图像、频域中心平移后的频域图像。
提到图像频域变换的用途:压缩和去噪。压缩的原理就是在频域中,大部分频域的值为0(或接近0,可以进行有损压缩,如jpeg图像),只要压缩频域中的少数非0值即可达到图片压缩的目的。去噪则是通过频域的滤波实现,因为噪声大部分情况下体现为高频信号,使用低通滤波器即可滤除高频噪声(当然,也会带来损失,那就是边缘会变得模糊(之前说过,边缘也是高频信号))。
--------------------------------------分割线 --------------------------------------
Ubuntu Linux下安装OpenCV2.4.1所需包
CentOS下OpenCV无法读取视频文件
--------------------------------------分割线 --------------------------------------