wtorek, 27 października 2009

Sposób na przycinanie danych i szybką wizualizację objętościową w VTK

2 komentarze
Problem, który opisywałem jakiś czas temu we wpisie "Przycinanie danych do wizualizacji w VTK" (sekcja: vtkClipVolume), dotyczący zawężania pola widzenia w wizualizacji objętościowej można rozwiązać łatwiej aniżeli mogłoby się wydawać. Nie trzeba korzystać z wyrafinowanych metod dedykowanych w VTK do przycinania danych, tylko wystarczy nałożyć na obraz wcześniej przygotowaną maskę.

Przykład

W tym przykładzie zostanie pokazane jak w danych wyciąć kulę. Zadanie to będzie o tyle łatwe, ponieważ w VTK istnieje już klasa wspomagająca rysowane kuli na obrazie, dzięki czemu nie musimy przeprowadzać sami żadnych operacji na pikselach (w przypadku innych kształtów niestety będzie to konieczne). Następnie tworzymy obiekt reprezentujący maskę (vtkImageMask), do którego przekazujemy obraz wejściowy i właśnie przygotowany obraz z kulą. Możemy również ustalić jakie wartości mają zostać wstawione w miejsce wyciętej kuli. W naszym przypadku wstawiamy "zera".
set extent [[reader GetOutput] GetExtent]
vtkImageEllipsoidSource imageSphere
imageSphere SetWholeExtent 0 [lindex $extent 1] 0 [lindex $extent 3] 0 [lindex $extent 5]
imageSphere SetCenter 40 40 40
imageSphere SetRadius $radius $radius $radius

vtkImageMask mask
mask SetImageInput [reader GetOutput]
mask SetMaskInput [imageSphere GetOutput]
mask SetMaskedOutputValue 0 0 0
mask NotMaskOn
mask ReleaseDataFlagOff

Tak przygotowany obiekt mask wstawiamy do potoku przetwarzania tradycyjnej wizualizacji objętościowej. Wynik tego działania możemy zobaczyć poniżej:


Dużą zaletą tego podejścia jest to, że operacja przycinania danych jest wykonywana jednorazowo i w żaden sposób nie wpływa na szybkość renderowania wizualizacji.

poniedziałek, 26 października 2009

Generowanie profili dla wskazanej linii w VTK

7 komentarze
Wartość jednego punktu niewiele nam daje podczas analizy dużego zbioru danych (patrz wpis: "Interaktywne wyświetlanie wartości wskazanego woksela w VTK"). Dopiero możliwość odniesienia tej wartości względem wybranego otoczenia ułatwia nam wydawanie bardziej obiektywnych ocen. W analizie obrazu w tym celu zwykle korzysta się z dwóch technik: generowania profili i przeglądu histogramów. Profil jest niczym innym aniżeli wykresem obrazującym wartości poszczególnych pikseli wzdłuż zadanej linii obrazu (linia może mieć dowolny kąt). Natomiast histogram pokazuje ile jest pikseli danej wartości we wskazanym obszarze.

W przykładach VTK jest już gotowy skrypt do wyświetlania histogramów, ja natomiast pokażę jak zaprogramować generowanie profili.

Przykład

Aby program był jak najbardziej przyjazny dla użytkownika zostanie wprowadzona możliwość ręcznego określenia linii, wzdłuż której ma być wyświetlony profil. Najlepiej do tego celu użyć kontrolki graficznej typu vtkLineWidget. Pozwala ona wskazać punkty startowe linii w wygodny sposób w przestrzeni trójwymiarowej. Dodatkowo niezbędne będzie skorzystanie z kontrolki do rysowania wykresów 2D - vtkXYPlotActor. Każda z tych kontrolek zostanie umieszczona na na innej scenie renderowania. Dzięki temu cała wizualizacja będzie znacznie czytelniejsza.

vtkRenderer ren1
ren1 SetBackground 0.5 0.6 0.8
ren1 SetGradientBackground 0

vtkRenderer ren2
ren2 SetBackground 1.0 1.0 1.0
ren2 SetBackground2 0.9 0.9 0.9
ren2 SetGradientBackground 1

renWin AddRenderer ren1
renWin AddRenderer ren2

ren2 SetViewport 0.5 0 1 1
ren1 SetViewport 0 0 0.5 1

vtkLineWidget lineWidget
lineWidget SetCurrentRenderer ren1
lineWidget SetInteractor iren
lineWidget SetInput [reader GetOutput]
lineWidget SetAlignToYAxis
lineWidget SetResolution 100
lineWidget PlaceWidget
lineWidget AddObserver InteractionEvent PrepareProfile
lineWidget On

vtkPolyData poly
lineWidget GetPolyData poly
vtkProbeFilter probe
probe SetInput poly
probe SetSource [reader GetOutput]

vtkXYPlotActor profile
profile AddInput [probe GetOutput]
eval [profile GetPositionCoordinate] SetValue 0.05 0.05 0
eval [profile GetPosition2Coordinate] SetValue 0.95 0.95 0
profile SetXValuesToNormalizedArcLength
profile SetNumberOfXLabels 6
profile SetTitle "Profile Data "
profile SetXTitle "s"
profile SetYTitle "I(s)"
profile SetXRange 0 1
profile SetYRange 0 255
eval [profile GetProperty] SetColor 0 0 0
eval [profile GetProperty] SetLineWidth 2
profile SetLabelFormat "%g"

set tprop [profile GetTitleTextProperty]
$tprop SetColor 0.02 0.06 0.62
$tprop SetFontFamilyToArial

profile SetAxisTitleTextProperty $tprop
profile SetAxisLabelTextProperty $tprop
profile SetTitleTextProperty $tprop

ren2 AddActor2D profile

proc PrepareProfile {} {
lineWidget GetPolyData poly
}
Uwaga:
Po uruchomieniu skryptu w lewej części okna zobaczymy wizualizację danych z możliwością określenia punktów startowych linii. Obok natomiast jest wyświetlany profil.



Warto również przetestować skrypt do generowania histogramu, który znajduje się w przykładach VTK (plik: VTK/Examples/ImageProcessing/Tcl/Histogram.tcl). Jego działanie można obejrzeć na poniższym zrzucie ekranu:



Opisywane narzędzia w swoim działaniu są bardzo proste. Jednak możliwości jakie oferują są niezastąpione.

środa, 21 października 2009

Tworzenie zrzutów ekranu oraz filmów w VTK

0 komentarze
Zazwyczaj po zakończonej analizie danych wyniki są zapisywane, aby można było do nich wrócić później lub przesłać współpracownikom albo zleceniodawcom. Warto również zastanowić się jak można dodatkowo utrwalić powstałe przy okazji wizualizacje, by odbiorca dostał nie tylko liczby, ale również ich graficzną prezentację. Można oczywiście udostępnić odpowiedni program lub skrypt. Jednak problem pojawi się, gdy trzeba będzie zainstalować dodatkowe biblioteki lub obliczenia miałyby trwać długo. W takiej sytuacji lepiej przygotować zrzuty ekranu kluczowych fragmentów procesu obliczeniowego, lub nagrać film przedstawiający co się dzieje. VTK posiada wsparcie dla obu podejść, co zostanie opisane w tym wpisie.

Zmiana koloru powierzchni z wykorzystaniem tablic przeglądu LUT (ang. lookup table)

Zanim przejdziemy do właściwego tematu najpierw zostanie pokazane jak ustalać kolor konturu (wizualizacja powierzchniowa) z użyciem tablic LUT. Zabieg ten pozwala na łatwiejsze rozróżnianie różnych obiektów i zwalnia nas z samodzielnego definiowania poszczególnych kolorów.

#skala kolorów od niebieskiego do czerwonego
vtkLookupTable lut
lut SetHueRange 0.66667 0.0
lut SetSaturationRange 1 1
lut SetValueRange 1 1
lut SetAlphaRange 1 1
lut SetNumberOfColors 256
lut Build

#algorytm marching cube
vtkMarchingCubes iso
iso SetInput [reader GetOutput]
iso SetValue 0 127

#obiekt mapujący wyniki na płaszczyznę; tutaj możemy określić zmianę jej koloru
vtkPolyDataMapper mapper
mapper SetInput [iso GetOutput]
mapper ScalarVisibilityOn
mapper SetLookupTable lut
mapper SetScalarRange 0 255

vtkActor isoActor
isoActor SetMapper mapper
eval [isoActor GetProperty] SetOpacity 0.5

ren1 AddActor isoActor
Jak to działa w praktyce zostanie pokazane w następnych sekcjach.

Tworzenie zrzutów ekranu z okna renderowania

Oczywiście zrzuty ekranu można zrobić za pomocą standardowych metod z użyciem klawisza PrintScreen lub korzystając ze specjalnego programu służącego do tego celu. Niestety wymaga to dodatkowej pracy i musi być wykonywane ręcznie. W VTK mamy możliwość zautomatyzowania tej czynności stosując klasę vtkWindowToImageFilter, która pobiera zawartość okna renderowania i zamienia je na obraz. Później wystarczy tylko skorzystać z odpowiedniego obiektu zapisującego (w zależności od formatu), aby otrzymać plik we wskazanej lokalizacji.
vtkWindowToImageFilter w2if
w2if SetInput renWin
vtkPNGWriter writer
writer SetInputConnection [w2if GetOutputPort]
writer SetFileName "screenshot.png" $level]
renWin Render
writer Write

Zapis sekwencji obrazów do katalogu

Jeden zrzut ekranu często bywa niewystarczający, dlatego można zapisać całą sekwencję plików.
W tym przykładzie będzie zwiększana iteracyjnie wartość progowa dla algorytmu generującego kontur, a wynik za każdym razem będzie zapisywany na dysk. Dodatkowo na początku został utworzony obiekt wyświetlający tą wartość (vtkTextActor), aby łatwiej było analizować postęp działania algorytmu.
iren Start

vtkTextActor textActor
textActor SetDisplayPosition 70 20
eval [textActor GetTextProperty] SetJustificationToCentered
eval [textActor GetTextProperty] SetFontSize 18
ren1 AddActor textActor

vtkWindowToImageFilter w2if
w2if SetInput renWin
vtkPNGWriter writer
writer SetInputConnection [w2if GetOutputPort]

for {set level 0} {$level < 255 } {incr level} {
textActor SetInput "Iso value: $level"
iso SetValue 0 $level
renWin Render
writer SetFileName [format "output/animate-change_iso_contour%04d.png" $level]
w2if Modified
writer Write
}
Po zakończeniu działania tego skryptu w katalogu output powinno znaleźć się 255 plików. Niektóre z nich zostały przedstawione poniżej. W tym momencie można dokładniej zobaczyć jakie możliwości daje użycie tablic LUT - obiekty są automatycznie kolorowane.


Uwaga:
  • Powyższy rysunek nie został przygotowany za pomocą prezentowanego skryptu tylko z użyciem programu ImageMagick. Wydano polecenie:
    montage *.png -tile x1 -background '#796a9f' -geometry 150x150+5+5  out.bmp
  • Zrzuty oczywiście zapisane są w katalogu jako niezależne pliki.

Generowanie filmów z użyciem narzędzi ffmpeg oraz mencoder

Kiedy mamy już całą serię obrazów zapisaną w katalogu można na jej podstawie przygotować film. W Linuksie do najpopularniejszych narzędzi wspierających to zadanie można zaliczyć ffmpeg i mencoder (podobno są również ich odpowiedniki dla MS Windows). Pomimo tego, że są to programy działające z poziomu linii komend, to ich możliwości w wielu przypadkach przewyższają aplikacje okienkowe do edycji wideo.

Instalacja w Ubuntu sprowadza się do wydania następującego polecenia w okienku terminala:
sudo apt-get install ffmpeg mencoder
Przykład użycia ffmpeg:
ffmpeg -sameq -y -r 10 -i animate-change_iso_contour%04d.png -r 24 ff_out.mpg
Przykład użycia mencoder:
mencoder "mf://*.png" -mf fps=10 -o men_out.mpg -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2000
W obu przypadkach powstaje film wideo bardzo dobrej jakości zakodowany w formacie MPEG-4. Aby film nie przebiegał zbyt szybko w każdej sekundzie jest wyświetlane 10 klatek wejściowych, co daje w sumie 25 sekundowy utwór przy 255 plikach.

Tworzenie filmów z poziomu VTK

VTK
, tak jak pisałem na początku, również posiada wsparcie do tworzenia filmów. Mamy do dyspozycji następujące klasy:
  • vtkAVIWriter - tworzy pliki AVI; dostępny tylko dla Windows; nie testowałem,
  • vtkFFMPEGWriter - bazuje na bibliotekach wchodzących w skład ffmpeg; miałem problemy z kompilacją VTK ze wsparciem tej opcji,
  • vtkMPEG2Writer - zapisuje wideo z użyciem częściowo opatentowanego kodeka MPEG-2. Użycie tej opcji w własnych programach tylko na własne ryzyko. Kompilacja bez problemów.
Z powyższych metod udało mi się przetestować tylko tą ostatnią. Dobre wprowadzenie jak sobie poradzić z instalacją jest w dokumentacji VTK. Postaram się jednak opisać poszczególne etapy krok po kroku.
  1. W dziale Download na stronie VTK, szukamy sekcji "Download additional components",
  2. Pobieramy plik vtkmpeg2encode.tar.gz i rozpakowujemy go do dowolnego katalogu.
  3. Tworzymy katalog build, przechodzimy do niego i uruchamiamy kompilację:
    mkdir build && cd build && cmake ../ && make
  4. Przechodzimy do katalogu gdzie mamy skompilowane VTK i uruchamiamy graficzną nakładkę na CMake. Ustawiamy dodatkowe opcje:
    VTK_USE_MPEG2_ENCODER            ON
    vtkMPEG2Encode_INCLUDE_PATH /home/rafal/install/vtk/support/vtkmpeg2encode/;/home/rafal/install/vtk/support/vtkmpeg2encode/build/
    vtkMPEG2Encode_LIBRARIES /home/rafal/install/vtk/support/vtkmpeg2encode/build/libvtkMPEG2Encode.a
  5. Kompilujemy VTK.
Przykład użycia jest niemal identyczny z opisywanym wcześniej sposobem zapisu sekwencji plików do katalogu. Zamieniamy tylko obiekt vtkPNGWriter na vtkMPEG2Writer i zmieniamy nazwę pliku do wygenerowania. Warto zwrócić uwagę na różnice: 1) nie musimy każdorazowo ustawiać nazwy pliku, 2) mamy dodatkowe funkcje Start oraz End otwierające i zamykające plik wideo.
vtkWindowToImageFilter w2if
w2if SetInput renWin
vtkMPEG2Writer movie
movie SetInputConnection [w2if GetOutputPort]
movie SetFileName "output/animate-change_iso_contour.mpg"
movie Start

for {set level 0} {$level < 255 } {incr level} {
textActor SetInput "Iso value: $level"
iso SetValue 0 $level
renWin Render
w2if Modified
movie Write
}

movie End

Umieszczanie filmów na YouTube

Jeśli uda nam się przygotować ciekawe wizualizacje warto je przedstawić szerszej publiczności na jednym z portali hostujących pliki wideo. Do najpopularniejszych serwisów tego typu należy oczywiście YouTube. Portal ten pozwala na publikację filmów wysokiej rozdzielczości pod warunkiem, że zostaną one przygotowane w odpowiedni sposób. Opisze tylko najważniejsze kwestie z tym związane, a po szczegóły odsyłam do dokumentacji YouTube.

Optymalizacja filmów pod kątem wysokiej rozdzielczości YouTube:
  • Ustawiamy rozmiar obrazu na: 640-szerokość, 480-wysokość
    renWin SetSize 640 480
  • Jeśli korzystamy z gradientu tła najlepiej go wyłączyć. Podczas kompresji wideo mogły by się pojawić pasy.
    ren1 SetGradientBackground 0
  • Preferowanymi kodekami są: H.264, MPEG-2 lub MPEG-4. Opisywane uprzednio sposoby generowania filmów korzystają odpowiednio z MPEG-4 (ffmpeg, mencoder) oraz MPEG-2 (vtkMPEG2Writer).

Film przygotowany z użyciem omawianych wyżej technik wizualizacji i tworzenia wideo umieściłem na YouTube:



piątek, 16 października 2009

Interaktywne wyświetlanie wartości wskazanego woksela w VTK

0 komentarze
Nawet najlepsza wizualizacja danych może okazać się niewystarczająca kiedy potrzebujemy dokładniej zbadać szczegóły na obrazie. Celowy w takiej sytuacji może być powrót do danych pierwotnych i przegląd wartości poszczególnych punktów. Zadanie to oczywiście ma sens tylko wtedy, gdy potrafimy określić gdzie na obrazie znajduje się dany punkt, bo przecież patrząc na plik wypełniony liczbami tego nie widać. Najwygodniej byłoby wskazać konkretny punkt na wizualizacji i otrzymać jego wartość. Przykład jak to zrobić w VTK zostanie opisany w tym poście.

Przykład
Aby zrealizować wyżej postawione zadanie skorzystamy z kontrolki wizualnej vtkPointWidget oraz obiektu graficznego vtkTextActor. Reprezentują one odpowiednio punkt w przestrzeni, którym możemy poruszać oraz tekst wyświetlający zadane informacje na scenie wizualizacji. Oczywiście dla kontrolki punkt powinna zostać przygotowana funkcja obsługi zdarzenia zmiany współrzędnych. W takiej sytuacji następuje pobranie wartości wskazanego woksela i wpisanie jej do obiektu tekst.
vtkPointWidget pointWidget
pointWidget SetInteractor iren
pointWidget SetInput [reader GetOutput]
pointWidget AllOff
pointWidget PlaceWidget
pointWidget AddObserver InteractionEvent pickValueCallback
pointWidget On

vtkTextActor textActor
textActor SetDisplayPosition 100 20
eval [textActor GetTextProperty] SetJustificationToCentered
eval [textActor GetTextProperty] SetFontSize 18
ren1 AddActor textActor

proc pickValueCallback {} {
set pos [pointWidget GetPosition]
set x [expr int([lindex $pos 0]) ]
set y [expr int([lindex $pos 1]) ]
set z [expr int([lindex $pos 2]) ]
set value [[reader GetOutput] GetScalarComponentAsDouble $x $y $z 0 ]

textActor SetInput "($x, $y, $z): $value"
}

Możliwości przedstawionego przykładu można zobaczyć na poniższym obrazku:


Taki sposób wyświetlania wartości danego piksela jest na pewno zdecydowanie wygodniejszy od przeglądu poszczególnych punktów w pliku lub wypisywaniu ich w linii poleceń.

czwartek, 15 października 2009

Przycinanie danych do wizualizacji w VTK

0 komentarze
Wizualizując dane przestrzenne często nie wystarcza podgląd obiektów "z wierzchu", ale celowe może się okazać zajrzenie "do ich środka". W VTK mamy taką możliwość zarówno podczas wizualizacji powierzchniowej (surface rendering) jak i objętościowej (volume rendering) poprzez odpowiednie zdefiniowanie przeźroczystości. Jednak może się zdarzyć, że to również będzie za mało i będziemy potrzebować dokładniej podejrzeć szczegóły znajdujące się w konkretnym miejscu. Do tego celu służą różne techniki przycinania danych, które zostaną opisane w tym wpisie.

Przycinanie danych za pomocą vtkExtractVOI

Najłatwiejszym sposobem przycinania danych jest użycie do tego celu klasy vtkExtractVOI. Pozwala ona zawęzić pole widzenia (Volume of Interest - VOI) na każdej osi dla ściśle zadanych przedziałów. Aby z niej skorzystać, wystarczy umieścić ją w potoku zaraz po czytniku danych i określić zakres widoczności funkcją SetVOI. Można to zrobić statycznie wpisując konkretne wartości w programie, lub też dynamicznie za pomocą parametrów linii poleceń lub odpowiednich kontrolek graficznych.
vtkExtractVOI extract
extract SetInput [reader GetOutput]
extract SetVOI $xmin $xmax $ymin $ymax $zmin $zmax
Tą technikę można stosować zarówno w wizualizacji powierzchniowej i objętościowej.


ClippingPlanes

Innym sposobem jest użycie płaszczyzn cięcia reprezentowanych w VTK klasą vtkPlanes. W odróżnieniu od poprzedniego rozwiązania jest to podejście zdecydowanie bardziej elastyczne, ponieważ sami możemy określić liczbę takich płaszczyzn oraz ich kąt. W ten sposób możemy wyciąć dowolny fragment danych.

Użycie tej klasy sprowadza się do ustawienia płaszczyzn cięcia dla obiektów mapujących za pomocą funkcji SetClippingPlanes.

Przykład - vtkBoxWidget
Płaszczyzny cięcia możemy zdefiniować sami lub też możemy skorzystać z wygodnej kontrolki graficznej vtkBoxWidget.

Przykładowy kod tworzy kontrolkę na scenie wizualizacji podpina ją do danych wejściowych i ustawia funkcję obsługującą zdarzenia. Kod może zostać w całości wklejony na końcu prezentowanych już we wcześniejszych wpisach skryptów do wizualizacji powierzchniowej i objętościowej.
vtkBoxWidget boxWidget
boxWidget SetInteractor iren
boxWidget SetPlaceFactor 1.0
boxWidget SetInput [reader GetOutput]
boxWidget PlaceWidget
boxWidget InsideOutOn
boxWidget AddObserver InteractionEvent clipVolumeRenderCallback
boxWidget On

[boxWidget GetOutlineProperty] SetRepresentationToWireframe
[boxWidget GetOutlineProperty] SetAmbient 1.0
[boxWidget GetOutlineProperty] SetAmbientColor 1 1 1
[boxWidget GetOutlineProperty] SetLineWidth 1

[boxWidget GetSelectedOutlineProperty] SetRepresentationToWireframe
[boxWidget GetSelectedOutlineProperty] SetAmbient 1.0
[boxWidget GetSelectedOutlineProperty] SetAmbientColor 1 0 0
[boxWidget GetSelectedOutlineProperty] SetLineWidth 3

vtkPlanes planes
proc clipVolumeRenderCallback {} {
boxWidget GetPlanes planes;
isoMapper SetClippingPlanes planes;
}

Należy zwrócić uwagę, że pomiędzy skryptami jest pewna różnica w nazewnictwie zmiennych. Kod zadziała bez problemu w skrypcie powierzchniowym, natomiast w skrypcie objętościowym należy zmienić dwie linijki:
boxWidget SetInput [reader GetOutput]
isoMapper SetClippingPlanes planes;


Ze wszystkich omawianych w tym wpisie technik zalecam to podejście. Jest ono najszybsze i działa bez problemu dla obu rodzajów wizualizacji.

vtkClipVolume

Kolejną możliwością przycięcia danych jest użycie klasy vtkClipVolume. Jak sama nazwa wskazuje wydawać by się mogło, że to jest dedykowany sposób w VTK. Niestety użycie tej klasy wiąże się ze zmianą reprezentacji danych z structured points na unstructured grid. W przypadku wizualizacji powierzchniowej nie ma to większego znaczenia - wszystko zadziała poprawnie, natomiast w wizualizacji objętościowej pojawiają się problemy. Pierwszym z nich jest zmiana kodu. Dla obiektu mapującego należy skorzystać z klasy vtkUnstructuredGridVolumeRayCastMapper. Niby nie jest to wielki problem, jednak przygotowanie wizualizacji jest niezwykle wolne i zajmuje ogromną ilość pamięci. Dla porównania skrypt TCL używający tradycyjnego algorytmu dla przedstawianego modelu zęba (plik 1,5MB) korzysta z ok. 75 MB Ramu (wartość obejmuje nie tylko dane, ale również załadowane biblioteki), a w przypadku nowego obiektu mapującego jest to już ok. 1 800MB!. Inny problem to różnica w wyglądzie wizualizacji jaką dostajemy. Widać to na poniższym obrazku:


Jeżeli szczególnie zależy nam na przycinaniu danych w niestandardowy sposób - np. kulą, jak na powyższym obrazku, a nie mamy wystarczającej ilości ramu, aby poradzić sobie z opisywanymi problemami, możemy wyświetlić dane używając do tego celu znanego z wizualizacji powierzchniowej mapowania wielokątów (klasa vtkPolyDataMapper). Przykład poniżej.
#Prepare sphere
set radius 50
vtkSphere sphere
sphere SetRadius $radius
eval sphere SetCenter [[reader GetOutput] GetCenter]
vtkSphereSource spheres
spheres SetRadius $radius
eval spheres SetCenter [[reader GetOutput] GetCenter]
spheres SetThetaResolution 80
spheres SetPhiResolution 40
spheres SetRadius 2
vtkPolyDataMapper soutlineMapper
soutlineMapper SetInput [spheres GetOutput]
vtkActor soutlineActor
soutlineActor SetMapper soutlineMapper
soutlineActor VisibilityOn
eval [soutlineActor GetProperty] SetColor $antique_white
eval [soutlineActor GetProperty] SetOpacity 0.1
ren1 AddActor soutlineActor

# Generate tetrahedral mesh
vtkClipVolume clip
clip SetInputConnection [reader GetOutputPort]
clip SetClipFunction sphere
clip SetValue 0.0
clip GenerateClippedOutputOff
clip Mixed3DCellGenerationOff
clip InsideOutOn

vtkGeometryFilter gf
gf SetInputConnection [clip GetOutputPort]

vtkPolyDataMapper clipMapper
clipMapper SetInputConnection [gf GetOutputPort]
clipMapper ScalarVisibilityOn
eval clipMapper SetScalarRange 0 2

vtkActor clipActor
clipActor SetMapper clipMapper


Wynik tej operacji jest następujący:


Użycie vtkClipVolume rodzi wiele problemów, ale wydaje się być to jedyna możliwość przycinania danych w niestandardowy sposób na potrzeby wizualizacji objętościowej.

vtkClipPolyData

Ostatnią opisywaną techniką zawężania danych do wizualizacji jest użycie klasy vtkClipPolyData. To podejście dotyczy tylko obiektów reprezentowanych za pomocą wielokątów (polygonal data) i jest zazwyczaj stosowane w wizualizacji powierzchniowej. Jego użycie sprowadza się do przygotowania płaszczyzny obiektu, stworzenia obiektu vtkClipPolyData i przekazanie do niego za pomocą funkcji SetClipFunction obiektu tnącego (np. kuli).


vtkMarchingCubes iso1
iso1 SetInput [reader GetOutput]
iso1 SetValue 0 $isoLevel1

# implicit function for clipping
set radius 43
vtkSphere sphere
sphere SetRadius $radius
eval sphere SetCenter [[reader GetOutput] GetCenter]
vtkClipPolyData clipper
clipper SetInput [iso1 GetOutput]
clipper SetClipFunction sphere
clipper GenerateClipScalarsOn
clipper SetValue 0.0
vtkPolyDataMapper clipMapper
clipMapper SetInput [clipper GetOutput]
clipMapper ScalarVisibilityOff
vtkActor iso1Actor
iso1Actor SetMapper clipMapper


Zaprezentowany kod został użyty do przygotowania poniższej wizualizacji:

Użycie tej techniki przycinania danych jest wskazane jeśli interesuje nas w danym momencie wizualizacja powierzchniowa. Nie ingerujemy w żaden sposób w dane, dlatego możemy stworzyć dowolną ilość obiektów i każdy może zostać przycięty inaczej.

Podsumowanie

Opisane sposoby zawężania pola wizualizacji mogą okazać się niezwykle przydatne jeśli interesują nas wybrane fragmenty obrazu, a nie możemy ich dostrzec ponieważ są zasłonięte przez inne obiekty. Przycinając dane na różne sposoby możemy wyłowić każdy szczegół i dokładnie go przeanalizować.

piątek, 9 października 2009

Sterowanie parametrami renderowania VTK za pomocą wbudowanych kontrolek

0 komentarze
Aby nasze programy lub skrypty mogły być stosowane dla różnych danych wejściowych warto zaprogramować możliwość ich definiowania. Można to zrobić za pomocą parametrów przekazywanych podczas startu aplikacji, lub też w trakcie jej działania. Pierwsze podejście jest zalecane do określania pliku z danymi, natomiast drugie dla dostrajania parametrów wyświetlania. Najlepiej oczywiście jeżeli zostaną przygotowane kontrolki graficzne, które pozwolą łatwo zmieniać te parametry. VTK nie jest ściśle związane z żadną biblioteką GUI (chociaż pozwala na łatwą integrację), ale dostarcza własny zestaw kontrolek OpenGL (więcej informacji na stronie WIKI projektu i w dziale z przykładami).

W dzisiejszym wpisie zostanie pokazane jak zmienić przykład "Generowanie powierzchni z wykorzystaniem algorytmu Marching Cube w VTK" tak, aby był bardziej interakcyjny i pozwalał na zmianę parametrów w trakcie wykonania programu.

Przykład
W tym przykładzie zostaną użyte dwie kontrolki typu suwak. Jedna do zmiany wartości progowej dla konturu, a druga do zmiany stopnia przezroczystości. W tym celu skorzystamy z następujących klas:
  • vtkSliderRepresentation2D - definiuje parametry wyświetlania komponentu,
  • vtkSliderWidget - odpowiada za narysowanie obiektu suwak na scenie.
Dodatkowo należy przygotować funkcje uruchamiane w momencie zmiany wartości poszczególnych suwaków.

Podany kod źródłowy można przetestować dodając go na końcu skryptu z poprzedniego wpisu.
vtkSliderRepresentation2D sliderIsoValueRep
sliderIsoValueRep SetValue 127
sliderIsoValueRep SetMinimumValue 0
sliderIsoValueRep SetMaximumValue 255
sliderIsoValueRep SetTitleText "Iso Contour Value"
eval [sliderIsoValueRep GetPoint1Coordinate] SetCoordinateSystemToNormalizedDisplay
eval [sliderIsoValueRep GetPoint1Coordinate] SetValue 0.2 0.2
eval [sliderIsoValueRep GetPoint2Coordinate] SetCoordinateSystemToNormalizedDisplay
eval [sliderIsoValueRep GetPoint2Coordinate] SetValue 0.8 0.2
sliderIsoValueRep SetSliderLength 0.02
sliderIsoValueRep SetSliderWidth 0.03
sliderIsoValueRep SetEndCapLength 0.01
sliderIsoValueRep SetEndCapWidth 0.03
sliderIsoValueRep SetTubeWidth 0.005

vtkSliderRepresentation2D sliderOpacityRep
sliderOpacityRep SetValue 0.5
sliderOpacityRep SetMinimumValue 0
sliderOpacityRep SetMaximumValue 1
sliderOpacityRep SetTitleText "Opacity Value"
eval [sliderOpacityRep GetPoint1Coordinate] SetCoordinateSystemToNormalizedDisplay
eval [sliderOpacityRep GetPoint1Coordinate] SetValue 0.2 0.1
eval [sliderOpacityRep GetPoint2Coordinate] SetCoordinateSystemToNormalizedDisplay
eval [sliderOpacityRep GetPoint2Coordinate] SetValue 0.8 0.1
sliderOpacityRep SetSliderLength 0.02
sliderOpacityRep SetSliderWidth 0.03
sliderOpacityRep SetEndCapLength 0.01
sliderOpacityRep SetEndCapWidth 0.03
sliderOpacityRep SetTubeWidth 0.005

vtkSliderWidget sliderIsoValueWidget
sliderIsoValueWidget SetInteractor iren
sliderIsoValueWidget SetRepresentation sliderIsoValueRep
sliderIsoValueWidget SetAnimationModeToAnimate
sliderIsoValueWidget AddObserver InteractionEvent changeIsoValueCallback
sliderIsoValueWidget On

vtkSliderWidget sliderOpacityWidget
sliderOpacityWidget SetInteractor iren
sliderOpacityWidget SetRepresentation sliderOpacityRep
sliderOpacityWidget SetAnimationModeToAnimate
sliderOpacityWidget AddObserver InteractionEvent changeOpacityCallback
sliderOpacityWidget On

proc changeIsoValueCallback {} {
iso SetValue 0 [sliderIsoValueRep GetValue]
}
proc changeOpacityCallback {} {
eval [isoActor GetProperty] SetOpacity [sliderOpacityRep GetValue]
}

Wyniki działania programu dla różnych wartości konturu można prześledzić na poniższej animacji:

Wykorzystanie graficznych kontrolek w VTK może znacznie ułatwić poszukiwanie odpowiednich parametrów wizualizacji, a sama aplikacja jest zdecydowanie łatwiejsza w obsłudze dla typowego użytkownika.

środa, 7 października 2009

Generowanie powierzchni z wykorzystaniem algorytmu Marching Cube w VTK

0 komentarze
Kolejnym sposobem - po wizualizacji objętościowej (ang. volume rendering) - renderowania danych przestrzennych jest technika generowania powierzchni (ang. surface rendering) z wykorzystaniem algorytmu Marching Cubes. Pozwala ona na wyświetlanie konturu wybranych obiektów i tworzenie dla nich dyskretnych modeli 3D. Obiekty te są reprezentowane za pomocą siatek wypełnionych trójkątami. Otrzymujemy w ten sposób model powierzchniowy obiektu, dla którego możemy dodatkowo zdefiniować stopień przeźroczystości i kolor.

Przykład
Użycie algorytmu Marching Cubes do generowania konturu w VTK jest niezwykle proste. Po odczytaniu danych z pliku wystarczy przekazać je do obiektu vtkMarchingCubes i zdefiniować wartość progową dla obiektu.

package require vtk

set inputFileName [ lindex $argv 0]
set isoLevel [expr [ lindex $argv 1] ]
set opacity [expr [ lindex $argv 2] ]
set color "0.9804 0.9216 0.8431"

vtkStructuredPointsReader reader
reader SetFileName $inputFileName
reader Update

vtkRenderer ren1
vtkRenderWindow renWin
renWin AddRenderer ren1
vtkRenderWindowInteractor iren
iren SetRenderWindow renWin

vtkMarchingCubes iso
iso SetInput [reader GetOutput]
iso SetValue 0 $isoLevel

vtkPolyDataMapper isoMapper
isoMapper SetInput [iso GetOutput]
isoMapper ScalarVisibilityOff

vtkActor isoActor
isoActor SetMapper isoMapper
eval [isoActor GetProperty] SetColor $color
eval [isoActor GetProperty] SetOpacity $opacity

ren1 AddActor isoActor
ren1 SetBackground 0.5 0.6 0.8
ren1 SetGradientBackground 4
renWin SetSize 500 500

iren Initialize
wm withdraw .

Powyższy skrypt zawiera obsługę parametrów wejściowych. Dla przykładowych danych (tooth.vtk) wywołanie może wyglądać w następujący sposób:
tclsh vtk-iso_contour.tcl data/tooth.vtk 128 0.5


Analizując przykład, polecam zrobić eksperymenty na własnych danych zmieniając wartość konturu, kolor i przeźroczystość. Rezultaty jakie w ten sposób możemy uzyskać mogą być naprawdę różne, co widać już po samej zmianie stopnia przeźroczystości:


Możliwości VTK w zakresie generowania konturu nie kończą się na wyświetlaniu tylko jednej powierzchni, ale możemy zdefiniować sobie ich dowolną ilość. Może to być szczególnie przydatne np. w zastosowaniach klinicznych, gdzie każdy organ może zostać osobno wyświetlony.

Wadą techniki surface rendering, o której trzeba na koniec wspomnieć, jest jej wysokie zapotrzebowanie na moc obliczeniową i pamięć operacyjną. Może się okazać, że przy bardziej złożonych obiektach czas oczekiwania będzie na tyle długi, że warto będzie rozważyć skorzystanie z wizualizacji objętościowej.

wtorek, 6 października 2009

Wizualizacja objętościowa w VTK

0 komentarze
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.

Jak skompilować InsightToolkit ze źródeł i podłączyć do TCLa i Pythona?

0 komentarze
Podobnie jak w przypadku VTK instalacja InsightToolkit w Ubuntu 9.04 sprowadza się do wpisania w terminalu następującego polecenia:
sudo apt-get install insighttoolkit3-examples libinsighttoolkit3-dev libinsighttoolkit3.10 tcl8.4-insighttoolkit3 python-insighttoolkit3

Podobnie również tutaj, występuje problem z dostępem do najnowszej wersji biblioteki (wersja w repozytorium na dzień dzisiejszy - 6 paź '09 - to 3.10, a na stronie projektu jest już dostępna wersja 3.16). Dlatego jeśli zależy nam na najświeższej wersji, możemy ją sami przygotować kompilując bibliotekę ze źródeł.

Ze strony ITK, z działu Download pobieramy następujące pliki: InsightToolkit-3.16.0.tar.gz, InsightApplications-3.16.0.tar.gz, CableSwig-ITK-3.16.0.tar.gz, lub ich nowsze wersje. Po ich rozpakowaniu do wcześniej przygotowanego katalogu, najpierw skompilujemy CableSwig - pakiet używany do opakowania (ang. wrapping) kodu C++ do innych języków programowania. Nie wymaga on ustawiania żadnych niestandardowych opcji kompilacji, dlatego po przejściu do katalogu CableSwig-ITK-3.16.0 wystarczy wpisać następującą sekwencję poleceń:
mkdir build && cd build && cmake ../ && make

Następnie przechodzimy do katalogu InsightToolkit-3.16.0, zakładamy katalog build i po przejściu do niego uruchamiamy graficzną nakładkę na CMake:
mkdir build && cd build && cmake-gui ../

W kolejnym kroku ustawiamy odpowiednie opcje kompilacji. Poniższa propozycja umożliwi połączenie ITK z językami skryptowymi TCL i Python.
BUILD_EXAMPLES                 OFF
BUILD_SHARED_LIBS ON
BUILD_TESTING OFF
CMAKE_BUILD_TYPE Release
CMAKE_INSTALL_PREFIX /opt
CableSwig_DIR /home/rafal/install/itk/CableSwig-ITK-3.16.0/build
ITK_USE_REVIEW ON
ITK_USE_PATENTED ON
ITK_USE_REVIEW_STATISTICS OFF
USE_WRAP_ITK ON
INSTALL_WRAP_ITK_COMPATIBILITY ON
WRAP_ITK_JAVA OFF
WRAP_ITK_PYTHON ON
WRAP_ITK_TCL ON

Uruchamiamy kompilację i instalujemy bibliotekę:
make
sudo make install

Uwagi odnośnie kompilacji:
  • Liczba przykładów i testów w ITK jest ogromna. Warto zatem je wyłączyć (opcje: BUILD_EXAMPLES i BUILD_TESTING) przy pierwszej kompilacji, bo w przeciwnym wypadku kompilacja może potrwać nawet kilka godzin. Jeśli proces kompilacji zakończy się poprawnie, kompilację przykładów polecam włączyć w wolnym czasie, np. w nocy.
  • Opcje BUILD_SHARED_LIBS i ITK_USE_REVIEW są wymagane po włączeniu opcji USE_WRAP_ITK.
  • W wersji ITK 3.16, którą testowałem, włączenie opcji ITK_USE_REVIEW_STATISTICS i USE_WRAP_ITK spowodowało błędy w kompilacji. Dlatego jeśli nam bardziej zależy na połączeniu z językami skryptowymi, polecam wyłączenie testowego modułu statystyk.

Jak połączyć ITK i Python?

Ustawiamy zmienną środowiskową PYTHONPATH na odpowiedni katalog:
export PYTHONPATH=/opt/lib/python2.6/site-packages

Jak podłączyć ITK i TCL?

Ustawiamy następujące zmienne systemowe:
export TCLLIBPATH=/opt/lib/InsightToolkit/WrapITK/Tcl
export LD_LIBRARY_PATH=/opt/lib/InsightToolkit

Testujemy połączenie z TCL:
tclsh
%puts $auto_path
%package require InsightToolkit
3.16.0

Automatyczne podłączenie TCL i Python przy starcie systemu
Aby nie ustawiać ręcznie zmiennych systemowych po każdym włączeniu komputera, możemy je dopisać do pliku ~/.bashrc, a system sam zrobi to za nas.
Poniżej przykład wpisu uwzględniający również VTK:
nano ~/.bashrc

export TCLLIBPATH="/opt/lib/vtk-5.4 /opt/lib/InsightToolkit/WrapITK/Tcl"
export LD_LIBRARY_PATH=/opt/lib/vtk-5.4:/opt/lib/InsightToolkit
export PYTHONPATH=/opt/lib/python2.6/site-packages

Instalacja ITK Application

Pakiet InsightToolkit sam w sobie zawiera tylko proste przykłady pokazujące jak pracować z biblioteką. Zbiór bardziej zaawansowanych przykładów jest dostępny w pakiecie InsightApplication (opis tych programów jest dostępny na stronie projektu, w dziale Applications).

Zdecydowana większość aplikacji korzysta z biblioteki FLTK do obsługi GUI. Możemy ją zainstalować następującym poleceniem:
sudo apt-get install libfltk1.1 libfltk1.1-dev fluid fltk1.1-doc

Następnie uruchamiamy CMake i ustawiamy, które aplikacje powinny zostać przygotowane. Ja wybrałem zdecydowaną większość z nich, z wyłączeniem wtyczek do Volview (pobierając Volview wtyczki są już skompilowane).
BUILD_SHARED_LIBS        OFF
BUILD_TESTING OFF
CMAKE_BUILD_TYPE Release
CMAKE_INSTALL_PREFIX /opt
ITK_DIR /opt/lib/InsightToolkit
USE_FLTK ON
USE_VTK ON
VTK_DIR /opt/lib/vtk-5.4
USE_VolviewPlugins OFF
USE_AUXILIARY ON


Instalacja biblioteki InsightToolkit ze źródeł daje nam pewność, że korzystamy z jej najnowszej wersji, a możliwość wyboru parametrów kompilacji pozwala na dopasowanie jej do aktualnych potrzeb.

poniedziałek, 5 października 2009

Jak skompilować VTK ze źródeł i podłączyć do TCLa i Pythona?

0 komentarze
W Ubuntu 9.04, bo tego systemu będzie dotyczył ten wpis, VTK można łatwo zainstalować z repozytorium wydając następujące polecenie w konsoli:
sudo apt-get install libvtk5 libvtk5-dev libvtk5-qt4 libvtk5-qt4-dev tk8.4-dev vtkdata vtk-doc vtk-examples vtk-tcl python-vtk

Dostaniemy w ten sposób nie tylko biblioteki i pliki nagłówkowe VTK, ale również całą dokumentację, przykłady oraz dane testowe. Dodatkowo zostanie skonfigurowane połączenie z językami skryptowymi TCL i Python. Ten sposób instalacji w zdecydowanej większości przypadków powinien być wystarczający do pracy z tą biblioteką. Jednak co w przypadku jeśli potrzebujemy najnowszej wersji biblioteki (w chwili pisania tego wpisu w repozytorium była wersja 5.0.4, a na stronie oficjalnej wersja 5.4.2) lub niestandardowych parametrów pracy. Wtedy najlepiej samemu skompilować VTK ze źródeł.

Źródła VTK pobieramy ze strony oficjalnej projektu, z działu Download. Pobieramy również przykładowe dane. Po rozpakowaniu obu archiwów w wcześniej przygotowanym katalogu, przechodzimy do katalogu ze źródłami, tworzymy tam katalog build i przechodzimy do niego. Następnie uruchamiamy graficzny interfejs CMake i wybieramy opcje kompilacji (moja propozycja znajduje się poniżej):
mkdir build && cd build && cmake-gui ../

BUILD_EXAMPLES           ON
BUILD_SHARED_LIBS ON
BUILD_TESTING ON
CMAKE_BUILD_TYPE Release
CMAKE_INSTALL_PREFIX /opt
VTK_DATA_ROOT /home/rafal/install/vtk/VTKData5.4.2/Data
VTK_USE_PARALLEL ON
VTK_USE_GUISUPPORT ON
VTK_USE_QVTK ON
DESIRED_QT_VERSION 4
VTK_WRAP_JAVA OFF
VTK_WRAP_PYTHON ON
VTK_WRAP_TCL ON

Po wygenerowaniu plików kompilacji w konsoli uruchamiamy program make i możemy spokojnie pójść na kawę:) - kompilacja może potrwać nawet pół godziny.
make
sudo make install
Komenda make install zainstaluje nam niezbędne pliki w katalogu /opt.

Uwagi po kompilacji:
  • Dodatkowe biblioteki znalazły się również w katalogu /opt/lib/python2.6/site-packages/vtk/. Można je przekopiować do katalogu /opt/lib/vtk-5.4/. Operacja ta może w przyszłości ułatwić kompilację innych pakietów zależnych od VTK, np. InsightApplication.
    sudo cp /opt/lib/python2.6/site-packages/vtk/lib* /opt/lib/vtk-5.4/


Jak połączyć VTK i Python?
Wystarczy ustawić zmienną systemową PYTHONPATH na odpowiedni katalog:
export PYTHONPATH=/opt/lib/python2.6/site-packages


Jak podłączyć VTK i TCL?
Tutaj podobnie, należy ustawić odpowiednie zmienne systemowe:
export TCLLIBPATH=/opt/lib/vtk-5.4
export LD_LIBRARY_PATH=/opt/lib/vtk-5.4

Testujemy połączenie z TCL:
tclsh
%puts $auto_path
%package require vtk
5.4


Automatyczne podłączenie TCL i Python przy starcie systemu
Dopisujemy do pliku ~/.bashrc wcześniej opisywane zmienne:
nano ~/.bashrc

export PYTHONPATH=/opt/lib/python2.6/site-packages
export TCLLIBPATH=/opt/lib/vtk-5.4
export LD_LIBRARY_PATH=/opt/lib/vtk-5.4


Jak podłączyć się do przykładowych danych (VTK Data)?
Jeśli korzystamy ze ściągniętych danych przykładowych (VTK Data) i rozpakowaliśmy je do własnego katalogu, skrypty TCL mogą ich nie widzieć nawet jeśli ustawimy zmienne systemowe w bashu. Musimy w takim wypadku dopisać odpowiednią zmienną systemową w pliku /etc/environment:
sudo nano /etc/environment

VTK_DATA_ROOT="/home/rafal/install/vtk/VTKData5.4.2"


Jak przetestować czy wszystko działa poprawnie?

Najlepiej skorzystać z przykładów dołączonych do VTK. W katalogu Examples/Tutorial znajdują się proste przykłady zaimplementowane w kilku językach programowania.