VTK随笔六:VTK图像处理(图像创建、图像显示)

一、VTK图像创建

1、VTK 图像数据结构

         数字图像文件内容由两个部分组成:图像头信息和数据。图像头信息定义了图像的基本信息,主要包括起点位置(Origin)、像素间隔(Space)和维数(Dimension)。通过这三个参数即可确定图像空间位置和大小。

        图像数据即为图像像素的像素值,一般采用一维数组来表示和存储。 

2、VTK 图像创建

 1)图像源 Source
        VTK 中内置了多个创建图像的Source类,利用这些Source 类可以快速创建图像。以 vtkImageCanvasSource2D为例。该Source 类的功能是创建一个画布(空白图像),并提供了多种几何图形(点、线段、圆、矩形以及图像等)的绘制填充功能。 

#include <QApplication>
#include <vtkSmartPointer.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <QVTKOpenGLNativeWidget.h>
#include <vtkGenericOpenGLRenderWindow.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    vtkSmartPointer<vtkImageCanvasSource2D> canvas = vtkSmartPointer<vtkImageCanvasSource2D>::New();
    canvas->SetScalarTypeToUnsignedChar();
    canvas->SetNumberOfScalarComponents(1);
    canvas->SetExtent(0, 100, 0, 100, 0, 0);
    canvas->SetDrawColor(0, 0, 0, 0);
    canvas->FillBox(0,100,0,100);
    canvas->SetDrawColor(255, 0, 0, 0);
    canvas->FillBox(20,40,20,40);
    canvas->Update();

    // Create actors
    vtkSmartPointer<vtkImageActor> redActor = vtkSmartPointer<vtkImageActor>::New();
    redActor->SetInputData(canvas->GetOutput());

    // Setup renderers
    vtkSmartPointer<vtkRenderer> redRenderer = vtkSmartPointer<vtkRenderer>::New();
    redRenderer->AddActor(redActor);
    redRenderer->ResetCamera();
    redRenderer->SetBackground(1.0, 1.0, 1.0);

    // Setup render window
    vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
    renderWindow->AddRenderer(redRenderer);
    QVTKOpenGLNativeWidget w;
    w.setWindowTitle("ImageCanvasSource2D");
    w.setRenderWindow(renderWindow);
    w.show();

    return a.exec();
}

 运行效果:

        除了 vkImageCanvasSource2D外,VTK还提供了其他类似的Source 类来快速生成特定的图像,例如 vtkImageEllipsoidSource,该类根据指定的中心以及各个轴的半径来生成一个前景为椭圆(球)的二值图像;vtkImageGaussianSource 类生成一幅像素值服从高斯分布的图像;vtkImageGridSource用于生成网格线图像;vtkImageNoiseSource 生成一个像素值为随机数的噪声图像;vtkImageSinusoidSource生成的图像像素值由正弦函数决定 。

2) 直接创建图像

#include <QApplication>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkInformation.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <QVTKOpenGLNativeWidget.h>
#include <vtkGenericOpenGLRenderWindow.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    vtkSmartPointer<vtkImageData> img =  vtkSmartPointer<vtkImageData>::New();
    vtkSmartPointer<vtkInformation> info =  vtkSmartPointer<vtkInformation>::New();
    img->SetDimensions(16,16,1);
    img->SetScalarType(VTK_UNSIGNED_CHAR,info);
    img->SetNumberOfScalarComponents(1,info);
    img->AllocateScalars(info);

    unsigned char *ptr = (unsigned char*)img->GetScalarPointer();
    for(int i=0; i<16*16*1; i++)
    {
        *ptr ++ =i%256;
    }

    vtkSmartPointer<vtkImageActor> redActor = vtkSmartPointer<vtkImageActor>::New();
    redActor->SetInputData(img);

    vtkSmartPointer<vtkRenderer> redRenderer = vtkSmartPointer<vtkRenderer>::New();
    redRenderer->AddActor(redActor);
    redRenderer->ResetCamera();
    redRenderer->SetBackground(1.0, 1.0, 1.0);

    vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
    renderWindow->AddRenderer(redRenderer);
    QVTKOpenGLNativeWidget w;
    w.setWindowTitle("CreateVTKImageData");
    w.setRenderWindow(renderWindow);
    w.show();

    return a.exec();
}

        首先定义vtklmageData指针,然后指定图像的维数,而图像的原点和像素间隔则都是采用默认值,因此不需要设置。SetScalarType指定图像的每个像素值的数据类型为unsigned char,SetNumberOfScalarComponents则指定了每个像素值的数据成分为1,每个像素值为1个标量值,参数设置完毕后,调用AllocateScalars()分配内存,生成图像数据。图像生成后,默认所有像素值为0。可以通过访问图像数据数组来设每个像素值GetScalarPointer()即返回图像的数据数组(图像数据数组都采用一维数组),然后根据图像的大小,访问每个像素并为其赋值。生成的图像如下所示:

二、VTK图像显示

 1、vtklmageViewer2

        vtklmageViewer2 中封装了 VTK 图像显示的可视化渲染引擎,包括 vtkActor、vtkRender、vtkRenderWindow、vtkInteractorStypelmage等对象,可以方便地完成图像显示和交互。该类提供的主要交互操作有图像放缩、窗宽窗位调节,并提供切片选择及切片方向设置接口,尤其适合三维图像的切片显示。

#include <QApplication>
#include <vtkSmartPointer.h>
#include <vtkMetaImageReader.h>
#include <vtkImageViewer2.h>
#include <vtkRenderer.h>
#include <QVTKOpenGLNativeWidget.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    vtkSmartPointer<vtkMetaImageReader> reader = vtkSmartPointer<vtkMetaImageReader>::New();
    reader->SetFileName("D:/data/brain.mhd");
    reader->Update();

    vtkSmartPointer<vtkImageViewer2> imageViewer = vtkSmartPointer<vtkImageViewer2>::New();
    imageViewer->SetInputConnection(reader->GetOutputPort());
    imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);

    QVTKOpenGLNativeWidget w;
    imageViewer->SetupInteractor(w.interactor()); //初始化交互器
    imageViewer->SetRenderWindow(w.renderWindow());  //初始化渲染窗口
    w.setWindowTitle("DisplayImageExample");
    w.show();
    imageViewer->SetColorLevel(500); //窗位
    imageViewer->SetColorWindow(2000); //窗宽
    imageViewer->SetSlice(40); //切片索引
    imageViewer->SetSliceOrientationToXY(); //切片方向

    return a.exec();
}

vtklmageViewer2显示三维图像的某个切片:

 1)窗宽/窗位的概念
        窗宽是图像显示的灰度范围。一般显示器的灰度范围为256级,而医学图像的灰度范围则远远大于该范围,因此通过显示器显示时不能显示所有灰度级,需要使用窗宽来定义欲显示的灰度范围。当灰度值高于该范围的最大值时,均以白影显示;当低于该范围时,均以黑色显示。若增大窗宽,则显示具有不同灰度值的组织结构增多,但是会降低组织之间的对比度,若减小窗宽,则可视的不同灰度组织结构会减少,同时增大组织结构的对比度。

2)医学图像二维视图
        切片(Slice)或切面是三维图像比较常用的概念,尤其在医学图像中,不同方向的切面都有特定的名字,分别是:矢状面(SagitalPlane),沿着身体前后径所做的与地面垂直的切面;冠状面(CoronalPlane),沿着身体左右径所做的与地面垂直的切面;横断面(Transverse/AxialPlane),是指横断身体与地面平行的切面。

 2、vtklmageActor

vtkImageActor 是一个三维图像渲染 Actor,通过纹理映射将图像映射到一个多边形上进行显示。 

#include <QApplication>
#include <vtkSmartPointer.h>
#include <vtkBMPReader.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();
    reader->SetFileName ("D:/data/lena.bmp");
    reader->Update();

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

    vtkSmartPointer<vtkRenderer> renderer =
        vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(imgActor);
    renderer->SetBackground(1.0, 1.0, 1.0);

    vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
    renderWindow->AddRenderer(renderer);

    QVTKOpenGLNativeWidget w;
    w.setRenderWindow(renderWindow);
    w.setWindowTitle("DisplayImageExample");
    w.show();

    return a.exec();
}

运行效果:

        需要注意的是,vtkImageActor 接收的图像数据 vtkImageData像素类型必须为unsigned char,如果类型不符合要求,在显示图像前需要先将图像数据类型转换为unsigned char。 

3、图像融合 

        图像融合是利用图像的不透明度来合成图像。在 VTK 中,用类 vtkImageBlend 实现图像的融合。 vtkmageBlend 可以接收多个图像输入,其输出为融合图像。输出图像的像素间隔、原点、范围以及像素组分个数与第一个图像一致。

#include <QApplication>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkImageBlend.h>
#include <vtkRenderer.h>
#include <vtkJPEGReader.h>
#include <vtkImageActor.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
    reader->SetFileName ("D:/data/lena-gray.jpg");
    reader->Update();

    vtkSmartPointer<vtkImageCanvasSource2D> imageSource = vtkSmartPointer<vtkImageCanvasSource2D>::New();
    imageSource->SetNumberOfScalarComponents(1);
    imageSource->SetScalarTypeToUnsignedChar();
    imageSource->SetExtent(0, 512, 0, 512, 0, 0);
    imageSource->SetDrawColor(0.0);
    imageSource->FillBox(0, 512, 0, 512);
    imageSource->SetDrawColor(255.0);
    imageSource->FillBox(100,400,100,400);
    imageSource->Update();

    vtkSmartPointer<vtkImageBlend> imageBlend = vtkSmartPointer<vtkImageBlend>::New();
    imageBlend->AddInputData(reader->GetOutput());
    imageBlend->AddInputData(imageSource->GetOutput());
    imageBlend->SetOpacity(0, 0.4);
    imageBlend->SetOpacity(1, 0.6);
    imageBlend->Update();

    // Create actors
    vtkSmartPointer<vtkImageActor> originalActor1 = vtkSmartPointer<vtkImageActor>::New();
    originalActor1->SetInputData(reader->GetOutput());

    vtkSmartPointer<vtkImageActor> originalActor2 =vtkSmartPointer<vtkImageActor>::New();
    originalActor2->SetInputData(imageSource->GetOutput());

    vtkSmartPointer<vtkImageActor> blendActor = vtkSmartPointer<vtkImageActor>::New();
    blendActor->SetInputData(imageBlend->GetOutput());

    // Define viewport ranges (xmin, ymin, xmax, ymax)
    double leftViewport[4] = {0.0, 0.0, 0.33, 1.0};
    double midViewport[4] = {0.33, 0.0, 0.66, 1.0};
    double rightViewport[4] = {0.66, 0.0, 1.0, 1.0};

    // Setup renderers
    vtkSmartPointer<vtkRenderer> originalRenderer1 = vtkSmartPointer<vtkRenderer>::New();
    originalRenderer1->AddActor(originalActor1);
    originalRenderer1->ResetCamera();
    originalRenderer1->SetBackground(1.0, 1.0, 1.0);
    originalRenderer1->SetViewport(leftViewport);

    vtkSmartPointer<vtkRenderer> originalRenderer2 = vtkSmartPointer<vtkRenderer>::New();
    originalRenderer2->AddActor(originalActor2);
    originalRenderer2->ResetCamera();
    originalRenderer2->SetBackground(1.0, 1.0, 1.0);
    originalRenderer2->SetViewport(midViewport);

    vtkSmartPointer<vtkRenderer> blendRenderer = vtkSmartPointer<vtkRenderer>::New();
    blendRenderer->AddActor(blendActor);
    blendRenderer->ResetCamera();
    blendRenderer->SetBackground(1.0, 1.0, 1.0);
    blendRenderer->SetViewport(rightViewport);

    vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
    renderWindow->AddRenderer(originalRenderer1);
    renderWindow->AddRenderer(originalRenderer2);
    renderWindow->AddRenderer(blendRenderer);

    QVTKOpenGLNativeWidget w;
    w.resize(640,320);
    w.setRenderWindow(renderWindow);
    w.setWindowTitle("ImageBlendExample");
    w.show();

    return a.exec();
}

 运行效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值