VTK知识学习(36)-图像平滑

1、前言

图像平滑常用于图像的预处理中,如计算梯度时先对图像进行平滑处理,可以减少噪声对梯度的影响。图像平滑一般是通过模板卷积运算实现。模板可以看作一个大小为nxn的小图像,例如 3x3、5x5等,模板的每个像素都对应一个系数值。模板卷积运算的过程先是将模板中心依次与图像每个像素重合,然后通过模板各个系数与图像对应像素相乘来计算模板对应像素的加权平均值,最后将运算结果赋给图像中模板中心对应的像素。

2、均值滤波

1)概述

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

2)代码
cs 复制代码
 private void TestMeanFilter()
 {
     //读取图像
     vtkJPEGReader reader = vtkJPEGReader.New();
     reader.SetFileName("F:\\code\\VTK\\TestActiViz\\data\\lena-gray.jpg");
     reader.Update();

     // 考虑到进行卷积运算时数据范围的变化和精度要求
     // 需要先将图像像素数据类型由unsigned char转换为float
     vtkImageCast originalCastFilter = vtkImageCast.New();
     originalCastFilter.SetInputConnection(reader.GetOutputPort());
     originalCastFilter.SetOutputScalarTypeToFloat();
     originalCastFilter.Update();

     //实现图像的卷积运算,两个输入:一个是计算的图像,一个是卷积模板数组
     vtkImageConvolve convoleFilter = vtkImageConvolve.New();
     convoleFilter.SetInputConnection(originalCastFilter.GetOutputPort());

     double[] kernel={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 };
     IntPtr dataPtr = Marshal.AllocHGlobal(sizeof(double) * kernel.Length);
     Marshal.Copy(kernel, 0, dataPtr, kernel.Length);
     convoleFilter.SetKernel5x5(dataPtr);
     convoleFilter.Update();

     //再将 float类型转换为unsigned char 进行图像显示
     vtkImageCast convCastFilter = vtkImageCast.New();
     convCastFilter.SetInputData(convoleFilter.GetOutput());
     convCastFilter.SetOutputScalarTypeToUnsignedChar();
     convCastFilter.Update();

     ShowImageBy2(reader.GetOutput(), convCastFilter.GetOutput());

 }
3)效果
4)说明

卷积运算时数据范围的变化和精度有要求,需要先将图像像素数据类型由unsigned char 转换成 float 数据类型。

数据类型转换通过 vtkImageCast 实现,对应的设置函数为SetOutputScalarTypeToFloat()。接着需要定义卷积算子和卷积模板。

vtklmageConvolve 类可实现图像的卷积运算,它需要两个输入:一个是需要进行卷积的图像,这里为vtkJPEGReader 读取的图像数据;另一个是卷积模板数组。

SetKermel5x5()函数接收一个 5x5的卷积模板数组,即定义的kermel数组。执行Update()后即可完成卷积运算。

注意,卷积模板对应的系数之和应该为1,否则需要对计算结果进行归一化处理。另外该类中还定义了3x3和7x7的卷积模板设置函数,使用过程是一样的。卷积运算完成后再次通过 vtkImageCast 类将 foat数据类型转换为unsigned char 数据类型进行图像显示。

3、高斯平滑

1)概述

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

2)代码
cs 复制代码
private void TestGaussianFilter()
 {
     //读取图像
     vtkJPEGReader reader = vtkJPEGReader.New();
     reader.SetFileName("F:\\code\\VTK\\TestActiViz\\data\\lena-gray.jpg");
     reader.Update();

     //默认执行三维高斯滤波 
     vtkImageGaussianSmooth gaussianSmooth = vtkImageGaussianSmooth.New();
     gaussianSmooth.SetInputConnection(reader.GetOutputPort());
     gaussianSmooth.SetDimensionality(2);
     gaussianSmooth.SetRadiusFactor(5);  //设置高斯模板的大小 当超出该模板的范围时,系数取0
     gaussianSmooth.SetStandardDeviation(3);  //用于设置高斯分布函数的标准差
     gaussianSmooth.Update();

     ShowImageBy2(reader.GetOutput(), gaussianSmooth.GetOutput());

 }
3)效果
4)说明

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

4、中值滤波

1)概述

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

2)代码
cs 复制代码
 private void TestMedianFilter()
 {
     //读取图像
     vtkJPEGReader reader = vtkJPEGReader.New();
     reader.SetFileName("F:\\code\\VTK\\TestActiViz\\data\\lena-gray.jpg");
     reader.Update();

     //中值滤波 不需要设置任何参数  有效保持图像边缘,并对椒盐噪声有较好的抑制作用。
    
     vtkImageHybridMedian2D hybridMedian2D = vtkImageHybridMedian2D.New();
     hybridMedian2D.SetInputData(reader.GetOutput());
     hybridMedian2D.Update();

     ShowImageBy2(reader.GetOutput(), hybridMedian2D.GetOutput());
 }
3)效果
4)说明

vtkImageHybridMedian2D类的使用,不需要用户设置任何参数。该方法能够有效保持图像边缘,并对椒盐噪声有较好的抑制作用。若要实现三维图像的中值滤波,则使用vtkImageHybridMedian3D类。

5、各向异性滤波

1)概述

高斯平滑方法在平滑噪声的同时模糊了图像的重要边缘信息。各向异性滤波是一种基于偏微分方程的滤波技术,建立于热量的各向异性扩散理论。各向异性滤波在图像的平坦区域选择大尺度平滑,而在边缘区域则选择小尺度的平滑,在抑制噪声的同时也保持了图像的边缘信息。VTK中用 vkImageAnisotropicDiffusion2D 类和 vtkImageAnisotropicDiffusion3D 类分别实现对二维和三维图像的各向异性扩散滤波。

2)代码
cs 复制代码
 private void TestAnistropicFilter()
 {
     //读取图像
     vtkJPEGReader reader = vtkJPEGReader.New();
     reader.SetFileName("F:\\code\\VTK\\TestActiViz\\data\\lena-gray.jpg");
     reader.Update();

     //通过迭代方法实现 
     vtkImageAnisotropicDiffusion2D diffusion2D = vtkImageAnisotropicDiffusion2D.New();
     diffusion2D.SetInputConnection(reader.GetOutputPort());
     diffusion2D.SetNumberOfIterations(10); //设置迭代的次数
     diffusion2D.SetDiffusionThreshold(20); //扩散的阈值
     diffusion2D.Update();

     ShowImageBy2(reader.GetOutput(), diffusion2D.GetOutput());
}
3)效果
4)说明

vtkImageAnisotropicDiffusion2D 类通过迭代方法实现,其中 SetNumberOfIterations()用于设置迭代的次数。各向异性扩散滤波原理是在梯度较小的像素处进行较大幅度扩散,而在大梯度处则只进行细微的扩散。该类中定义了一个扩散的值 DiffusionThreshold,并通过SetDiffusionThreshold()设置,只有当像素梯度小于该阈值时才会进行扩散。另外,该类中还有一个梯度类型变量 GradientMagnitudeThreshold,该变量用来设置梯度算子类型。当该变量为1时,梯度通过中心差分方法计算;否则,需要比较当前像素与每个相邻像素。当前像素与相邻像素梯度小于 DifusionThreshold 时进行扩散处理。

相关推荐
扶离_flee6 分钟前
麦田物语学习笔记:构建游戏的时间系统
笔记·学习·游戏
古斯塔斯hugh7 分钟前
VUE学习笔记10__vue指令v-on配置method函数
vue.js·笔记·学习
dal118网工任子仪1 小时前
58,【8】BUUCTF [PwnThyBytes 2019]Baby_SQL1
数据库·笔记·sql·学习·mysql
s_little_monster3 小时前
【Linux】打破Linux神秘的面纱
linux·运维·经验分享·笔记·学习·学习方法
stormjun4 小时前
2025 年 Java 最新学习资料与学习路线——从零基础到高手的成长之路
java·开发语言·学习·java学习路线·java 学习教程·2025java 学习路线
【上下求索】4 小时前
学习笔记081——如何备份服务器中MySQL数据库数据?
数据库·笔记·学习
dal118网工任子仪4 小时前
55.【5】BUUCTF WEB NCTF2019 sqli
数据库·笔记·sql·学习·mysql·安全
隼玉5 小时前
【STM32-学习笔记-10-】BKP备份寄存器+时间戳
c语言·笔记·stm32·学习
虾球xz5 小时前
游戏引擎学习第79天
学习·游戏引擎