poniedziałek, 21 grudnia 2009

Instalacja bazy danych Oracle 11g w Ubuntu 9.04

21 komentarze
Postanowiłem rozszerzyć tematykę bloga o inne zainteresowania nie związane przetwarzaniem i wizualizacją obrazów medycznych. W niedługim czasie pojawi się więcej wpisów dotyczących baz danych, programowania oraz obliczeń równoległych. Mam nadzieje, że dzięki temu blog stanie się ciekawszy dla szerszego grona odbiorców.

Na początek opiszę proces instalacji pełnej wersji bazy danych Oracle 11g Release 2 w systemie Ubuntu Linux 9.04 32-bit. Instalacja nie jest bardzo złożona, ale pewne fragmenty mogą być problematyczne dla osób, które nie miały nigdy do czynienia z tą bazą danych.

Proces instalacji został zaplanowany tak, aby poznać jak najwięcej narzędzi konfiguracyjnych i dokładnie prześledzić co się dzieje w systemie.

Uwaga:
Użytkowników, którzy nie chcą instalować pełnej wersji bazy Oracle może zainteresować jej okrojona wersja: Oracle Database 10g Express Edition. Nie dość, że istnieje dedykowany instalator dla Debiana/Ubuntu, to dodatkowo może być ona używana do zastosowań komercyjnych.

Podczas przygotowania tego wpisu szczególnie przydatne okazały się następujące strony:


Przygotowanie systemu do instalacji bazy



Instalator Oracle niestety nie jest przystosowany dla Ubuntu, dlatego niektóre kroki będą miały na celu upodobnienie tego systemu do RedHata.

Poniższe kroki wykonujemy na koncie administratora.
  • Instalacja niezbędnych pakietów:
    Instalator może wymagać dodatkowych pakietów do zainstalowania:
    apt-get update && sudo apt-get dist-upgrade
    apt-get install gcc make binutils lesstif2 rpm libmotif3 libaio1 gawk alien ksh
  • Utworzenie linków symbolicznych:
    Instalator Oracle używa pełnych ścieżek niektórych programów systemowych, dlatego należy upewnić się, że znajdują się one w odpowiednim miejscu:
    ln -s /usr/bin/awk /bin/awk
    ln -s /usr/bin/rpm /bin/rpm
    ln -s /usr/bin/basename /bin/basename

    mkdir /etc/rc.d
    for i in 0 1 2 3 4 5 6 S ; do ln -s /etc/rc$i.d /etc/rc.d/rc$i.d ; done
  • Ustawienie powłoki skryptowej:
    Instalator Oracle zdecydowanie bardziej preferuje bash'a aniżeli dash'a:
    cd /bin
    ls -l /bin/sh

    lrwxrwxrwx 1 root root 4 2009-04-23 14:05 /bin/sh -> dash

    ln -sf /bin/bash /bin/sh
    ls -l /bin/sh

    lrwxrwxrwx 1 root root 9 2009-12-15 19:12 /bin/sh -> /bin/bash
  • Utworzenie odpowiednich użytkowników i grup:
    Aby Ubuntu z punktu widzenia instalatora przypominał RedHata dodajemy odpowiednie grupy i użytkownika oracle:
    addgroup oinstall
    addgroup dba
    addgroup nobody
    usermod -g nobody nobody
    useradd -g oinstall -G dba -p password -d /home/oracle -s /bin/bash oracle

    mkdir /home/oracle
    chown -R oracle:dba /home/oracle
  • Przygotowanie katalogów:
    mkdir -p /u01/app/oracle
    chown -R oracle:dba /u01
  • Modyfikujemy ustawienia /etc/security/limits.conf:
    cd /etc/security/
    cp limits.conf limits.conf.original
    nano limits.conf

    Dodajemy poniższe linie na końcu pliku:
    oracle soft nproc 2047
    oracle hard nproc 16383
    oracle soft nofile 1023
    oracle hard nofile 65535

  • Modyfikujemy ustawienia /etc/sysctl.conf
    cd /etc
    cp sysctl.conf sysctl.conf.original
    nano sysctl.conf

    Dodajemy poniższe linie na końcu pliku:
    fs.file-max = 65535
    kernel.shmall = 2097152
    kernel.shmmax = 2147483648
    kernel.shmmni = 4096
    kernel.sem = 250 32000 100 128
    net.ipv4.ip_local_port_range = 1024 65535
    net.core.rmem_default = 4194304
    net.core.rmem_max = 4194304
    net.core.wmem_default = 262144
    net.core.wmem_max = 262144

    Przeładowanie pliku konfiguracyjnego:
    sysctl -p
  • Restart komputera
    Aby mieć pewność, że wszystkie ustawienia zostały poprawnie zatwierdzone w systemie restartujemy komputer (tak przynajmniej zalecały wszystkie poradniki instalacji, z których korzystałem).


Pobranie i instalacja oprogramowania



Pobranie i rozpakowanie instalatora
Te czynności możemy wykonywać jako zwyczajny użytkownik, na którym pracujemy na co dzień

Uruchomienie instalatora
  • Instalację należy przeprowadzić jako użytkownik oracle z prawami administratora:
    xhost +
    sudo -s
    su - oracle

  • Będzie nam potrzebny tryb graficzny:
    DISPLAY=:0.0; export DISPLAY
    xhost local:oracle

  • Przejście do katalogu z rozpakowanym instalatorem:
    cd /sciezka/do/instalatora/database/

  • Uruchomienie instalatora:

    ./runInstaller

    Starting Oracle Universal Installer...

    Checking Temp space: must be greater than 80 MB. Actual 11002 MB Passed
    Checking swap space: must be greater than 150 MB. Actual 4024 MB Passed
    Checking monitor: must be configured to display at least 256 colors. Actual 16777216 Passed
    Preparing to launch Oracle Universal Installer from /tmp/OraInstall2009-12-15_12-36-28PM. Please wait ...



Opcje instalacji

Poniżej zostały wyróżnione niestandardowe opcje, które polecam zaznaczyć. Pozostałe opcje należy zostawić tak jak zaproponuje instalator.
  • step2: Install database software only
  • step5: Enterprise Edition (3,95BG)
  • step8: Zaznaczamy opcję „Ignore All”

Czynności po instalacji

W ostatnim etapie instalacji jesteśmy proszeni o wykonanie podanego skryptu jako użytkownik root:
/u01/app/oracle/product/11.2.0/dbhome_1/root.sh


Powinniśmy dostać mniej więcej taki komunikat:
Running Oracle 11g root.sh script...

The following environment variables are set as:
ORACLE_OWNER= oracle
ORACLE_HOME= /u01/app/oracle/product/11.2.0/dbhome_1

Enter the full pathname of the local bin directory: [/usr/local/bin]:
Copying dbhome to /usr/local/bin ...
Copying oraenv to /usr/local/bin ...
Copying coraenv to /usr/local/bin ...


Creating /etc/oratab file...
Entries will be added to the /etc/oratab file as needed by
Database Configuration Assistant when a database is created
Finished running generic part of root.sh script.
Now product-specific root actions will be performed.
Finished product-specific root actions.


Instalacja listenera


Poniższe czynności wykonujemy jako użytkownik oracle.
  • Ustawiamy zmienne systemowe:
    export ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1
    export PATH=$PATH:$ORACLE_HOME/bin

  • Uruchamiamy program:
    netca

Dalej postępujemy według zaleceń instalatora - nie zmieniamy żadnych opcji.


Instalacja bazy danych



Uruchamiamy program:
dbca

i na poszczególnych etapach instalacji wybieramy następujące opcje:
  • step4: Odznaczamy „Configure Enterprise Manager”
  • step4: Odznaczamy „Enable automatic maintenance tasks”
  • step5: Zaznaczamy „Use the Same Administrative Password for All Accounts”
  • step7: Wyłączamy „Specify Flash Recovery Area”
  • step8: „Sample schemas”
  • step9 - Memory: Pamięć ustawiamy na 250MB, Wyłączamy opcję „Use Automatic Memory Management”
  • step9 - Sizing: Processes: 30
  • step9 - Character Sets: „Use Unicode”

Komentarz: Powyższe opcje to tylko propozycja - można zostawić domyślne lub wybrać własne. Te opcje zostały ustawione według zaleceń na stronie: Installing Oracle 11gR1 on Ubuntu 9.04 Jaunty Jackalope | The Pythian Blog.

Manualny start bazy danych



Po zrestartowaniu komputera wszelkie próby połączenia się z bazą okażą się daremne - baza nie jest uruchomiona. Aby ją włączyć wykonujemy następujące czynności:

  • Logujemy się jako sysdba:
    sqlplus '/as sysdba'

    SQL*Plus: Release 11.2.0.1.0 Production on Tue Dec 22 20:41:21 2009

    Copyright (c) 1982, 2009, Oracle. All rights reserved.

    Connected to an idle instance.

  • Uruchamiamy instancję bez montowania bazy:
    startup nomount;

    ORACLE instance started.

    Total System Global Area 196681728 bytes
    Fixed Size 1335444 bytes
    Variable Size 71307116 bytes
    Database Buffers 117440512 bytes
    Redo Buffers 6598656 bytes

    Sprawdzamy stan:
    select status from v$instance;

    STATUS
    ------------
    STARTED

  • Montujemy bazę:
    alter database mount;

    Baza danych zostala zmieniona.

    Sprawdzamy stan:
    select status from v$instance;

    STATUS
    ------------
    MOUNTED

  • Otwieramy bazę:
    alter database open;

    Baza danych zostala zmieniona.

    Sprawdzamy stan:
    select status from v$instance;

    STATUS
    ------------
    OPEN


Aby wyłączyć instancję wraz z bazą danych wpisujemy:
shutdown immediate;

Baza danych zostala zamknieta.
Baza danych zostala zdemontowana.
Instancja ORACLE zostala zamknieta.



Automatyczny start bazy danych przy starcie systemu



Wygodniejszym od każdorazowego ręcznego włączania bazy może być takie jej skonfigurowanie, aby startowała razem z systemem. W tym celu
  • Logujemy się na konto administratora:
    sudo -s

  • Edytujemy ostatnią linijkę w pliku /etc/oratab, zamieniając literkę N na Y:
    nano /etc/oratab

    ORCL:/u01/app/oracle/product/11.2.0/dbhome_1:Y

  • Tworzymy następujący plik i zapisujemy do niego poniższą zawartość:
    nano /etc/init.d/oracledb

    #!/bin/bash
    #
    # /etc/init.d/oracledb
    #
    # Run-level Startup script for the Oracle Listener and Instances
    # It relies on the information on /etc/oratab

    # these are the paths for our base installation
    export ORACLE_BASE=/u01/app/oracle
    export ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1
    export ORACLE_OWNR=oracle
    export PATH=$PATH:$ORACLE_HOME/bin

    if [ ! -f $ORACLE_HOME/bin/dbstart -o ! -d $ORACLE_HOME ]
    then
    echo "Oracle startup: cannot start"
    exit 1
    fi

    case "$1" in
    start)
    # Oracle listener and instance startup
    echo -n "Starting Oracle: "
    su $ORACLE_OWNR -c "$ORACLE_HOME/bin/lsnrctl start"
    su $ORACLE_OWNR -c "$ORACLE_HOME/bin/dbstart $ORACLE_HOME"
    touch /var/lock/oracle
    echo "OK"
    ;;
    stop)
    # Oracle listener and instance shutdown
    echo -n "Shutdown Oracle: "
    su $ORACLE_OWNR -c "$ORACLE_HOME/bin/lsnrctl stop"
    su $ORACLE_OWNR -c "$ORACLE_HOME/bin/dbshut $ORACLE_HOME"
    rm -f /var/lock/oracle
    echo "OK"
    ;;
    reload|restart)
    $0 stop
    $0 start
    ;;
    *)
    echo "Usage: `basename $0` start|stop|restart|reload"
    exit 1
    esac

    exit 0

  • Przydzielamy prawa do wykonywania dla tego pliku:
    chmod a+x /etc/init.d/oracledb

  • Uaktualniamy skrypty startowe:
    update-rc.d oracledb defaults

  • Restartujemy komputer. Baza powinna uruchomić się automatycznie.


Testy


Wszystkie czynności przeprowadzamy na własnym koncie.

Testujemy połączenie z bazą danych
Dodajemy użytkownika, na którym pracujemy do grupy dba:
sudo usermod -G dba -a rafal


Ustawiamy niezbędne zmienne środowiskowe:
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1
export PATH=$PATH:$ORACLE_HOME/bin
export ORACLE_SID=ORCL

Łączymy się z bazą:
sqlplus '/as sysdba'

i wydajemy polecenie:
SELECT INSTANCE_NAME, VERSION, STATUS FROM V$INSTANCE;

INSTANCE_NAME    VERSION           STATUS
---------------- ----------------- ------------
ORCL 11.2.0.1.0 OPEN


Odblokowujemy użytkownika Scott
Warto odblokować przykładowego użytkownika Scott i na nim wykonać kilka testów:
sqlplus '/as sysdba'

ALTER USER scott ACCOUNT UNLOCK;

sqlplus scott/tiger

select * from emp;


Enterprise Manager


Enterprise Manager jest narzędziem służącym do diagnozowania i administracji bazą danych Oracle. Można go skonfigurować na dwa sposoby: 1) w kreatorze instalacji bazy danych lub 2) manualnie.

Manualna konfiguracja:
Ustawiamy zmienne systemowe ORACLE_SID i ORACLE_HOME, a następnie uruchamiamy polecenie tworzące repozytorium EM:
cd $ORACLE_HOME/bin
emca -config dbcontrol db -repos create
Jeśli wszystko przebiegnie bez problemów możemy przejść na stronę: https://[host]:1158/em/ (np. https://laptop:1158/em/). Ja niestety dostałem błąd:

INFO: Creating the EM repository (this may take a while) ...
2009-12-17 16:55:07 oracle.sysman.emcp.EMReposConfig invoke
SEVERE: Error creating the repository

Jak sobie poradzić z błędami? Ja musiałem wykonać kilka czynności:
  • Najpierw należało odblokować użytkowników DBSNMP i SYSMAN:
    sqlplus '/as sysdba'

    ALTER USER DBSNMP ACCOUNT UNLOCK;
    ALTER USER SYSMAN ACCOUNT UNLOCK;

  • Usunąć użytkownika MGMT_VIEW:
    drop user MGMT_VIEW;

  • Zwiększyć liczbę procesów dla Oracle:
    show parameter processes
    alter system set processes=100 scope=spfile;

    Po tej operacji niezbędny jest restart bazy danych:
    shutdown immediate
    startup

  • Oraz ponownie utworzyć repozytorium:
    emca -config dbcontrol db -repos recreate


Po tych czynnościach konfiguracja zakończyła się poprawnie. Problemy prawdopodobnie wynikały z przyjętych ustawień w trakcie tworzenia bazy danych (zablokowani użytkownicy, za mała liczba procesów).

Uruchomienie Managera:
Po restarcie komputera Enterprise Manager jest wyłączony. Aby go uruchomić logujemy się na konto oracle ustawiamy zmienne środowiskowe jak powyżej i wydajemy polecenie:
emctl start dbconsole


Manualnie Managera wyłączamy poleceniem:
emctl stop dbconsole


Komentarz:
  • Z niewiadomych mi powodów Enterprise Manager nie chce u mnie działać w Firefoksie - wyświetlana jest biała strona.
  • Działa za to bez problemu w Google Chrome.


Oracle SQL Develpoer



Do codziennej pracy warto również zainstalować edytor SQL. Do najbardziej zalecanych dla Ubuntu można zaliczyć TOra (niestety miałem problemy z instalacją) oraz Oracle SQL Develpoer, którego instalacja zostanie opisana.
  • Pobieramy wersję instalacyjną ze strony: http://www.oracle.com/technology/products/database/sql_developer/index.html.
  • Jest to wersja RPM dlatego będziemy musieli przekonwertować ją do formatu DEB zrozumiałego dla Ubuntu. Instalujemy w tym celu narzędzie alien:
    sudo apt-get install alien

  • Konwertujemy pakiet RPM na DEB:
    sudo alien -k --scripts sqldeveloper*.rpm

  • i instalujemy go w systemie:
    sudo dpkg -i sqldeveloper*.deb

  • Jeśli dostaniemy komunikat:
    Oracle SQL Developer
    Copyright (c) 1997, 2009, Oracle and/or its affiliates.All rights reserved.

    Type the full pathname of a J2SE installation (or Ctrl-C to quit), the path will be stored in ~/.sqldeveloper/jdk

  • Wykonujemy następujące polecenia:
    mkdir -p ~/.sqldeveloper
    touch ~/.sqldeveloper/jdk
    echo "/usr/lib/jvm/java-6-sun" >> ~/.sqldeveloper/jdk

niedziela, 13 grudnia 2009

MedicalVolumeRenderer - aplikacja testowa do wizualizacji objętościowej

2 komentarze
Pełny kod źródłowy
Ostatnim programem - przynajmniej jak na razie, który przygotowałem do demonstracji biblioteki KWWidgets jest MedicalVolumeRenderer. Jego głównym zadaniem jest interaktywne ustawianie parametrów wizualizacji objętościowej, o której pisałem w notatce: Wizualizacja objętościowa w VTK.

Budowa programu

MedicalVolumeRenderer ma podobną budowę jak programy opisywane ostatnio (MedicalContourMaker i MedicalSlicer). Główne okno programu jest zarządzane przez klasę vtkKWWindow. To ona zajmuje się obsługą menu, panelu bocznego oraz obszaru renderowania. Z nowych kontrolek, które pojawiły się w tym programie na szczególną uwagę zasługuje volumePropertyWidget widoczna na panelu jako Volume Apperance Settings. Po utworzeniu tej kontrolki przekazujemy do niej obiekt klasy vtkVolumeProperty. W ten sposób mamy dostęp do aktualnych parametrów renderowania obiektu i możemy je oczywiście dowolnie zmieniać. Interfejs graficzny kontrolki jest widoczny na poniższych zrzutach ekranu:





Warto również wspomnieć o kontrolce vtkKWColorPresetMenu widocznej na panelu jako Color Presets. Definiuje ona szereg zestawów kolorów, które mogą być ustawiane na poprzedniej kontrolce w sekcji Scalar Color Mapping.



Możliwości
  • Definiowanie skali kolorów dla odpowiednich wartości.
  • Ustawianie przezroczystości.
  • Kilkanaście predefiniowanych zestawów kolorów.
  • Nagrywanie animacji dla pola renderowania.
Przykładowe wizualizacje można obejrzeć poniżej:



Podsumowanie

Pomimo tego, że te same rezultaty można osiągnąć samemu programując ustawienia opcji renderowania (klasa: vtkVolumeProperty), to wygoda jaką dają nam dostępne w KWWidgets kontrolki może bardzo ułatwić przygotowanie profesjonalnego narzędzia do wizualizacji medycznej.

Kody źródłowe oraz wersję dla Windows można pobrać ze strony: link.

wtorek, 8 grudnia 2009

MedicalContourMaker - aplikacja testowa do generowania konturu

0 komentarze
Pełny kod źródłowy
Następnym programem po MedicalSlicer, który przygotowałem w celu prezentacji możliwości biblioteki KWWidgets jest MedicalContourMaker. Przykład ten umożliwia tworzenie wizualizacji powierzchniowej dla wczytanych danych 3D (więcej na ten temat można przeczytać w notatce: Generowanie powierzchni z wykorzystaniem algorytmu Marching Cube w VTK).



Budowa programu

Szkielet programu jest niemal identyczny ze szkieletem MedicalSlicer, zatem nie będę go ponownie szczegółowo opisywał. Z dodatkowych kontrolek, które tutaj się pojawiły są vtkKWChangeColorButton - do zmiany koloru (widoczny na rysunku poniżej), oraz vtkKWSurfaceMaterialPropertyWidget - do zmiany sposobu wyświetlania powierzchni konturu.



Możliwości
  • Zmiana wartości progowej dla algorytmu Marching Cube (suwak: Iso Level).
  • Zmiana przeźroczystości (suwak: Opacity) oraz koloru (przycisk Set Color) powierzchni konturu.



  • Zmiana parametrów materiału pokrywającego powierzchnię konturu:



Podsumowanie

Pomimo tego, że jest to bardzo prosty program, to posiada całkiem spore możliwości w zakresie ustalania parametrów wyświetlania konturu. Wystarczyłoby dodać do niego funkcję wyświetlania kilku konturów na raz, a powstałaby dosyć sprawna aplikacja do wizualizacji medycznej.

Kody źródłowe oraz wersję dla Windows można pobrać ze strony: link.

niedziela, 6 grudnia 2009

MedicalSlicer - aplikacja testowa do przeglądania zdjęć medycznych

0 komentarze
Pełny kod źródłowy
Pierwszą aplikacją prezentującą możliwości biblioteki do tworzenia interfejsu KWWidgets jest program o roboczej nazwie MedicalSlicer. Pomimo tego, że jego główną rolą jest pokazanie jak łączyć tą bibliotekę z VTK, to jest to w pełni funkcjonalny program do przeglądania medycznych zdjęć 3D.

Budowa programu

Szkielet aplikacji obsługuje klasa vtkKWWindow, która tworzy główne okno programu i zarządza kontrolkami w nim umieszczonymi. Jedną z ważniejszych kontrolek jest vtkKWRenderWidget posiadająca cechy znanych z VTK klas: vtkRenderer, vtkRenderWindow. Na obrazku poniżej jest to oczywiście pole renderowania widoczne po prawej stronie. Płaszczyzny obrazu, które na nim widzimy zostały uzyskane za pomocą obiektów vtkImagePlaneWidget (opis możliwości poniżej). Z lewej strony mamy przewijaną ramkę vtkKWFrameWithScrollbar, na której zostały umieszczone kolejne komponenty: vtkKWScaleWithEntry (suwak do wyboru wartości z zadanego zakresu) oraz vtkKWRadioButton (przycisk opcji). Interesującym komponentem widocznym na samym końcu ("Movie Creator") jest vtkKWSimpleAnimationWidget. Pozwala on na łatwe tworzenie animacji z pola renderowania dla ustalonych wartości obrotu i skalowania. Animacja jest zapisywana na dysk w postaci serii plików png, i później może zostać zamieniona na film np. za pomocą programu ffmpeg lub mencoder (jak to zrobić pisałem w notatce "Tworzenie zrzutów ekranu oraz filmów w VTK").



Możliwości
  • Program pozwala na przeglądanie danych medycznych jednocześnie w trzech różnych płaszczyznach: X, Y i Z. "Plasterki" (ang. slices) możemy przewijać wciśniętym przyciskiem rolki na myszce.
  • Lewy przycisk myszy służy do sprawdzania wartości danego piksela.
  • Prawy do zmiany ustawień okna oraz poziomu wyświetlania.
  • Dodatkowo możliwe jest obracanie i zmienianie kąta nachylenia każdej płaszczyzny.

  • Na panelu opcji, w ramce Lut Table można wybrać skalę kolorów w jakiej będą widoczne dane.


Podsumowanie

Pewną niedogodnością prezentowanego programu MedicalSlicer może być brak obsługi formatu DICOM. Istnieją jednak narzędzia do konwersji tego formatu do formatu VTK Structured Point, który jest obsługiwany przez program. Ja osobiście polecam ImageJ oraz plugin 3D Toolkit.

Kody źródłowe programu oraz wersję skompilowaną dla Windows można pobrać ze mojej anglojęzycznej strony www. Przygotowanie wersji binarnej dla innych systemów nie powinno być problematyczne, ponieważ wszystkie narzędzia są niezależne od systemu oraz dołączyłem plik kompilacji CMake.

piątek, 27 listopada 2009

Kontrolki KWWidgets do współpracy z VTK

0 komentarze
W kilku poprzednich artykułach dotyczących VTK posługiwałem się wbudowanymi kontrolkami graficznymi, aby praca z programami była bardziej przyjazna dla użytkownika. Niestety pomimo zalet tych kontrolek, mogą one być umieszczane tylko na scenie renderowania, co uniemożliwia przygotowanie tradycyjnego programu okienkowego. Dodatkowo brakuje wielu kontrolek, które są dostępne w innych bibliotekach GUI. Można oczywiście korzystać z zewnętrznych bibliotek takich jak Qt, GTK+, WxWidgets i innych, które pozwalają uniknąć opisywanych powyżej problemów, ale też nie są to rozwiązania idealne.

Najlepszym rozwiązaniem do współpracy z VTK wydaje się biblioteka KWWidgets (strona WWW projektu). Została ona opracowana przez firmę Kitware rozwijającą właśnie VTK, która korzysta z niej we własnych, komercyjnych aplikacjach (m.in. VolView). Wielką zaletą tej biblioteki są dodatkowe, niestandardowe komponenty GUI specjalnie dedykowane do obsługi wizualizacji tworzonych w VTK.

W kolejnych artykułach postaram się zaprezentować jej możliwości na konkretnych przykładach.

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.