機器學習實踐系列之14
阿新 • • 發佈:2019-02-09
關於 傅立葉變換,講的太多了,這裡我就不再囉嗦一遍了,原理的東西大家可以搜一下,推薦一篇文章:
這篇文章寫得很不錯了,從 頻域 到傅立葉級數 講的都比較細,而且都有配圖,真看不懂的話就 你掐死他吧!
(PS:冤冤相報何時了,我在一旁看熱鬧,橫批:不嫌事大)
看下效果(居然暴漏了自己的迅雷,哈哈):
參考程式碼:
/* linolzhang 2013.11 基於OpenCV的傅立葉變換及逆變換 */ #include <iostream> #include "opencv2/highgui/highgui.hpp" #pragma comment(lib,"opencv_core2410.lib") #pragma comment(lib,"opencv_highgui2410.lib") //傅立葉正變換 void fft2(IplImage *src, IplImage *dst) { // 實部、虛部 IplImage *image_Re = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1); IplImage *image_Im = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1); IplImage *Fourier = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 2); cvConvertScale(src, image_Re); // 實部變換 u8 -> 64f cvZero(image_Im); // 虛部變換 -> 0 // Merge cvMerge(image_Re, image_Im, 0, 0, Fourier); // DFT計算傅立葉變換 cvDFT(Fourier, dst, CV_DXT_FORWARD); cvReleaseImage(&image_Re); cvReleaseImage(&image_Im); cvReleaseImage(&Fourier); } void fft2shift(IplImage *src, IplImage *dst) { IplImage *image_Re = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1); IplImage *image_Im = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1); cvSplit(src, image_Re, image_Im, 0, 0); // 具體原理見岡薩雷斯《數字影象處理》p123 // Compute the magnitude of the spectrum Mag = sqrt(Re^2 + Im^2) // 計算傅立葉譜 cvPow(image_Re, image_Re, 2.0); cvPow(image_Im, image_Im, 2.0); cvAdd(image_Re, image_Im, image_Re); cvPow(image_Re, image_Re, 0.5); // 對數變換以增強灰度級細節(這種變換使以窄帶低灰度輸入影象值對映 // 一寬頻輸出值,具體可見岡薩雷斯數字影象處理p62) // Compute log(1 + Mag); cvAddS(image_Re, cvScalar(1.0), image_Re); // 1 + Mag cvLog(image_Re, image_Re); // log(1 + Mag) // Rearrange the quadrants of Fourier image so that the origin is at the image center int cy = src->height / 2; int cx = src->width / 2; // CV_IMAGE_ELEM為OpenCV定義的巨集,用來讀取影象的畫素值,這一部分就是進行中心變換 for(int j=0; j<cy; j++) { for(int i=0; i<cx; i++) { // 中心化,將整體份成四塊進行對角交換 double tmp13 = CV_IMAGE_ELEM( image_Re, double, j, i); CV_IMAGE_ELEM( image_Re, double, j, i) = CV_IMAGE_ELEM(image_Re, double, j+cy, i+cx); CV_IMAGE_ELEM( image_Re, double, j+cy, i+cx) = tmp13; double tmp24 = CV_IMAGE_ELEM( image_Re, double, j, i+cx); CV_IMAGE_ELEM( image_Re, double, j, i+cx) = CV_IMAGE_ELEM( image_Re, double, j+cy, i); CV_IMAGE_ELEM( image_Re, double, j+cy, i) = tmp24; } } // 歸一化處理將矩陣的元素值歸一為[0,255] // [(f(x,y)-minVal)/(maxVal-minVal)]*255 double minVal = 0, maxVal = 0; // Localize minimum and maximum values cvMinMaxLoc( image_Re, &minVal, &maxVal ); // Normalize image (0 - 255) to be observed as an u8 image double scale = 255/(maxVal - minVal); double shift = -minVal * scale; cvConvertScale(image_Re, dst, scale, shift); cvReleaseImage(&image_Re); cvReleaseImage(&image_Im); } int main(int argc, char** argv) { IplImage *src = NULL; if(argc != 2) src = cvLoadImage("1.jpg", 0); // 載入源影象,轉為單通道 else src = cvLoadImage(argv[1], 0); IplImage *Fourier = cvCreateImage(cvGetSize(src),IPL_DEPTH_64F,2); // 傅立葉係數 IplImage *dst = cvCreateImage(cvGetSize(src),IPL_DEPTH_64F,2); IplImage *ImageRe = cvCreateImage(cvGetSize(src),IPL_DEPTH_64F,1); IplImage *ImageIm = cvCreateImage(cvGetSize(src),IPL_DEPTH_64F,1); IplImage *Image = cvCreateImage(cvGetSize(src),src->depth,src->nChannels); IplImage *ImageDst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels); fft2(src,Fourier); // 傅立葉變換 fft2shift(Fourier, Image); // 中心化 cvDFT(Fourier,dst,CV_DXT_INV_SCALE); // 實現傅立葉逆變換,並對結果進行縮放 cvSplit(dst,ImageRe,ImageIm,0,0); // 對陣列每個元素平方並存儲在第二個引數中 cvPow(ImageRe,ImageRe,2); cvPow(ImageIm,ImageIm,2); cvAdd(ImageRe,ImageIm,ImageRe,NULL); cvPow(ImageRe,ImageRe,0.5); double m,M; cvMinMaxLoc(ImageRe,&m,&M,NULL,NULL); double scale = 255/(M - m); double shift = -m * scale; // 將shift加在ImageRe各元素按比例縮放的結果上,儲存為ImageDst cvConvertScale(ImageRe,ImageDst,scale,shift); cvShowImage("源影象",src); cvShowImage("傅立葉譜",Image); cvShowImage("傅立葉逆變換",ImageDst); cvWaitKey(0); // 釋放資源 cvReleaseImage(&src); cvReleaseImage(&Image); cvReleaseImage(&ImageIm); cvReleaseImage(&ImageRe); cvReleaseImage(&Fourier); cvReleaseImage(&dst); cvReleaseImage(&ImageDst); return 0; }