1. 程式人生 > >機器學習實踐系列之14

機器學習實踐系列之14

       關於 傅立葉變換,講的太多了,這裡我就不再囉嗦一遍了,原理的東西大家可以搜一下,推薦一篇文章:

       這篇文章寫得很不錯了,從 頻域傅立葉級數 講的都比較細,而且都有配圖,真看不懂的話就 你掐死他吧!

       (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;
}