1. 程式人生 > >(Opencv C++)數字影象處理-頻域增強

(Opencv C++)數字影象處理-頻域增強

    這裡我們將從兩個方面進行頻域增強的學習

一、任選兩幅影象(包括一副自備影象),計算其頻譜圖,並顯示

 

 

二、採用頻域濾波的方法進行影象降取樣和升取樣

 

一、首先計算其頻譜圖,用到的庫函式如下:

CV_EXPORTS_W void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0);

在進行dft之前我們需要提取圖片的行和列的畫素值,然後建立一個二維的陣列來儲存傅立葉變換的實部和虛部。

進行完dft之後,我們需要重新排列傅立葉影象的象限,使原點位於中心。

程式碼實現如下:

Mat Fourier_transform(Mat& imag)
{
	int r = getOptimalDFTSize(imag.rows);
	int c = getOptimalDFTSize(imag.cols);
	Mat padded;
	copyMakeBorder(imag, padded, 0, r - imag.rows, 0, c - imag.cols, BORDER_CONSTANT, Scalar::all(0));

	//為傅立葉變換的結果(複數,包含實部和虛部,所以需要建立一個二維的陣列
	//分配儲存空間,
	//需要用至少float型來儲存
	//最後將二維數組合併為二通道--傅立葉變換需要
	Mat dst1[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
	Mat dst2;
	merge(dst1, 2, dst2);

	//傅立葉變換,結果依舊儲存在dst2中
	dft(dst2, dst2);
	//將複數換算成幅值
	split(dst2, dst1);//把二通道影象分解為二維陣列,儲存到dst1中,dst1[0]中存放的為實部
	magnitude(dst1[0], dst1[1], dst1[0]);//結果存放在dst1[0]中
	Mat magnitudeImage = dst1[0];


	//對數尺度縮放以便於顯示
	//計算log(1 + sqrt(Re(DFT(dst2))**2 + Im(DFT(dst2))**2))
	magnitudeImage += Scalar::all(1);
	log(magnitudeImage, magnitudeImage);

	//剪下和重分佈幅度圖象限
	//若有奇數行或奇數列,進行頻譜裁剪
	magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2,    magnitudeImage.rows & -2));//任何一個數&-2的結果一定是偶數

	//重新排列傅立葉影象的象限,使原點位於影象中心
	int cx = magnitudeImage.cols / 2;
	int cy = magnitudeImage.rows / 2;
	Mat q0(magnitudeImage(Rect(0, 0, cx, cy)));
	Mat q1(magnitudeImage(Rect(cx, 0, cx, cy)));
	Mat q2(magnitudeImage(Rect(0, cy, cx, cy)));
	Mat q3(magnitudeImage(Rect(cy, cy, cx, cy)));

	Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);

	//將幅度值歸一化到0~1之間,這是因為magnitudeImage中的資料型別是浮點型,這時用imshow()來顯示函式,會將畫素值乘於255,因此需要歸一化到0~1之間
         normalize(magnitudeImage, magnitudeImage, 0, 1,NORM_MINMAX);


	//返回最後的頻譜影象
	return magnitudeImage;
}

其效果圖如下:

 

二、採用頻域濾波的方法進行影象降取樣和升取樣

這裡我們主要用到的庫函式如下:

CV_EXPORTS_W void pyrDown( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT ); //降取樣函式
CV_EXPORTS_W void pyrUp( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );//升取樣函式

高斯金字塔–降取樣

高斯金字塔從底向上,逐層降取樣取得,不能跨域越層;

對當前層刪除偶數行與列就得到降取樣後上一層的圖片;

 

高斯金字塔生成步驟:

①進行高斯模糊;

②刪除偶數行與列。

 

升取樣則與之相反。

程式碼如下:

//降取樣
Mat PyrDownTest(Mat& imag)
{
	Mat dest1, dest2;
	pyrDown(imag, dest1, Size(imag.cols/2 , imag.rows/2 ));
	pyrDown(dest1, dest2, Size(dest1.cols / 2, dest1.rows / 2));
	return dest2;
}
//升取樣
Mat PyrupTest(Mat& imag)
{
	Mat dest1, dest2;
	pyrUp(imag, dest1, Size(imag.cols * 2, imag.rows * 2));
	pyrUp(dest1, dest2, Size(dest2.cols * 2, dest2.rows * 2));
	return dest2;
}

效果圖如下:

主函式如下:

int main()
{
	/*
        Mat img = imread("5.jpg");
	Mat src = imread("p3-05.tif", CV_LOAD_IMAGE_GRAYSCALE);
	Mat src_1 = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);

	if (!img.data)
	{
		std::cout << "Image->img Load Fail!!!" << "\n";
		return 1;
	}
	if (!src.data)
	{
		std::cout << "Image->scr Load Fail!!!" << "\n";
		return 1;
	}
	if (!src_1.data)
	{
		std::cout << "Image-scr_1 Load Fail!!!" << "\n";
		return 1;
	}*/

	/**********************傅立葉變換*************************/
	//namedWindow("【載入的圖片1】", CV_WINDOW_AUTOSIZE);
	//imshow("【載入的圖片1】", src);

	//namedWindow("【載入的圖片2】", CV_WINDOW_AUTOSIZE);
	//imshow("【載入的圖片2】", src_1);
	// Mat show_img, show_img_1;
	//show_img = Fourier_transform(src);
	//show_img_1 = Fourier_transform(src_1);
	//imshow("【傅立葉變換後的圖片1】", show_img);
	//imshow("【傅立葉變換後的圖片2】", show_img_1);
	/*****************************************************/
	/**********************升取樣,降取樣*************************/
	/*namedWindow("【載入的圖片】", CV_WINDOW_AUTOSIZE);
	imshow("【載入的圖片】", img);
	Mat show_img;
	show_img = PyrDownTest(img);
	imshow("【降取樣後的圖片】", show_img);
	show_img = PyrupTest(show_img);
	imshow("【升取樣後的圖片】", show_img);*/
	/*****************************************************/
	waitKey(0);
	return 0;
}

按照自己的需要進行相應的處理即可。

完。