5.6.1 快速傅立叶变换(FFT+RFFT)

1.图像频域处理的意义
       在图像处理和分析中,经常会将图像从图像空间转换到其他空间中,并利用这些空间的特点进行对转换后图像进行分析处理,然后再将处理后的图像转换到图像空间中,这称之为图像变换。
在一些图像处理和分析中通过空间变换往往会取得更有效的结果。图像频域处理是指将图像从图像空间转换到频域空间进行处理的过程。最常用的频域转换是傅里叶变换。
傅里叶变换的计算量较大,人们为了提高速度,提出了快速傅里叶变换,并得到了广泛的应用。本篇博客主要来学习VTK中的快速傅里叶变换。
2.快速傅里叶变换及其逆变换
       快速傅里叶变换(Fast Fourier Transform),简称做FFT。它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。傅里叶变换是可逆的,其逆变换为RFFT。
       FFT在数字图像处理中有着广泛的应用,例如数字图像频域滤波,去噪,增强等等。 目前VTK中两变换都已经实现,对应的类分别为vtkImageFFT和vtkImageRFFT。
      vtkImageFFT和vtkImageRFFT的输入为实数或者复数数据,输出都为复数数据。因此,vtkImageFFT与vtkImageRFFT的输出结果不能直接显示,因为VTK会将其当做彩色图像显示,需要通过vtkImageExtractComponents提取某一组分图像显示。
VTK频率域的图像处理步骤如下:

下面代码演示了怎样对图像进行傅里叶变换,以及将傅里叶变换结果进行逆变换:

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageFFT.h>
#include <vtkImageExtractComponents.h>
#include <vtkImageData.h>
#include <vtkImageShiftScale.h>
#include <vtkImageRFFT.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.jpg");
	reader->Update();
	//FFT//
	vtkSmartPointer<vtkImageFFT> imgFFT = vtkSmartPointer<vtkImageFFT>::New();
	imgFFT->SetInputConnection(reader->GetOutputPort());
	imgFFT->SetDimensionality(2);
	imgFFT->Update();
	//其输出为一个像素类型为复数的vtkImageData数据,即每个像素值为两个组分(Component):复数实部和虚部

	// the resualts are complex, we shoule extract one component to display
	vtkSmartPointer<vtkImageExtractComponents> imgComponent = vtkSmartPointer<vtkImageExtractComponents>::New();
	imgComponent->SetInputConnection(imgFFT->GetOutputPort());
	imgComponent->SetComponents(0);//指定提取实部
	// norm image range
	double Range[2];
	imgComponent->GetOutput()->GetScalarRange(Range);

	vtkSmartPointer<vtkImageShiftScale> imgfftShiftScale = vtkSmartPointer<vtkImageShiftScale>::New();
	imgfftShiftScale->SetOutputScalarTypeToUnsignedChar(); //vtkImageActor类仅支持unsigned char数据类型的图像,所以进行数据类型转换
	imgfftShiftScale->SetScale(255.0 / (Range[1] - Range[0]));
	imgfftShiftScale->SetShift(-Range[0]);
	imgfftShiftScale->SetInputConnection(imgComponent->GetOutputPort());
	imgfftShiftScale->Update();
	//RFFT/
	vtkSmartPointer<vtkImageRFFT> imgRFFT = vtkSmartPointer<vtkImageRFFT>::New();
	imgRFFT->SetInputConnection(imgFFT->GetOutputPort());
	imgRFFT->SetDimensionality(2);
	imgRFFT->Update();

	vtkSmartPointer<vtkImageExtractComponents> imgComponetNew = vtkSmartPointer<vtkImageExtractComponents>::New();
	imgComponetNew->SetInputConnection(imgRFFT->GetOutputPort());
	imgComponetNew->SetComponents(0);

	double RangeNew[2];
	imgComponetNew->GetOutput()->GetScalarRange(RangeNew);
	vtkSmartPointer<vtkImageShiftScale> imgrfftShiftScale = vtkSmartPointer<vtkImageShiftScale>::New();
	imgrfftShiftScale->SetOutputScalarTypeToUnsignedChar();
	imgrfftShiftScale->SetScale(255.0 / (RangeNew[1] - RangeNew[0]));
	imgrfftShiftScale->SetInputConnection(imgComponetNew->GetOutputPort());
	imgrfftShiftScale->Update();
	///
	//谨记vtkImageActor仅能够显示UnsignedChar类型数据
	vtkSmartPointer<vtkImageActor> origActor = vtkSmartPointer<vtkImageActor>::New();
	origActor->SetInputData(reader->GetOutput());
	vtkSmartPointer<vtkImageActor> fftActor = vtkSmartPointer<vtkImageActor>::New();
	fftActor->SetInputData(imgFFT->GetOutput());
	vtkSmartPointer<vtkImageActor> rfftActor = vtkSmartPointer<vtkImageActor>::New();
	rfftActor->SetInputData(imgrfftShiftScale->GetOutput());
	///
	double origView[4] = { 0, 0, 0.33, 1 };
	double fftView[4] = { 0.33, 0, 0.66, 1 };
	double rfftView[4] = { 0.66, 0, 1, 1 };
	vtkSmartPointer<vtkRenderer> origRender = vtkSmartPointer<vtkRenderer>::New();
	origRender->SetViewport(origView);
	origRender->AddActor(origActor);
	origRender->ResetCamera();
	origRender->SetBackground(1, 1, 1);

	vtkSmartPointer<vtkRenderer> fftRender = vtkSmartPointer<vtkRenderer>::New();
	fftRender->SetViewport(fftView);
	fftRender->AddActor(fftActor);
	fftRender->ResetCamera();
	fftRender->SetBackground(1, 1, 1);

	vtkSmartPointer<vtkRenderer> rfftRender = vtkSmartPointer<vtkRenderer>::New();
	rfftRender->SetViewport(rfftView);
	rfftRender->AddActor(rfftActor);
	rfftRender->ResetCamera();
	rfftRender->SetBackground(1, 1, 1);
	/
	vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(origRender);
	rw->AddRenderer(fftRender);
	rw->AddRenderer(rfftRender);
	rw->SetWindowName("Frequncy_FFT_RFFT");
	rw->SetSize(960, 320);

	vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
	rwi->SetInteractorStyle(style);
	rwi->SetRenderWindow(rw);
	rwi->Initialize();
	rwi->Start();

	return 0;
}

运行结果如下:

首先建立一个JPEG图像reader来读取一副灰度图像。然后定义一个vtkImageFFT指针,直接接收reader的输出即原图像数据作为输入进行二维快速傅里叶变换。其输出为一个像素类型为复数的vtkImageData数据,即每个像素值为两个组分(Component):复数实部和虚部。因此如果直接显示这个vtkImageData,会发现是一个彩色图像。如果需要显示频域图像,需要通过vtkImageExtractComponents类来提取某一个组分图像来显示。上例中通过定义vtkImageExtractComponents类指针,利用函数SetComponents(0)指定提取实部图像显示;由于vtkImageActor类仅支持unsigned char数据类型的图像,利用vtkImageCast类的SetOutputScalarTypeToUnsignedChar()指定输出类型为unsigned char,将FFT结果图像转换为需要的类型

对于逆变换的过程也是类似。首先定义vtkImageRFFT指针,并接收输入为vtkImageFFT指针的输出,调用Update执行函数完成快速傅里叶逆变换。vtkImageRFFT的输出同样为一副复数图像,通常不能直接显示或者进行其他操作。对于傅里叶逆变换的图像中虚数部分值为0,实数部分图像即为重建的原始图像。因此再次利用vtkImageExtractComponents提取实数部分图像,并通过SetOutputScalarTypeToUnsignedChar()将图像转换为unsigned char类型进行显示。

参考资料:

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值