wtorek, 6 października 2009

Wizualizacja objętościowa w VTK

Dłuższy czas temu (rok 2007) napisałem na tym blogu wpis związany z wizualizacją medyczną. Dzisiaj nie będę powtarzał tych samych informacji, tylko skupię się na tym, jak można wyrenderować serię obrazów (np. z badania tomograficznego) w VTK za pomocą techniki Volume Rendering. Co najważniejsze, technika ta nie dość, że daje bardzo dobre rezultaty - co zobaczymy później na przykładzie - to działa nadzwyczaj sprawnie. Implementacja dostępna w VTK potrafi skorzystać z kilku rdzeni dostępnych w naszym procesorze, a podczas obrotów lub skalowania automatycznie zmniejsza rozdzielczość.

Najważniejsze klasy:
Przed rozpoczęciem analizowania przykładu warto najpierw zapoznać się z najważniejszymi klasami, z których będziemy korzystać:
  • vtkPiecewiseFunction - klasa umożliwia definiowanie funkcji przeźroczystości dla danych,
  • vtkColorTransferFunction - pozwala na definiowanie skali kolorów dla odpowiednich wartości,
  • vtkVolumeProperty - zbiera wszystkie informacje dotyczące parametrów wyświetlania danych (funkcje koloru i przeźroczystości, sposób cieniowania i interpolacji, i wiele innych),
  • vtkVolume - reprezentuje dane i właściwości ich wyświetlania, odpowiada za sterowanie pozycją i orientacją na scenie renderowania,
  • vtkVolumeRayCastCompositeFunction i vtkVolumeRayCastMapper zawierają algorytmy, które na podstawie informacji zawartych w vtkVolumeProperty wiedzą jak zamienić obiekt 3D na obraz płaski, który w rzeczywistości widzimy na ekranie.
Przykład:
Poniżej znajduje się prosty skrypt TCL, który pokazuje jak wyrenderować serię zdjęć przedstawiających zęba za pomocą techniki Volume Rendering.
Przykładowe dane zostały zaczerpnięte z pakietu SciRun i przekonwertowane do formatu VTK Structured Points. Można je pobrać z następującej lokalizacji: link.
package require vtk
package require vtkinteraction

# Create the reader for the data
vtkStructuredPointsReader reader
reader SetFileName "data/tooth.vtk"
reader Update

vtkImageCast cast
cast SetInput [reader GetOutput]
cast SetOutputScalarTypeToUnsignedShort
cast ClampOverflowOn

# Create transfer mapping scalar value to opacity
vtkPiecewiseFunction opacityTransferFunction
opacityTransferFunction AddPoint 0.0 0.0
opacityTransferFunction AddPoint 90.0 0.0
opacityTransferFunction AddPoint 137.9 0.119
opacityTransferFunction AddPoint 255.0 0.2

# Create transfer mapping scalar value to color
vtkColorTransferFunction colorTransferFunction
colorTransferFunction AddRGBPoint 0.0 0.0 0.0 1.0
colorTransferFunction AddRGBPoint 120.0 1.0 1.0 1.0
colorTransferFunction AddRGBPoint 160.0 1.0 1.0 0.0
colorTransferFunction AddRGBPoint 200.0 1.0 0.0 0.0
colorTransferFunction AddRGBPoint 255.0 0.0 1.0 1.0

# Create transfer mapping scalar value to opacity based on gradient magnitude
vtkPiecewiseFunction gradientTransferFunction
gradientTransferFunction AddPoint 0.0 0
gradientTransferFunction AddPoint 2.5 0
gradientTransferFunction AddPoint 12.7 1
gradientTransferFunction AddPoint 255.0 1

# The property describes how the data will look
vtkVolumeProperty volumeProperty
volumeProperty SetColor colorTransferFunction
volumeProperty SetScalarOpacity opacityTransferFunction
volumeProperty SetGradientOpacity gradientTransferFunction
#volumeProperty ShadeOn
volumeProperty SetInterpolationTypeToLinear

# The mapper / ray cast function know how to render the data
vtkVolumeRayCastCompositeFunction compositeFunction
vtkVolumeRayCastMapper volumeMapper
volumeMapper SetVolumeRayCastFunction compositeFunction
volumeMapper SetInputConnection [cast GetOutputPort]

# The volume holds the mapper and the property and
# can be used to position/orient the volume
vtkVolume volume
volume SetMapper volumeMapper
volume SetProperty volumeProperty

vtkRenderer ren1
ren1 SetBackground 0.5 0.6 0.8
ren1 SetGradientBackground 4
vtkRenderWindow renWin
renWin AddRenderer ren1
renWin SetSize 600 600
vtkRenderWindowInteractor iren
iren SetRenderWindow renWin

ren1 AddVolume volume
renWin Render

iren AddObserver UserEvent {wm deiconify .vtkInteract}
iren Initialize

wm withdraw .


Przykład ten został uruchomiony dwa razy - z wyłączoną i włączoną opcją przeźroczystości generowanej na podstawie gradientu (linijka: volumeProperty SetGradientOpacity gradientTransferFunction). W pierwszym przypadku widzimy struktury odsłonięte za pomocą funkcji opacityTransferFunction, natomiast w drugim przypadku możemy również zajrzeć do wnętrza tych struktur.



Przedstawiony przykład korzysta z bardzo prostego modelu, co wcale nie oznacza, że technika Volume Rendering nadaje się tylko to tego typu zastosowań. Jest ona często wykorzystywana (razem z samym VTK) w zastosowaniach klinicznych, gdzie mamy zdecydowanie więcej danych i często potrzebujemy skupić się na konkretnych tkankach lub organach. Ten sposób oceny obrazu daje zdecydowanie lepszy pogląd analizowanego obiektu badań, aniżeli przeglądanie dziesiątek, a nawet setek skanów 2D.

0 komentarze:

Prześlij komentarz