5.6.2 低通濾波器(理想低通+巴特沃斯低通濾波器)
1.低通濾波器
低通濾波是將頻域影象中的高頻部分濾除而通過低頻部分。影象的邊緣和噪聲對應於頻域影象中的高頻部分,而低通濾波的作用即是減弱這部分的能量,從而達到影象平滑去噪的目的。
2.理想低通濾波器
最簡單的低通濾波器是理想低通濾波器,基本思想是給定一個頻率閾值,將高於該閾值的所有部分設定為0,而低於該頻率的部分保持不變。
理想是指該濾波器不能用電子元器件來實現,但是可以通過計算機來模擬。
在VTK中定義了理想低通濾波器,下面我們來看下怎麼使用該濾波器來對影象進行低通濾波:
//理想低通濾波器 #include <vtkSmartPointer.h> #include <vtkJPEGReader.h> #include <vtkImageFFT.h> #include <vtkImageIdealLowPass.h> #include <vtkImageData.h> #include <vtkImageRFFT.h> #include <vtkImageCast.h> #include <vtkImageExtractComponents.h> #include <vtkImageActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> int main() { vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New(); reader->SetFileName("data\\lena.jpg"); reader->Update(); vtkSmartPointer<vtkImageFFT> fftFilter = vtkSmartPointer<vtkImageFFT>::New(); fftFilter->SetInputConnection(reader->GetOutputPort()); fftFilter->Update(); vtkSmartPointer<vtkImageIdealLowPass> lowPassFilter = vtkSmartPointer<vtkImageIdealLowPass>::New(); lowPassFilter->SetInputConnection(fftFilter->GetOutputPort()); lowPassFilter->SetXCutOff(0.05); //設定x\y方向上的截斷頻率 lowPassFilter->SetYCutOff(0.05); lowPassFilter->Update(); vtkSmartPointer<vtkImageRFFT> rfftFilter = vtkSmartPointer<vtkImageRFFT>::New();//將處理後的頻域影象轉換至空域影象, rfftFilter->SetInputConnection(lowPassFilter->GetOutputPort()); //注意:轉換後的影象每個畫素值都是一個複數; rfftFilter->Update(); vtkSmartPointer<vtkImageExtractComponents> ifftExtractReal = vtkSmartPointer<vtkImageExtractComponents>::New(); ifftExtractReal->SetInputConnection(rfftFilter->GetOutputPort()); ifftExtractReal->SetComponents(0);//提取實部分量 vtkSmartPointer<vtkImageCast> castFilter = vtkSmartPointer<vtkImageCast>::New();//資料型別轉換為unsigned char型別 castFilter->SetInputConnection(ifftExtractReal->GetOutputPort()); castFilter->SetOutputScalarTypeToUnsignedChar(); castFilter->Update(); vtkSmartPointer<vtkImageActor> originalActor = vtkSmartPointer<vtkImageActor>::New(); originalActor->SetInputData(reader->GetOutput()); vtkSmartPointer<vtkImageActor> erodedActor = vtkSmartPointer<vtkImageActor>::New(); erodedActor->SetInputData(castFilter->GetOutput()); double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 }; double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 }; vtkSmartPointer<vtkRenderer> leftRenderer = vtkSmartPointer<vtkRenderer>::New(); leftRenderer->AddActor(originalActor); leftRenderer->ResetCamera(); leftRenderer->SetViewport(leftViewport); leftRenderer->SetBackground(1.0, 0, 0); vtkSmartPointer<vtkRenderer> rightRenderer = vtkSmartPointer<vtkRenderer>::New(); rightRenderer->AddActor(erodedActor); rightRenderer->SetViewport(rightViewport); rightRenderer->ResetCamera(); rightRenderer->SetBackground(1.0, 1.0, 1.0); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(rightRenderer); renderWindow->AddRenderer(leftRenderer); renderWindow->SetSize(540, 320); renderWindow->SetWindowName("Frequency_IdealLowPassFilter"); vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); renderWindow->Render(); interactor->Start(); return 0; }
執行結果如下:
從結果看,在過濾掉影象的高頻部分後,影象變得模糊,丟失了許多細節,另外還可以看到影象會存在一定的振鈴效應,這也是理想低通濾波的特點。
首先讀入一副影象,通過vtkImageFFT將影象轉換到頻域空間。vtkImageIdealLowPass對頻域影象做理想低通濾波,需要使用者設定每個方向的截斷頻率,相應的設定函式SetXCutOff()和SetYCutOff()。執行完畢後,需要通過vtkImageRFFT將處理後的頻域影象轉換至空域影象。需要注意的是,轉換後的影象每個畫素都是一個複數,需要vtkImageExtractComponents將該影象的第一個分量提出出來顯示,否則影象不能正確顯示。由於傅立葉變換輸入輸出的資料型別都是double,為了方便顯示,還需要將其轉換為Unsigned char型別,這裡vtkImageCast負責型別轉換。
3.巴特沃茲低通濾波器
在實際中經常使用的是巴特沃斯濾波器。巴特沃斯濾波器對應的轉移函式(可以看做是一個係數矩陣)是:
其中D(u,v)表示頻域點(u,v)到頻域影象原點的距離,稱為截止頻率,當D(u,v) = 時,H(u,v)=0.5,即對應的頻域能量將為原來的一半。因為巴特沃斯低通濾波器在高低頻間的過渡平滑,因此不會出現明顯的振鈴效應。VTK中實現巴特沃斯低通濾波器的類是vtkImageButterworthLowPass.
/***********************巴特沃茲低通濾波器*****************************************/
#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageFFT.h>
#include <vtkImageButterworthLowPass.h>
#include <vtkImageRFFT.h>
#include <vtkImageExtractComponents.h>
#include <vtkImageCast.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
int main()
{
vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName("data\\lena-gray.jpg");
reader->Update();
vtkSmartPointer<vtkImageFFT> fftFilter = vtkSmartPointer<vtkImageFFT>::New();
fftFilter->SetInputConnection(reader->GetOutputPort());
fftFilter->Update();
vtkSmartPointer<vtkImageButterworthLowPass> lowPassFilter = vtkSmartPointer<vtkImageButterworthLowPass>::New();
lowPassFilter->SetInputConnection(fftFilter->GetOutputPort());
lowPassFilter->SetXCutOff(0.05);
lowPassFilter->SetYCutOff(0.05);
lowPassFilter->Update();
vtkSmartPointer<vtkImageRFFT> rfftFilter = vtkSmartPointer<vtkImageRFFT>::New();
rfftFilter->SetInputConnection(lowPassFilter->GetOutputPort());
rfftFilter->Update();
vtkSmartPointer<vtkImageExtractComponents> ifftExtractReal = vtkSmartPointer<vtkImageExtractComponents>::New();
ifftExtractReal->SetInputConnection(rfftFilter->GetOutputPort());
ifftExtractReal->SetComponents(0);
vtkSmartPointer<vtkImageCast> castFilter = vtkSmartPointer<vtkImageCast>::New();
castFilter->SetInputConnection(ifftExtractReal->GetOutputPort());
castFilter->SetOutputScalarTypeToUnsignedChar();
castFilter->Update();
////////////////////////////////////////////////////
vtkSmartPointer<vtkImageActor> originalActor = vtkSmartPointer<vtkImageActor>::New();
originalActor->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkImageActor> erodedActor = vtkSmartPointer<vtkImageActor>::New();
erodedActor->SetInputData(castFilter->GetOutput());
///////////////////////
double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> leftRenderer = vtkSmartPointer<vtkRenderer>::New();
leftRenderer->AddActor(originalActor);
leftRenderer->SetViewport(leftViewport);
leftRenderer->SetBackground(1.0, 1.0, 1.0);
leftRenderer->ResetCamera();
vtkSmartPointer<vtkRenderer> rightRenderer = vtkSmartPointer<vtkRenderer>::New();
rightRenderer->AddActor(erodedActor);
rightRenderer->SetViewport(rightViewport);
rightRenderer->SetBackground(1.0, 1.0, 1.0);
rightRenderer->ResetCamera();
vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(leftRenderer);
rw->AddRenderer(rightRenderer);
rw->SetSize(640, 320);
rw->SetWindowName("ButterworthLowPassExample");
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
rwi->SetInteractorStyle(style);
rwi->SetRenderWindow(rw);
rwi->Start();
return 0;
}
執行結果如下:
vtkImageButterworthLowPass與理想低通濾波器的使用一樣。為了便於比較,這裡設定X和Y方向的截止頻率時,與理想低通濾波器設定一致,從結果來看,巴特沃斯低通濾波器產生的影象更為平滑,不會出現振鈴現象。
參考資料:
1.《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
2. 張曉東, 羅火靈. VTK圖形影象開發進階[M]. 機械工業出版社, 2015.
所用軟體:vtk7.0+visual studio 2013
注:此文知識學習筆記,僅記錄完整程式和實現結果,具體原理參見:
https://blog.csdn.net/www_doling_net/article/details/8541534
https://blog.csdn.net/shenziheng1/article/category/6114053/4