Создание и чтение файлов .vtk из файлов .dcm и изменение модели

Я хотел бы лучше понять объемный рендеринг dicom.

У меня есть набор изображений dicom, из которых я смог извлечь аксиальные, коронарные и сагиттальные срезы следующим образом:

введите здесь описание изображения

Сначала я хотел создать 3D-модель с нуля, но это оказалось слишком сложно.

Итак, я услышал о VTK/ITK и использовал этот код для создания файла .vtk из моего набора изображений:

http://www.itk.org/Doxygen46/html/IO_2DicomSeriesReadImageWrite2_8cxx-example.html

Это работает, но мне нужны некоторые пояснения:

Когда я открываю этот файл с помощью ParaView, я получаю следующий результат:

введите здесь описание изображения

Во-первых, это может быть глупый вопрос, но почему он синий?

Есть ли способ вырезать и увидеть внутреннюю часть модели?

Моя цель не использовать ParaView, и я хотел бы сделать свой собственный считыватель .vtk, я нашел этот код, не помню где, который, я думаю, должен работать, но все, что я получаю с ним, это зеленый фон ни с чем больше:

#include <vtkPolyDataReader.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>

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

  // Parse command line arguments                                                                     
  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " Filename(.vtk)" << std::endl;
    return EXIT_FAILURE;
  }

  std::string filename = argv[1];

  // Read all the data from the file                                                                  
  vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New();
  reader->SetFileName(filename.c_str());
  reader->Update();

  // Visualize                                                                                        
  vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputConnection(reader->GetOutputPort());

  vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);

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

  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
  renderWindowInteractor->SetRenderWindow(renderWindow);

  renderer->AddActor(actor);
  renderer->SetBackground(.3, .6, .3); // Background color green                                      

  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

есть идеи, почему? Я видел в ParaView, что мне нужно было активировать режим «Объем», чтобы увидеть мою модель, здесь есть что-то похожее?

Последнее, что очень важно: можно ли изменить 3D-объем внутри файла .vtk? Например, если я хочу изменить цвет определенной части модели, предоставляет ли VTK инструменты, позволяющие это сделать?


person Charrette    schedule 24.03.2016    source источник


Ответы (1)


Здесь много вопросов! Вот несколько ответов.

Вот полный пример, который считывает все файлы DICOM в каталоге, создает объем, визуализирует его с помощью рендеринга объема и позволяет виджету блока интерактивно обрезать объем.

#include "vtkBoxRepresentation.h"
#include "vtkBoxWidget2.h"
#include "vtkCamera.h"
#include "vtkColorTransferFunction.h"
#include "vtkCommand.h"
#include "vtkDICOMImageReader.h"
#include "vtkGPUVolumeRaycastMapper.h"
#include "vtkImageData.h"
#include "vtkInteractorStyle.h"
#include "vtkInteractorStyleTrackballCamera.h"
#include "vtkMath.h"
#include "vtkPiecewiseFunction.h"
#include "vtkPlanes.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkVolume.h"
#include "vtkVolumeProperty.h"

// Box interaction callback
class vtkBoxCallback : public vtkCommand
{
public:
    static vtkBoxCallback *New(){ return new vtkBoxCallback; }
    vtkGPUVolumeRayCastMapper* m_mapper;
    vtkPlanes* m_planes;

    virtual void Execute( vtkObject* a_caller, unsigned long, void* ){
        vtkBoxWidget2* l_box_wdget = vtkBoxWidget2::SafeDownCast( a_caller );
        ( (vtkBoxRepresentation*)l_box_wdget->GetRepresentation() )->GetPlanes( m_planes );
        this->m_mapper->SetClippingPlanes( m_planes );
    }

    vtkBoxCallback(){}
};



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

    // Read volume
    vtkDICOMImageReader* l_reader = vtkDICOMImageReader::New();
    l_reader->SetDirectoryName( "C:/PathToDicomFiles/" );
    l_reader->Update();

    // Setup rendering stuff
    vtkRenderer* l_renderer = vtkRenderer::New();
    l_renderer->SetBackground( 0.3, 0.3, 0.3 );

    vtkRenderWindow* l_render_windows = vtkRenderWindow::New();
    l_render_windows->AddRenderer( l_renderer );
    l_render_windows->SetSize( 900, 900 );

    vtkInteractorStyleTrackballCamera* l_trackball = vtkInteractorStyleTrackballCamera::New();

    vtkRenderWindowInteractor* l_iren = vtkRenderWindowInteractor::New();
    l_iren->SetInteractorStyle( l_trackball );
    l_iren->SetRenderWindow( l_render_windows );
    l_iren->GetInteractorStyle()->SetDefaultRenderer( l_renderer );
    l_iren->SetDesiredUpdateRate( 15 );

    // Make sure we have an opengl context
    l_render_windows->Render();


    // Setup GPU volume raycast mapper
    vtkGPUVolumeRayCastMapper* l_gpu_mapper = vtkGPUVolumeRayCastMapper::New();
    l_gpu_mapper->SetInputConnection( l_reader->GetOutputPort() );

    // Setup Volume property
    // Window/Level
    double wl = 260;
    double ww = 270;

    // Color function
    vtkColorTransferFunction* l_color = vtkColorTransferFunction::New();
    l_color->SetColorSpaceToRGB();
    l_color->AddRGBPoint( wl - ww / 2, 0, 0, 0 );
    l_color->AddRGBPoint( wl - ww / 2 + 94 * ( ww / 255.0 ), 1., 21. / 255.0, 27. / 255.0 );
    l_color->AddRGBPoint( wl - ww / 2 + 147 * ( ww / 255.0 ), 1., 176. / 255.0, 9. / 255.0 );
    l_color->AddRGBPoint( wl - ww / 2 + 201 * ( ww / 255.0 ), 1., 241. / 255.0, 39. / 255.0 );
    l_color->AddRGBPoint( wl - ww / 2 + 255 * ( ww / 255.0 ), 1, 1, 1. );
    l_color->Build();

    // Opacity function
    vtkPiecewiseFunction* l_opacity = vtkPiecewiseFunction::New();
    l_opacity->AddPoint( wl - ww / 2, 0 );
    l_opacity->AddPoint( wl + ww / 2, 1 );

    // Volume property, light, shading
    vtkVolumeProperty* l_volume_property = vtkVolumeProperty::New();
    l_volume_property->SetColor( l_color );
    l_volume_property->SetScalarOpacity( l_opacity );
    l_volume_property->SetInterpolationTypeToLinear();
    l_volume_property->ShadeOn();
    l_volume_property->SetAmbient( 0.15 );
    l_volume_property->SetDiffuse( 0.8 );
    l_volume_property->SetSpecular( 0.25 );
    l_volume_property->SetSpecularPower( 40 );

    // Put everything together
    vtkVolume* l_volume = vtkVolume::New();
    l_volume->SetProperty( l_volume_property );
    l_volume->SetMapper( l_gpu_mapper );
    l_renderer->AddVolume( l_volume );
    l_renderer->ResetCamera();

    // setup Box interactive widget
    vtkBoxRepresentation* l_box_rep = vtkBoxRepresentation::New();
    l_box_rep->SetInsideOut( true );

    vtkBoxWidget2* l_voi_widget = vtkBoxWidget2::New();
    l_voi_widget->SetRepresentation( l_box_rep );
    l_voi_widget->SetInteractor( l_iren );
    l_voi_widget->GetRepresentation()->SetPlaceFactor( 1. );
    l_voi_widget->GetRepresentation()->PlaceWidget( l_reader->GetOutput()->GetBounds() );
    l_voi_widget->SetEnabled( true );

    vtkPlanes* l_planes = vtkPlanes::New();

    vtkBoxCallback* l_callback = vtkBoxCallback::New();
    l_callback->m_mapper = l_gpu_mapper;
    l_callback->m_planes = l_planes;
    l_voi_widget->AddObserver( vtkCommand::InteractionEvent, l_callback );

    // Go rendering !
    l_iren->Start();

    // Memory cleanup
    l_reader->Delete();
    l_renderer->Delete();
    l_render_windows->Delete();
    l_trackball->Delete();
    l_iren->Delete();
    l_gpu_mapper->Delete();
    l_color->Delete();
    l_opacity->Delete();
    l_volume_property->Delete();
    l_volume->Delete();
    l_voi_widget->Delete();
    l_planes->Delete();
    l_callback->Delete();
}

В качестве общего совета я предлагаю вам прочитать VTK примеры, которые должны помочь вам понять все возможности ВТК.

Надеюсь, это поможет :)

person Simon Esneault    schedule 24.03.2016
comment
Спасибо за ваш ответ, я думаю, вы сделали мой день :D У меня сейчас тысяча новых вопросов по этому поводу, но я сначала попытаюсь понять, как работает этот код :) Действительно, редактирование значения внутри модели пока не актуально , но мне просто нужно было знать, будет ли это возможно :) Еще раз спасибо! - person Charrette; 25.03.2016