5.5 图像滤波(均值、高斯、中值、各项异性滤波)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kateyabc/article/details/83628129

5.5.1 均值滤波

均值滤波是一种经常用到的平滑方法,其对应的模板各个像素的值为1。在VTK中没有直接实现均值滤波的类,但是我们可以通过图像卷积运算来实现。卷积运算通过vtkImageConvolve类实现。通过vtkImageConvolve类,只需要设置相应的卷积模板,便可以实现多种空域图像滤波。

下面代码说明了怎样使用vtkImageConvolve类来实现图像的均值滤波:


//中值滤波
#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageCast.h> //图像数据类型转换为计算类型
#include <vtkImageData.h>
#include <vtkImageConvolve.h>  //图像卷积运行
#include <vtkImageShiftScale.h> //设置像素值范围
//#include <vtkImageMandelbrotSource.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkImageMandelbrotSource.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>

int main()
{
	vtkSmartPointer<vtkJPEGReader> reader =
		vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("data\\lena-noise.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageCast> originalCastFilter =
		vtkSmartPointer<vtkImageCast>::New();
	originalCastFilter->SetInputConnection(reader->GetOutputPort()); //建管线
	originalCastFilter->SetOutputScalarTypeToFloat(); //设置属性
	originalCastFilter->Update();

	vtkSmartPointer<vtkImageConvolve> convolveFilter =
		vtkSmartPointer<vtkImageConvolve>::New();
	convolveFilter->SetInputConnection(originalCastFilter->GetOutputPort()); //建管线

	double kernel[25] = {
		0.04, 0.04, 0.04, 0.04, 0.04,
		0.04, 0.04, 0.04, 0.04, 0.04,
		0.04, 0.04, 0.04, 0.04, 0.04,
		0.04, 0.04, 0.04, 0.04, 0.04,
		0.04, 0.04, 0.04, 0.04, 0.04
	};
	convolveFilter->SetKernel5x5(kernel);
	convolveFilter->Update();

	vtkSmartPointer<vtkImageCast> convCastFilter =
		vtkSmartPointer<vtkImageCast>::New();
	convCastFilter->SetInputData(convolveFilter->GetOutput());
	convCastFilter->SetOutputScalarTypeToUnsignedChar(); //转换为图像数据
	convCastFilter->Update();
	///////////////////////////////////////////////////
	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> convolvedActor =
		vtkSmartPointer<vtkImageActor>::New();
	convolvedActor->SetInputData(convCastFilter->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> originalRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	originalRenderer->SetViewport(leftViewport);
	originalRenderer->AddActor(originalActor);
	originalRenderer->SetBackground(1.0, 1.0, 1.0);
	originalRenderer->ResetCamera();

	vtkSmartPointer<vtkRenderer> convolvedRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	convolvedRenderer->SetViewport(rightViewport);
	convolvedRenderer->AddActor(convolvedActor);
	convolvedRenderer->SetBackground(1.0, 1.0, 1.0);
	convolvedRenderer->ResetCamera();
	////////////////////////
	vtkSmartPointer<vtkRenderWindow> rw =
		vtkSmartPointer<vtkRenderWindow>::New();;
	rw->AddRenderer(originalRenderer);
	rw->AddRenderer(convolvedRenderer);
	rw->SetSize(640, 320);
	rw->Render();
	rw->SetWindowName("Smooth by MeanFilter");

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

	return 0;
}

运行结果如下:

        首先vtkJPEGReader对象读取一幅图像。考虑到进行卷积运算时数据范围的变化和精度要求,需要先将图像像素数据类型由unsigned char转换到float类型,该变换通过vtkImageCast实现,对应的设置函数SetOutputScalarTypeToFloat()。接下来需要定义卷积算子和卷积模板。vtkImageConvolve类实现图像的卷积运算,它需要两个输入。一个是需要进行卷积的图像,这里为vtkJPEGReader读取的图像数据,第二个是卷积模板数组。SetKernel5x5()函数接收一个5x5的卷积模板数组,即本例上定义的kernel数组。执行Update()后即可完成卷积运算。需要注意的是,卷积模板对应的系数之和应该为1,否则需要对计算结果进行归一化处理。另外该类中还定义了3x3和7x7的卷积模板设置函数,使用过程是一样的。卷积完成以后,再次通过vtkImageCast将float数据类型转换为unsigned char进行图像显示。

5.5.2高斯滤波

高斯平滑的原理类似于均值滤波。均值滤波模板的系数都是一样的,而高斯平滑则是需要根据像素与模板中心的距离来定义权重。权重的计算方法是采用高斯分布,离中心越远,权重越小。

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageCast.h>//图像数据类型转换
#include <vtkImageData.h>
#include <vtkImageGaussianSmooth.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-noise.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageGaussianSmooth> gaussianSmoothFilter =
		vtkSmartPointer<vtkImageGaussianSmooth>::New();
	gaussianSmoothFilter->SetInputConnection(reader->GetOutputPort());
	gaussianSmoothFilter->SetDimensionality(2);
	gaussianSmoothFilter->SetRadiusFactor(5); //设置模板范围
	gaussianSmoothFilter->SetStandardDeviation(3);//正态分布/高斯分布标准差
	gaussianSmoothFilter->Update();

	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> smoothedActor =
		vtkSmartPointer<vtkImageActor>::New();
	smoothedActor->SetInputData(gaussianSmoothFilter->GetOutput());

	double originalViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
	double smoothedViewport[4] = { 0.5, 0.0, 1.0, 1.0 };

	vtkSmartPointer<vtkRenderer> originalRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	originalRenderer->SetViewport(originalViewport);
	originalRenderer->AddActor(originalActor);
	originalRenderer->ResetCamera();
	originalRenderer->SetBackground(1.0, 0, 0);

	vtkSmartPointer<vtkRenderer> gradientMagnitudeRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	gradientMagnitudeRenderer->SetViewport(smoothedViewport);
	gradientMagnitudeRenderer->AddActor(smoothedActor);
	gradientMagnitudeRenderer->ResetCamera();
	gradientMagnitudeRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderWindow> rw =
		vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(originalRenderer);
	rw->AddRenderer(gradientMagnitudeRenderer);
	rw->SetSize(640, 320);
	rw->SetWindowName("Smooth by Gaussian");

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

	return 0;
}

运行结果如下所示:

vtkImageGaussianSmooth类默认是执行三维高斯滤波;
SetDimensionality()根据需要设置相应的维数;
SetRadiusFactor()用于设置高斯模板的大小,当超出该模板的范围时,系数取0;
SetStandardDeviation()用于设置高斯分布函数的标准差。
 

扫描二维码关注公众号,回复: 4211341 查看本文章

5.5.3 中值滤波

vtkImageHybridMedian2D实现了对二维图像的中值滤波。其实现原理是,采用一个5x5的模板,逐次将模板中心对应于图像的每个像素上,将模板图像覆盖的像素的中值作为当前像素的输出值。

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageData.h>
#include <vtkImageCast.h>
#include <vtkImageHybridMedian2D.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>

int main(int argc, char* argv[])
{
	vtkSmartPointer<vtkJPEGReader> reader =
		vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("data\\lena-noise.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageHybridMedian2D> hybridMedian =
		vtkSmartPointer<vtkImageHybridMedian2D>::New();
	hybridMedian->SetInputData(reader->GetOutput());
	hybridMedian->Update();
	///////////////////////////////////////////////////////
	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> hybridMedianActor =
		vtkSmartPointer<vtkImageActor>::New();
	hybridMedianActor->SetInputData(hybridMedian->GetOutput());
	/////////////////////
	double originalViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
	double hybridMedianViewport[4] = { 0.5, 0.0, 1.0, 1.0 };

	vtkSmartPointer<vtkRenderer> originalRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	originalRenderer->SetViewport(originalViewport);
	originalRenderer->AddActor(originalActor);
	originalRenderer->ResetCamera();
	originalRenderer->SetBackground(1.0, 0, 0);

	vtkSmartPointer<vtkRenderer> hybridMedianRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	hybridMedianRenderer->SetViewport(hybridMedianViewport);
	hybridMedianRenderer->AddActor(hybridMedianActor);
	hybridMedianRenderer->ResetCamera();
	hybridMedianRenderer->SetBackground(1.0, 1.0, 1.0);
	//////////////////////////
	vtkSmartPointer<vtkRenderWindow> rw =
		vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(originalRenderer);
	rw->AddRenderer(hybridMedianRenderer);
	rw->SetSize(640, 320);
	rw->Render();
	rw->SetWindowName("MedianFilterExample");

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

	return 0;
}

运行结果如下:

该类使用非常简单,不需要用户设置任何参数。该方法能够有效的保持图像边缘,并对于椒盐噪声有较好的抑制作用。对于三维图像,则使用vtkImageHybridMedian3D类。

5.5.4 各项异性滤波

高斯平滑方法在平滑噪声的同时,模糊了图像的重要边缘图像。

各向异性滤波是一种基于偏微分方程的滤波技术,建立于热量的各向异性扩散理论。

各向异性滤波在图像的平坦区域选择大尺度平滑,而边缘区域则选择小尺度的平滑,在抑制噪声的同时保持了图像的边缘信息。

vtkImageAnisotropicDiffusion2D(vtkImageAnisotropicDiffusion3D)实现图像各向异性扩散滤波,代码如下:

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageCast.h>
#include <vtkImageAnisotropicDiffusion2D.h>
#include <vtkImageActor.h>
#include <vtkCamera.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-noise.jpg");

	vtkSmartPointer<vtkImageAnisotropicDiffusion2D> diffusion =
		vtkSmartPointer<vtkImageAnisotropicDiffusion2D>::New();
	diffusion->SetInputConnection(reader->GetOutputPort());
	diffusion->SetNumberOfIterations(200); //用于设置迭代次数
	diffusion->SetDiffusionThreshold(5); //小于该阈值扩散
	diffusion->Update();
	/////////////////////////////////////////////////////////////////
	vtkSmartPointer<vtkImageActor> originalActor =
		vtkSmartPointer<vtkImageActor>::New();
	originalActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> diffusionActor =
		vtkSmartPointer<vtkImageActor>::New();
	diffusionActor->SetInputData(diffusion->GetOutput());
	////////////////////
	double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
	double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };

	vtkSmartPointer<vtkCamera> camera =
		vtkSmartPointer<vtkCamera>::New();
	vtkSmartPointer<vtkRenderer> leftRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	leftRenderer->SetViewport(leftViewport);
	leftRenderer->AddActor(originalActor);
	leftRenderer->SetBackground(1.0, 1.0, 1.0);
	leftRenderer->SetActiveCamera(camera);
	leftRenderer->ResetCamera();

	vtkSmartPointer<vtkRenderer> rightRenderer =
		vtkSmartPointer<vtkRenderer>::New();
	rightRenderer->SetViewport(rightViewport);
	rightRenderer->SetBackground(1.0, 1.0, 1.0);
	rightRenderer->AddActor(diffusionActor);
	rightRenderer->SetActiveCamera(camera);
	/////////////////////
	vtkSmartPointer<vtkRenderWindow> rw =
		vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(leftRenderer);
	rw->AddRenderer(rightRenderer);
	rw->SetSize(540, 320);
	rw->SetWindowName("Smooth by AnistropicFilter");

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

	return 0;
}

运行结果如下:

vtkImageAnisotropicDiffusion2D类通过迭代方法实现。
其中SetNumberOfIterations()用于设置迭代的次数;
各向异性扩散滤波原理是在梯度较小的像素处进行较大幅度扩散,而在大梯度处则只进行细微的扩散。因此需要设置一个扩算的阈值DiffusionThreshold,这个阈值与图像的梯度有关。SetDiffusionThreshold()即是用来设置扩散阈值。该类中还有一个梯度标志GradientMagnitudeThreshold,用来设置梯度算子。当该标志开时梯度通过中心差分方法计算;当标志为关时,需要单独处理每个相邻像素。当像素与相邻像素梯度小于DiffusionThreshold时进行扩散处理。

参考资料:

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
 

猜你喜欢

转载自blog.csdn.net/kateyabc/article/details/83628129