1. 程式人生 > >5.6.2 低通濾波器(理想低通+巴特沃斯低通濾波器)

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