Metody diagnostyczne/programowanie

Z Brain-wiki

Podręcznik do języka skryptowego ImageJ

Programowanie w ImageJ

Zadanie 1

Mamy obraz rtg płuc w formacie jpg, w 8-bitowej skali szarości. Zauważyliśmy, że punkty tła mają wartość mniejszą niż 10. Chcielibyśmy na tej podstawie ustalić, jaki procent na obrazie stanowi tło. W tym celu sprawdzamy po kolei wszystkie punkty obrazu i jeśli któregoś wartość jest mniejsza niż wartość graniczna, zliczamy go.

Zadanie 2

Mamy obraz w formacie dicom przedstawiający jedną warstwę CT (można wybrać dowolny z obrazów, na których pracowaliśmy na zajęciach). Chcielibyśmy sprawdzić, gdzie na tym obrazie znajduje się najjaśniejszy obszar. Moglibyśmy zrobić to tak, że podzielilibyśmy obraz na 10x10=100 mniejszych obrazków, w każdym z nich sprawdzilibyśmy sumę wartości wszystkich punktów i wskazalibyśmy współrzędne obrazka o największej wartości sumy. Na koniec wybrana część obrazka powinna zostać zaznaczona.

Hint: Należy zrobić pętlę, w której 100 razy zaznaczy się coraz to inny obszar, sprawdzi się sumę w nim i czy jest większa niż największa dotąd znaleziona wartość, a jeśli tak, to nową wartość zapamięta wraz z jej współrzędnymi. Pamiętaj: komendy w ImageJ kończy się zawsze średnikiem, a komentarze zaczyna się //

open(path)
Otwiera obraz o tytule podanym w ścieżce.

makeRectangle(x, y, width, height)
Zaznacza obszar prostokątny o lewym górnym rogu w punkcie x,y, szerokości width i wysokości height. Np.: 
makeRectangle(10,10,50,50);

getStatistics(area, mean, min, max, std, histogram)
Wywołanie tego polecenia spowoduje, że w zmiennej mean zostanie zapisana średnia wartość pikseli w zaznaczeniu.

getWidth()
Zwraca szerokość obrazu w pikselach. Np.: 
szer=getWidth();

getHeight()
Zwraca wysokość obrazu w pikselach.

getPixel(x, y)
Zwraca wartość piksela o współrzędnych (x,y).

floor(x) 
Zwraca wartość x zaokrągloną w dół. Np. 
n=floor(128/10); //zwróci wartość 12.

print(args)
Wypisuje wyliczoną wartość lub wartości. Np. jeśli wartość n to 5, wówczas
print(Wynik , n); //wypisze Wynik=5

Przykład pętli iterującej n od 0 do 5:
for (n=0; n<=5; n++) {
  print n; //lista komend
}

Przykład instrukcji warunkowej:
if (n<100) {
	print n;
}

Zadanie 3

Chcemy podzielić obraz na kwadraty o boku n pikseli i w każdym z nich znaleźć średnią wartość gradientu. Gradient to wektor o dwóch współrzędnych. Pierwsza współrzędna może być oszacowana jako różnica między wartością danego piksela a piksela po lewej stronie od niego, druga jako różnica wartości danego piksela i piksela ponad nim. Wynik obliczeń ma zostać przedstawiony jako osobny obraz, na którym w każdym kwadracie zostanie wyrysowany odcinek o długości n i nachyleniu zgodnym z gradientem. Wartość gradientu może zostać zobrazowana jasnością lub jeszcze lepiej kolorem odcinka.

Przydadzą się do tego następujące komendy:

a=newArray(n); //tworzy jednowymiarową tablicę o długości n
//W ImageJ nie istnieją tablice wielowymiarowe. 
//Ale tablicy 1-D można użyć jako 2-D odpowiednio adresując jej komórki. 
//Np. gdybyśmy chcieli mieć tablicę o wymiarach nx na ny, stworzylibyśmy ją:
tabl=newArray(nx*ny);
//Wypisanie wartości elementu tablicy o współrzędnych i, j wykonalibyśmy: 
print (tabl[i+ny*j]);

//Nowy obraz tworzy się:
newImage(tytul, typ, szerokosc, wysokosc, grubosc);
//Typ to może być np. "8-bit". "8-bit black" oznacza, że na początku piksele wszystkie będą czarne.

setPixel(x,y,100); //ustawianie wartości piksela o współrzędnych (x, y) na 100
drawLine(x1, y1, x2, y2); //Rysowanie linii między punktami o współrzędnych (x1, y1) i (x2, y2)

Rozmiar kwadratu można wpisać do programu "na siłę". Ale można by też poprosić użytkownika, aby go podał. ImageJ ma do tego bardzo miłe narzędzia do tworzenia okienek dialogowych. Poniżej przykład, który możesz skopiować i uruchomić, a następnie wykorzystać do ulepszenia Twojego skryptu do liczenia gradientów.

//Proste pytanie o jedną liczbę:
n=getNumber("Ile masz lat?", 18); //drugi parametr to domyślna odpowiedź
print("Dowiedziałem się, że masz "+n+" lat");

//Tak definiuje się i wyświetla bardziej zaawansowane okienko:
Dialog.create("Przedstaw się, proszę!");
//pole liczbowe:
Dialog.addNumber("Rok urodzenia", 1985); //Drugi parametr to domyślna wartość pojawiająca się w okienku
Dialog.addNumber("Miesiąc", 1);
Dialog.addNumber("Dzień", 1);
//pole tekstowe
Dialog.addString("Twoje imię:", "Hermenegilda"); //Drugi parametr to domyślny tekst
Dialog.show();

//a tak odczytuje się wpisane przez użytkownika wartości:
rok=Dialog.getNumber(); //odczytuje wartość kolejnego pola liczbowego
mies=Dialog.getNumber();
dzien=Dialog.getNumber();
imie=Dialog.getString(); //odczytuje tekst z kolejnego pola tekstowego

print("Twoje imie to "+imie+", a data urodzenia to "+dzien+"."+mies+"."+rok);

Zadanie 4

  • Otwórz wszystkie pliki z rozszerzeniem .jpg w wybranym katalogu i zapisz w formacie .png.
  • Wyświetl dla każdego z otwartych plików średnią wartość jasności pikseli.
katalog=getDirectory("Wybierz katalog"); //otwiera okienko do wyboru katalogu
tabl=getFileList(katalog); //tworzy tablicę zawierającą wszystkie nazwy plików w danym katalogu
l1=lengthOf(tabl); //zwraca długość tablicy
l2=lengthOf(tabl[3]); //zwraca długość tekstu będącego czwartym elementem tablicy
saveAs("PNG", "nowy_plik.png"); //zapisuje otwarty obraz w formacie .png, pod zadanym tytułem
endsWith("ala ma kota", "kota"); //zwraca true, jeśli pierwszy tekst kończy się drugim tekstem
substring("ala ma kota", 4, 6); //zwraca "ma", czyli część tekstu między pierwszym indeksem a drugim indeksem, bez tego ostatniego

Zadanie 5

Wczytaj plik flashpad-hand-clinical.jpg. Możesz zmniejszyć jego wielkość tak, by usunąć niepotrzebne czarne tło zaznaczając prostokąt z ręką i wybierając Image > Crop.

Naszym zadaniem będzie napisać algorytm, który znajdzie i zaznaczy automatycznie na tym obrazie granice między kośćmi palców. Dla oka to łatwe, ale jak wytłumaczyć komputerowi co widzi oko? Otóż tu kłania się nam czystej wody algorytmika (plus trochę wiedzy o analizie obrazu).

Proszę spojrzeć na poniższy obraz. Prawda, że granice między kostkami mają charakterystyczne kształty? Udało się je zaznaczyć (trochę za dużo, skrypt należałoby jeszcze dopracować).

Szukacz1.PNG

  • Zamiana obrazu na format 32-bit
  • Normalizacja obrazu do wartości od -1 do 1 za pomocą funkcji sigmoidalnej:
[math]S(t) = \frac{2}{1 + e^{-k(t-t_0)}}-1[/math]

Gdzie k to stała mówiąca o nachyleniu funkcji w zerze, a t_0 to wartość środkowa (np. średnia wartość pikseli na obszarze zdjęcia ręki).

  • Splot z filtrem krawędzi o zadanej wielkości, np.
[math]\begin{bmatrix}-1 & -1 & -1 & -1 & -1 \\-1 & -1 & -1 & -1 & -1 \\ 0 & 0 & 0 & 0 & 0 \\ 1 & 1 & 1 & 1 & 1 \\1 & 1 & 1 & 1 & 1\end{bmatrix}.[/math]
  • Znalezienie i zaznaczenie różdżką (Wand) spójnych fragmentów poniżej pewnego progu, dodanie ich do roiManagera

Powyższe kroki można wykonać wyklikując je w ImageJ i od tego zaczniemy. Ale potem należy napisać własny skrypt, który całą tę pracę zrobi za nas automatycznie.