(Opencv C++)數字影象處理-頻域增強
阿新 • • 發佈:2019-01-04
這裡我們將從兩個方面進行頻域增強的學習
一、任選兩幅影象(包括一副自備影象),計算其頻譜圖,並顯示
二、採用頻域濾波的方法進行影象降取樣和升取樣
一、首先計算其頻譜圖,用到的庫函式如下:
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;
}
按照自己的需要進行相應的處理即可。
完。