【QT+VTK 学习笔记】11:VTK图像平滑

前言

“VTK图形图像开发进阶_张晓东_罗火灵”的学习笔记。
东灵工作室 教程系列导航:http://blog.csdn.net/www_doling_net/article/details/8763686

学习资料

VTK官网学习地址:https://vtk.org/doc/nightly/html/

图像平滑

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

什么是卷积

卷积操作指的就是使用一个卷积核(kernel)对一张图像中的每个像素进行一系列操作。卷积核通常是一个四方形网格结构。(例如3X3的方形区域),该区域内每个方格都有一个权重值。当对图像中的某个像素进行卷积时,我们会把卷积核的中心放置于该图像上,依次计算核中每个元素和其覆盖的图像像素值的乘积并求和,得到的结果就是该位置的新像素值。卷积过程如下图。
在这里插入图片描述

均值滤波

均值滤波是一种常用的平滑方法,其对应的模板各个像素的值相同且和为1。在VTK中 没有直接实现均值滤波的类,但是可以通过图像卷积运算来实现均值滤波。卷积运算通过 vtklmageConvolve类实现。
在这里插入图片描述

#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)

#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageConvolve.h>
#include <vtkImageMandelbrotSource.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkImageCast.h>
#include <vtkJPEGReader.h>
#include <vtkImageShiftScale.h>

//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkJPEGReader> reader =
        vtkSmartPointer<vtkJPEGReader>::New();
    reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena-gray.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());
    //5*5*0.04=1 卷积模板对应的系数之和应该为1,否则需要对计算结果进行归一化处理
    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);//提供kernel 有 3*3 5*5 7*5
    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> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();;
    renderWindow->AddRenderer(originalRenderer);
    renderWindow->AddRenderer(convolvedRenderer);
    renderWindow->SetSize(640, 320);
    renderWindow->Render();
    renderWindow->SetWindowName("MeanFilterExample");

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    vtkSmartPointer<vtkInteractorStyleImage> style =
        vtkSmartPointer<vtkInteractorStyleImage>::New();

    renderWindowInteractor->SetInteractorStyle(style);
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

高斯平滑

通常用它来减少图像噪声以及降低细节层次。
高斯平滑的原理类似于均值滤波。均值滤波模板的系数都是一样的,而高斯平滑则是需 要根据像素与模板中心的距离来定义权重。
一维高斯分布函数图像:
在这里插入图片描述
在这里插入图片描述

#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)

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

//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkJPEGReader> reader =
        vtkSmartPointer<vtkJPEGReader>::New();
    reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena.jpg");
    reader->Update();

    vtkSmartPointer<vtkImageGaussianSmooth> gaussianSmoothFilter =
        vtkSmartPointer<vtkImageGaussianSmooth>::New();
    gaussianSmoothFilter->SetInputConnection(reader->GetOutputPort());
    gaussianSmoothFilter->SetDimensionality(2);     //设置相应维数
    gaussianSmoothFilter->SetRadiusFactor(10);       //设置模板大小
    gaussianSmoothFilter->SetStandardDeviation(10);  //设置高斯分布函数的标准差
    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, 1.0, 1.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> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(originalRenderer);
    renderWindow->AddRenderer(gradientMagnitudeRenderer);
    renderWindow->SetSize(640, 320);
    renderWindow->Render();
    renderWindow->SetWindowName("GaussianFilterExample");

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    vtkSmartPointer<vtkInteractorStyleImage> style =
        vtkSmartPointer<vtkInteractorStyleImage>::New();

    renderWindowInteractor->SetInteractorStyle(style);
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

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

中值滤波

中值滤波能够有效保持图像边缘,并对椒盐噪声有较好的抑制作用。.
VTK中用类vtkImageHybridMedian2D来实现二维图像的中值滤波若要实现三维图像的中值滤波,则使用vtkImageHybridMedian3D。其实现原理是釆用一个 5x5的模板,逐次将模板中心对应到图像的每个像素上,将模板图像覆盖的像素的中值作为当前像素的输出值。
在这里插入图片描述

#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)


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

//测试图像:../data/lena-noise.jpg
int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkJPEGReader> reader =
        vtkSmartPointer<vtkJPEGReader>::New();
    reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/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, 1.0, 1.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> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(originalRenderer);
    renderWindow->AddRenderer(hybridMedianRenderer);
    renderWindow->SetSize(640, 320);
    renderWindow->Render();
    renderWindow->SetWindowName("MedianFilterExample");

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    vtkSmartPointer<vtkInteractorStyleImage> style =
        vtkSmartPointer<vtkInteractorStyleImage>::New();

    renderWindowInteractor->SetInteractorStyle(style);
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

各向异性滤波

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

#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)

#include <vtkSmartPointer.h>
#include <vtkCamera.h>
#include <vtkImageActor.h>
#include <vtkImageAnisotropicDiffusion2D.h>
#include <vtkImageAnisotropicDiffusion3D.h>
#include <vtkImageCast.h>
#include <vtkImageData.h>
#include <vtkImageMandelbrotSource.h>
#include <vtkInteractorStyleImage.h>
#include <vtkJPEGReader.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>

//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkJPEGReader> reader =
        vtkSmartPointer<vtkJPEGReader>::New();
    reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena-gray.jpg");
    //向异性扩散滤波原理是在梯度较小的像素处进行较大幅度扩散而在大梯度处则只进行细微的扩散。
    /*
    该类中还有一个梯度类型变量GradientMagnitudeThreshold,
    该变量用来设置梯度算子类型。
    当该变量为1时,梯度通过中心差分方法计算;
    否则,需要比较当前像素与每个相邻像素。
    当前像素与相邻像素梯度小于DiffusionThreshold时进行扩散处理。
    */
    vtkSmartPointer<vtkImageAnisotropicDiffusion2D> diffusion =
        vtkSmartPointer<vtkImageAnisotropicDiffusion2D>::New();
    diffusion->SetInputConnection(reader->GetOutputPort());
    diffusion->SetNumberOfIterations(10);   //设置迭代的次数
    diffusion->SetDiffusionThreshold(200);   //扩散的阈值20 只有当像素梯度小于该阈值时才会进行扩散
    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> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(leftRenderer);
    renderWindow->AddRenderer(rightRenderer);
    renderWindow->SetSize(640, 320);
    renderWindow->Render();
    renderWindow->SetWindowName("AnistropicFilteringExample");

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    vtkSmartPointer<vtkInteractorStyleImage> style =
        vtkSmartPointer<vtkInteractorStyleImage>::New();

    renderWindowInteractor->SetInteractorStyle(style);
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jbyyy、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值