poniedziałek, 26 października 2009

Generowanie profili dla wskazanej linii w VTK

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.

7 komentarze:

Lukasz pisze...

Mój Mistrzu, powiedz mi proszę jak usunąć trwale z renderera widgety, tzn. nie poprzez wciśnięcie i?

Przykład: Usuwam aktora i chcę usunąć np. jego boxwidget

Metoda Delete nie usuwa trwale widgetu.

Rafał Petryniak pisze...

Delete to już ostateczność - włącza destruktora, który powinien usunąć obiekt z pamięci. Przynajmniej w C++. Dlaczego nie działa, to nie wiem, ale tej metody nie polecam uruchamiać w środku programu, tylko na jego końcu.

Ja zazwyczaj stosuję metodę Off() dla widgetów. Np. dla widgetu wyświetlającego "plasterek obrazka" działa to mniej więcej tak:
1. utworzenie:
planeWidgetX = vtkImagePlaneWidget::New();
... (ustawiamy parametry)
2. podpinamy się pod interaktor:
planeWidgetX->SetInteractor( iren);
3. korzystamy ...
4. jeśli nie chcemy, aby był dłużej był wyświetlany można go wyłączyć poleceniem:
planeWidgetX->Off();

Lukasz pisze...

Wielkie Dzięki za błyskawiczną pomoc!
Chodziło mi dokładnie o usunięcie obserwatora interaktora czyli widgetu,a nie tylko schowanie go, ponieważ przy zastosowaniu off po wciśnięciu "i" znowu się pojawia.
Musiałem mieć coś zle.
Off w połączeniu z Delete działa doskonale.

Rafał Petryniak pisze...

Cieszę się, że mogłem pomóc. Słaba pogoda w Krakowie zmusiła mnie do spędzenia przedpołudnia przy komputerze :)

Lukasz pisze...

Mistrzu, małe pytanko odnośnie formatu vtk structured points.
Jaką petla można opisać dane w pliku vtk structured points?

Posiadam dane w stylu fortranowskim
opisane petla

for z in Z:
for y in Y;
for x in X:
print wartosc_funkcji(x,y,z)
print "/n"
i nie jestem w stanie ich poprawnie wyswietlic, tzn, nie to co potrzeba otrzymuje (poszatkwany volume)

Lukasz pisze...

Jeszcze raz petle zamieszczam, bo widze ,ze nie uznalo spacji

for z in Z{
for y in Y{
for x in X{
print wartosc_funkcji(x,y,z)}
print "/n"
}
}

Rafał Petryniak pisze...

No cóż Wodzu ;) nie wiele będę mógł Ci pomóc. Najlepiej jakbyś podesłał mi te dane, lub program do ich generowania to mógłbym zobaczyć co da się zrobić.
Ja np. korzystam z danych, które zapisuje w sposób binarny i dodaje nagłówek tego typu:
tooth.nhdr
BINARY
DATASET STRUCTURED_POINTS
DIMENSIONS 103 94 161
SPACING 1.0 1.0 1.0
ORIGIN 0.0 0.0 0.0
POINT_DATA 1558802
SCALARS volume_scalars unsigned_char 1
LOOKUP_TABLE default

(fragment wycięty z pliku: http://riad.pk.edu.pl/~rpetryniak/website_resources/share/data/tooth.vtk).

Jak widać po tym przykładzie, to jest tutaj ustawiony typ danych na "unsigned_char" i tak właśnie trzeba dane zapisać w programie, który ma generować te pliki.

Polecam również zapoznać się z klasą "vtkImageToStructuredPoints".

I jeszcze jedno: zapis "print "/n"" nie wydaje mi się poprawny. Nową linię formatujemy slashem.

Pozdrawiam,
Rafał

Prześlij komentarz