当前位置: 首页 > article >正文

VTK知识学习(28)-区域提取

1、感兴趣区域(Volume ofInterest,VOI)

        它是图像内部的一块子区域。在VTK中,vtkExtractVOI 类可根据用户指定的区域范围提取子图像。该Filter 的输入和输出都是一个vtkImageData,因此其结果可以直接作为图像保存。

代码:

private void TestExtractVOI()
{
    vtkBMPReader reader = vtkBMPReader.New();
    reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena.bmp");
    reader.Update();

    int[] dims = reader.GetOutput().GetDimensions();

    //提取红色对应灰度图像
    vtkExtractVOI extractVOI = vtkExtractVOI.New();
    extractVOI.SetInputData(reader.GetOutput());
    // 6个参数 依次表示X方向坐标最小值、最大值  Y方向最小值、最大值 Z方向最小值、最大值。
    extractVOI.SetVOI(dims[0] / 4, (int)3.0 * dims[0] / 4, dims[1] / 4, (int)3.0 * dims[1] / 4, 0, 0);
    extractVOI.Update();

    vtkImageActor orgActor = vtkImageActor.New();
    orgActor.SetInputData(reader.GetOutput());

    vtkImageActor voiActor = vtkImageActor.New();
    voiActor.SetInputData(extractVOI.GetOutput());

    vtkRenderer orgRenderer = vtkRenderer.New();
    orgRenderer.AddActor(orgActor);
    orgRenderer.SetViewport(0.0, 0.0, 0.5, 1.0);
    orgRenderer.ResetCamera();
    orgRenderer.SetBackground(1, 1, 1);

    vtkRenderer renderer3 = vtkRenderer.New();
    renderer3.SetViewport(0.5, 0.0, 1, 1.0);
    renderer3.AddActor(voiActor);
    renderer3.ResetCamera();
    renderer3.SetBackground(1, 1, 1);

    vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;
    renderWindow.AddRenderer(orgRenderer);
    renderWindow.AddRenderer(renderer3);
    renderWindow.Render();
}

效果: 

        先读取一幅 BMP 图像,并获取图像的维数;然后定义 vtkExtractVOI对象,该对象接收两个输入:第一个是图像数据,第二个是区域大小。设置区域大小的函数原型的代码如下:

        

public virtual void SetVOI(int _arg1, int _arg2, int _arg3, int _arg4, int _arg5, int _arg6);
public virtual void SetVOI(IntPtr _arg);

        其参数是所提取区域各个方向的大小,共6个参数,依次表示X方向坐标最小值、X方向最大值、Y方向最小值、Y方向最大值、Z方向最小值和Z方向最大值。由于示例读取的是二维图像,因此Z方向的区域为[0,0],而X方向的范围为[dims[0]/4,3*dims[0]/4],Y方向的范围为[dims[1]/4,3*dims[1]/4],即提取图像原图中间 1/4图像。

2、三维图像切面提取

        除了冠状面、矢状面和横断面,即过图像内部一点且平行于 XY、YZ.XZ平面的平面,切面也可以是过三维图像内部一点且平行于任意方向的平面。通过提取切面可以方便地浏览和分析图像内部组织结构,这是医学图像浏览软件中的一个重要的功能。VTK中 vtkImageReslice 类可实现图像切面的提取。

代码:

private void TestReslice()
{
    vtkMetaImageReader reader = vtkMetaImageReader.New();
    reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\brain.mhd");
    reader.Update();

    int[] extent = reader.GetOutput().GetExtent();
    double[] spacing = reader.GetOutput().GetSpacing();
    double[] origin = reader.GetOutput().GetOrigin();

    double[] center = new double[3];
    center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
    center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
    center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);
    double[] axialElements =
    //       {
    //    0, 0, -1, 0,
    //    1, 0, 0, 0,
    //    0, -1, 0, 0,
    //    0, 0, 0, 1
    //};//提取平行于YZ平面的切片
      //        {
      //    1, 0, 0, 0,
      //    0, 1, 0, 0,
      //    0, 0, 1, 0,
      //    0, 0, 0, 1
     // };//提取平行于XZ平面的切片
    {
                1, 0, 0, 0,
                0, 0.866025, -0.5, 0,
                0, 0.5, 0.866025, 0,
                0, 0, 0, 1
            };//提取斜切切片

    IntPtr ptrData = Marshal.AllocHGlobal(sizeof(double) * axialElements.Length);
    Marshal.Copy(axialElements, 0, ptrData, axialElements.Length);
    vtkMatrix4x4 resliceAxes = vtkMatrix4x4.New();
    resliceAxes.DeepCopy(ptrData);
    resliceAxes.SetElement(0, 3, center[0]);
    resliceAxes.SetElement(1, 3, center[1]);
    resliceAxes.SetElement(2, 3, center[2]);

    vtkImageReslice reslice = vtkImageReslice.New();
    reslice.SetInputData(reader.GetOutput());
    reslice.SetOutputDimensionality(2);
    reslice.SetResliceAxes(resliceAxes);
    // reslice.SetInterpolationModeToLinear(); //指定切面提取中的插值方式为线性插值
    reslice.SetInterpolationModeToNearestNeighbor(); //最近邻插值
    //  reslice.SetInterpolationModeToCubic(); //三次线性插值
    reslice.Update();

    vtkLookupTable colorTable = vtkLookupTable.New();
    colorTable.SetRange(0, 1000);
    colorTable.SetValueRange(0, 1);
    colorTable.SetSaturationRange(0, 0);
    colorTable.SetRampToLinear();
    colorTable.Build();

    vtkImageMapToColors colorMap = vtkImageMapToColors.New();
    colorMap.SetLookupTable(colorTable);
    colorMap.SetInputConnection(reslice.GetOutputPort());
    colorMap.Update();

    vtkImageActor orgActor = vtkImageActor.New();
    orgActor.SetInputData(colorMap.GetOutput());

    vtkRenderer renderer3 = vtkRenderer.New();
    renderer3.AddActor(orgActor);
    renderer3.ResetCamera();
    renderer3.SetBackground(1, 1, 1);

    vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;
    renderWindow.AddRenderer(renderer3);
    renderWindow.Render();
}

效果:

        先通过 vtkMetaImageReader 读取一幅三维图像,获取图像范围、原点和像素间隔,由这三个参数可以计算图像的中心位置;接下来定义了切面的变换矩阵axialElements,该矩阵的前三列分别表示X、Y和乙方向矢量,第四列为切面坐标系原点。通过修改切面坐标系原点,可以得到不同位置的切面图像。代码中的 axialElements 表示切面坐标系与图像坐标系一致,且经过图像中心点 center。定义该切面时,也可以使用其他平面,甚至是任意平面,但是必须过图像内部点。下面给出了一个常用的变换矩阵:

 double[] axialElements =
    //       {
    //    0, 0, -1, 0,
    //    1, 0, 0, 0,
    //    0, -1, 0, 0,
    //    0, 0, 0, 1
    //};//提取平行于YZ平面的切片
      //        {
      //    1, 0, 0, 0,
      //    0, 1, 0, 0,
      //    0, 0, 1, 0,
      //    0, 0, 0, 1
     // };//提取平行于XZ平面的切片
    {
                1, 0, 0, 0,
                0, 0.866025, -0.5, 0,
                0, 0.5, 0.866025, 0,
                0, 0, 0, 1
            };//提取斜切切片

        注意:使用这些变换矩阵时,需要将第四列替换为切片经过图像的一个点坐标,上例中将图像的中心添加到变换矩阵 axialElements,并通过函数 SetResliceAxes()设置变换矩阵。

SetOutputDimensionality(2)指定输出的图像为一个二维图像;

SetlnterpolationModeToLinear()则指定了切面提取中的插值方式为线性插值.

另外该类中还提供了其他插值方式:

        SetInterpolationModeToNearestNeighbor():最近邻插值。
        SetInterpolationModeToCubic():三次线性插值。

3、 扩展

       在三维图像切面提取程序的基础上进行扩展,实现一个稍微复杂的程序,即通过滑动鼠标来切换三维图像切面,这也是医学图像处理软件中一个基本的功能。实现该功能的难点是怎样在 VTK 中控制鼠标来实时提取图像切面。可以通过观察者/命令模式来实现这种功能。VTK中鼠标消息是在交互器样式(InteractorStyle)中响应,因此通过为交互器样式添加观察者(Observer)来监听相应的消息,当消息触发时,由命令模式执行相应的回调函数即可。

在c++中,继承后进行更改Execute函数。并进行注册。

class vtkMyCallback : public vtkCommand
{
public:
	static vtkMyCallback* New()
	{
		return new vtkMyCallback;
	}
	void Execute(vtkObject* caller, unsigned long, void*) 
	{
		vtkTransform* t = vtkTransform::New();
		vtkBoxWidget* widget = reinterpret_cast<vtkBoxWidget*>(caller);
		widget->GetTransform(t);
		widget->GetProp3D()->SetUserTransform(t);
		t->Delete();
	}
};

c#版本使用包装控件会报错,暂时没有查找到问题。

private void TestInteractorStyle()
        {
            vtkMetaImageReader reader = vtkMetaImageReader.New();
            reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\brain.mhd");
            reader.Update();

            int[] extent = reader.GetOutput().GetExtent();
            double[] spacing = reader.GetOutput().GetSpacing();
            double[] origin = reader.GetOutput().GetOrigin();

            double[] center = new double[3];
            center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
            center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
            center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);

            double[] axialElements ={
               1, 0, 0, 0,
               0, 1, 0, 0,
               0, 0, 1, 0,
               0, 0, 0, 1
           };//提取平行于YZ平面的切片

            IntPtr ptrData = Marshal.AllocHGlobal(sizeof(double) * axialElements.Length);
            Marshal.Copy(axialElements, 0, ptrData, axialElements.Length);
            vtkMatrix4x4 resliceAxes = vtkMatrix4x4.New();
            resliceAxes.DeepCopy(ptrData);
            resliceAxes.SetElement(0, 3, center[0]);
            resliceAxes.SetElement(1, 3, center[1]);
            resliceAxes.SetElement(2, 3, center[2]);

            vtkImageReslice reslice = vtkImageReslice.New();
            reslice.SetInputData(reader.GetOutput());
            reslice.SetOutputDimensionality(2);
            reslice.SetResliceAxes(resliceAxes);
            reslice.SetInterpolationModeToLinear(); //指定切面提取中的插值方式为线性插值
            reslice.Update();

            vtkLookupTable colorTable = vtkLookupTable.New();
            colorTable.SetRange(0, 1000);
            colorTable.SetValueRange(0, 1);
            colorTable.SetSaturationRange(0, 0);
            colorTable.SetRampToLinear();
            colorTable.Build();

            vtkImageMapToColors colorMap = vtkImageMapToColors.New();
            colorMap.SetLookupTable(colorTable);
            colorMap.SetInputConnection(reslice.GetOutputPort());
            colorMap.Update();

            vtkImageActor orgActor = vtkImageActor.New();
            orgActor.SetInputData(colorMap.GetOutput());

            vtkRenderer renderer3 = vtkRenderer.New();
            renderer3.AddActor(orgActor);
            renderer3.ResetCamera();
            renderer3.SetBackground(0.4, 0.5, 0.6);

            vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;
            renderWindow.AddRenderer(renderer3);

            vktImageInteractionCallback callback = new vktImageInteractionCallback();
            callback.SetImageReslice(reslice);
            callback.SetInteractor(renderWindow);

            renderWindow.AddObserver((uint)vtkCommand.EventIds.LeftButtonPressEvent, callback, 0);
            renderWindow.AddObserver((uint)vtkCommand.EventIds.MouseMoveEvent, callback, 0);
            renderWindow.AddObserver((uint)vtkCommand.EventIds.LeftButtonReleaseEvent, callback, 0);

            renderWindow.Render();

           
        }


http://www.kler.cn/a/466427.html

相关文章:

  • 重庆大学软件工程复试怎么准备?
  • Java jni调用nnom rnn-denoise 降噪
  • windows11安装minikube
  • 【Android项目学习】3. MVVMHabit
  • 使用FDBatchMove的几个问题总结
  • k8s基础(3)—Kubernetes-Deployment
  • SpringMVC的消息转换器
  • 国产芯RK3568教学实验箱操作案例:颜色识别抓取积木
  • Android 第三方框架:网络框架:OkHttp:源码分析:缓存
  • 基于springboot+vue的校园论坛系统
  • 代码随想录day34 动态规划2
  • js逆向:算法分析某携酒店数据接口参数testab的生成
  • DALL·E 2模型及其论文详解
  • WPF的一些控件的触发事件记录
  • 渗透测试-非寻常漏洞案例
  • 使用IDEA远程debug服务器上的jar包
  • 基于 Python 虎扑网站的 NBA 球员大数据分析与可视化
  • QEMU网络配置简介
  • Wireshark中的名称解析设置详解
  • ROS 2中的DDS中间件
  • 小信号处理
  • LeetCode -Hot100 - 438. 找到字符串中所有字母异位词
  • 前后端分离项目部署到云服务器、宝塔(前端vue、后端springboot)详细教程
  • Trimble天宝X9三维扫描仪为建筑外墙检测提供了全新的解决方案【沪敖3D】
  • 【运维工具】Ansible一款好用的自动化工具
  • MQ-导读