OpenCV C++頻率域濾波 高斯低通

l  頻率域濾波的基本步驟

思想:通過濾波器函數以某種方式來修改圖像 變換,然後通過取結果的反變換來獲得處理後 的輸出圖像

低通濾波器:

              使低頻通過而使高頻衰減的濾波 器

              被低通濾波的圖像比原始圖像少尖銳的細節部分而 突出平滑過渡部分

              對比空間域濾波的平滑處理,如均值濾波器

高通濾波器:

             使高頻通過而使低頻衰減的濾波

            被高通濾波的圖像比原始圖像少灰度級的平滑過渡 而突出邊緣等細節部分

            對比空間域的梯度算子、拉普拉斯算子

 

濾波器處理效果的尖銳程度,可以將他們分爲三種類型:理想濾波器、巴特沃斯濾波器、高斯濾波器。他們的尖銳程度也是依次遞減。 
再從濾波的通過範圍看,這三種濾波器都有低通、高通、帶通、帶阻四個版本。 
下面將他們的的公式貼出來,就一目瞭然啦。

理想低通濾波器: 
這裏寫圖片描述 
理想高通濾波器: 
這裏寫圖片描述 
理想帶阻濾波器: 
這裏寫圖片描述 
這裏: 
這裏寫圖片描述

巴特沃斯低通濾波器: 
這裏寫圖片描述 
巴特沃斯高通濾波器: 
這裏寫圖片描述 
巴特沃斯帶阻濾波器: 
這裏寫圖片描述

W是帶寬

高斯低通濾波器 
這裏寫圖片描述 
高斯高通濾波器 
這裏寫圖片描述 
高斯帶阻濾波器 
這裏寫圖片描述

按照公式可以實現任意濾波器。

頻率域濾波——以高斯低通爲例

//**************************************
//頻率域濾波——以高斯低通爲例
//**************************************
#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;
Mat gaussianlbrf(Mat scr,float sigma);//高斯低通濾波器函數
Mat freqfilt(Mat scr,Mat blur);//頻率域濾波函數

static void help(char* progName)
{
    cout << endl
        <<  "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl
        <<  "The dft of an image is taken and it's power spectrum is displayed."          << endl
        <<  "Usage:"                                                                      << endl
        << progName << " [image_name -- default ../data/lena.jpg] "               << endl << endl;
}

int main( int argc, char *argv[])
{
    help(argv[0]);

    const char* filename = argc >=2 ? argv[1] : "../data/lena.jpg";

    Mat input = imread(filename, IMREAD_GRAYSCALE);
    if( input.empty())
        return -1;
    imshow("input",input);//顯示原圖

    int w=getOptimalDFTSize(input.cols);  //獲取進行dtf的最優尺寸
    int h=getOptimalDFTSize(input.rows); //獲取進行dtf的最優尺寸

    Mat padded;
    copyMakeBorder(input,padded,0,h-input.rows,0,w-input.cols,  BORDER_CONSTANT  , Scalar::all(0));  //邊界填充
    padded.convertTo(padded,CV_32FC1); //將圖像轉換爲flaot型

    Mat gaussianKernel=gaussianlbrf(padded,45);//高斯低通濾波器

    Mat out=freqfilt(padded,gaussianKernel);//頻率域濾波
    out = out(Rect(0,0,input.cols,input.rows));
    imshow("結果圖 sigma=40",out);

    waitKey(0);
    return 0;
}


//*****************高斯低通濾波器***********************
Mat gaussianlbrf(Mat scr,float sigma)
{
  Mat gaussianBlur(scr.size(),CV_32FC1); //,CV_32FC1
  float d0=2*sigma*sigma;//高斯函數參數,越小,頻率高斯濾波器越窄,濾除高頻成分越多,圖像就越平滑
  for(int i=0;i<scr.rows ; i++ )
  {
      for(int j=0; j<scr.cols ; j++ )
      {
          float d=pow(float(i-scr.rows/2),2)+pow(float(j-scr.cols/2),2);//分子,計算pow必須爲float型
          gaussianBlur.at<float>(i,j)=expf(-d/d0);//expf爲以e爲底求冪(必須爲float型)
      }
  }
   imshow("高斯低通濾波器",gaussianBlur);
 return gaussianBlur;
}


//*****************頻率域濾波*******************
Mat freqfilt(Mat scr,Mat blur)
{
    //***********************DFT*******************
    Mat plane[]={scr, Mat::zeros(scr.size() , CV_32FC1)}; //創建通道,存儲dft後的實部與虛部(CV_32F,必須爲單通道數)
    Mat complexIm;
    merge(plane,2,complexIm);//合併通道 (把兩個矩陣合併爲一個2通道的Mat類容器)
    dft(complexIm,complexIm);//進行傅立葉變換,結果保存在自身

    //***************中心化********************
    split(complexIm,plane);//分離通道(數組分離)

    int cx=plane[0].cols/2;int cy=plane[0].rows/2;//以下的操作是移動圖像  (零頻移到中心)
    Mat part1_r(plane[0],Rect(0,0,cx,cy));  //元素座標表示爲(cx,cy)
    Mat part2_r(plane[0],Rect(cx,0,cx,cy));
    Mat part3_r(plane[0],Rect(0,cy,cx,cy));
    Mat part4_r(plane[0],Rect(cx,cy,cx,cy));

    Mat temp;
    part1_r.copyTo(temp);  //左上與右下交換位置(實部)
    part4_r.copyTo(part1_r);
    temp.copyTo(part4_r);

    part2_r.copyTo(temp);  //右上與左下交換位置(實部)
    part3_r.copyTo(part2_r);
    temp.copyTo(part3_r);

    Mat part1_i(plane[1],Rect(0,0,cx,cy));  //元素座標(cx,cy)
    Mat part2_i(plane[1],Rect(cx,0,cx,cy));
    Mat part3_i(plane[1],Rect(0,cy,cx,cy));
    Mat part4_i(plane[1],Rect(cx,cy,cx,cy));

     part1_i.copyTo(temp);  //左上與右下交換位置(虛部)
    part4_i.copyTo(part1_i);
    temp.copyTo(part4_i);

    part2_i.copyTo(temp);  //右上與左下交換位置(虛部)
    part3_i.copyTo(part2_i);
    temp.copyTo(part3_i);

    //*****************濾波器函數與DFT結果的乘積****************
    Mat blur_r,blur_i,BLUR;
    multiply(plane[0], blur, blur_r); //濾波(實部與濾波器模板對應元素相乘)
    multiply(plane[1], blur,blur_i);//濾波(虛部與濾波器模板對應元素相乘)
    Mat plane1[]={blur_r, blur_i};
    merge(plane1,2,BLUR);//實部與虛部合併

      //*********************得到原圖頻譜圖***********************************
    magnitude(plane[0],plane[1],plane[0]);//獲取幅度圖像,0通道爲實部通道,1爲虛部,因爲二維傅立葉變換結果是複數
    plane[0]+=Scalar::all(1);  //傅立葉變o換後的圖片不好分析,進行對數處理,結果比較好看
    log(plane[0],plane[0]);    // float型的灰度空間爲[0,1])
    normalize(plane[0],plane[0],1,0,CV_MINMAX);  //歸一化便於顯示
    imshow("原圖像頻譜圖",plane[0]);


    //******************IDFT*******************************
    /*
    Mat part111(BLUR,Rect(0,0,cx,cy));  //元素座標(cx,cy)
    Mat part222(BLUR,Rect(cx,0,cx,cy));
    Mat part333(BLUR,Rect(0,cy,cx,cy));
    Mat part444(BLUR,Rect(cx,cy,cx,cy));
     part111.copyTo(temp);  //左上與右下交換位置(虛部)
    part444.copyTo(part111);
    temp.copyTo(part444);

    part222.copyTo(temp);  //右上與左下交換位置
    part333.copyTo(part222);
    temp.copyTo(part333);
    */

    idft( BLUR, BLUR);    //idft結果也爲複數
    split(BLUR,plane);//分離通道,主要獲取通道
    magnitude(plane[0],plane[1],plane[0]);  //求幅值(模)
    normalize(plane[0],plane[0],1,0,CV_MINMAX);  //歸一化便於顯示
    return plane[0];//返回參數
}
 

結果:

原圖:

原圖像頻譜圖

高斯低通濾波器

結果圖像:

結論

ü   GLPF不能達到有相同截止頻率的二階 BLPF的平滑效果

           ü   GLPF沒有振鈴

ü   如果需要嚴格控制低頻和高頻之間截 至頻率的過渡,選用BLPF,代價是可能 產生振鈴

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章