Super-rozdzielczość: opis + algorytm

RobertG

Użytkownik
Dołączył
Styczeń 3, 2007
Posty
391
== Wstęp ===

Na pewno oglądacie jakieś filmy sensacyjne, CSI czy coś, laboranci często badają
tam jakieś zdjęcie, powiększają, poprawiają ostrość, aż do skutku, w końcu widzą
twarz przestępcy albo rejestracje. Wielu z was krzyknie, że to czysta bujda, a
jednak jest w tym ziarno prawdy, mając serie zdjęć można uzyskać zjecie o
wyższej rozdzielczości, o większej liczbie detali (choć IMHO na filmach trochę
przesadzają). Dziś chciałem wam zaprezentować taki skrypt, nie jest on wysokiej
jakości, a do tego wykorzystuje dość słaby algorytm ale póki co tyle tylko mam.


Nie jestem biegły w tym temacie więc w tekście może być sporo błędów, z góry
dzięki za uwagi. Temat jest trudny ale fajny :)

Algorytmy te znajdują zastosowanie:
* w wojsku (do zdjęć z satelitów szpiegowskich)
* medycynie (do zdjęć tomograficznych etc)
* astronomii (do obiektów astronomicznych)

Jeden przykład ze skryptu opisanego poniżej:
(zdjęcie oryginalne, w wysokiej rozdzielczości)
http://rgawron.megiteam.pl/static/others/wyniki/diagram.tif
(jedno ze zdjęć niskiej rozdzielczości, powiększyłem je do rozmiarów zdjęcia symulowanego algorytmem lanczos3, żeby było porównanie):
http://rgawron.megiteam.pl/static/others/wyniki/@1_1.tif
zdjęcie uzyskane:
http://rgawron.megiteam.pl/static/others/wyniki/iteration.12.tif

== Model ==

Zbudujemy model tego zjawiska. Mamy serię zdjęć w niskiej rozdzielczości które
przedstawiają obraz w większej rozdzielczości. Przeanalizujemy, jak przebiega
proces tworzenia zdjęcia (nie jest tu istotne, czy to skanowanie, fotografia
analogowa, cyfrowa, fotografia komórką, czy z satelity, schemat jest ten sam).

Tak więc obraz wysokiej rozdzielczości jest przesuwany, to jest kluczowe, każda
fotka zawiera obrazek trochę przesunięty w porównaniu do innych (np satelita
wykonuje zdjęcia z innej pozycji w skutek przemieszczania się po orbicie, ręka
drży, etc).

Następnie obraz jest rozmywany (np przez turbulencje powietrza, zapylenie).

Na obraz nakładany jest szum (np w skutek szumów matrycy w aparacie
fotograficznym, szumy to też drobne obiekty jak muchy czy ptaki pojawiające się
na niektórych ujęciach).

Następnie obraz jest pomniejszany.

W ten sposób ze zdjęcia wysokiej rozdzielczości (często oznaczanego HR)
uzyskujemy (nieskończoną) ilość zdjęć niskiej rozdzielczość. Mówiąc prosto: tak
wygląda robienie fotki od strony matematyki :)

Proces ten możemy zapisać jako:
LR(n) = S(B(T(HR) + N))

gdzie:
LR(n) - n-te zdjęcie niskiej rozdzielczości
HR - zdjęcie wysokiej rozdzielczości
T - przesunięcie o wektor (x,y)
N - szum
B - rozmycie (a dokładniej "point spread function", nie wiem, czy jest polski
odpowiednik tego pojęcia, a Wikipedia milczy)
S - operator pomniejszania

Wzór jest dość ogólny, przyjąłem swoje oznaczenia, bo i tak w każdym artykule są
inne. Wartości w tym równaniu są macierzami, a nie skalarami!

Nasze zadanie polega na tym, by znając ten model i mając kilka LR zdjęć i zbiór
stałych (kolejny problem i inna bajka) uzyskać obrazek wyjściowy w większej rozdzielczości.


== Metody ===

Metod jest kilka, nie jestem pewien, czy mają polskie nazwy:
* iteratywna, zastosowana przeze mnie. O niej poniżej
* w domenie częstotliwości, traktujemy kolor każdego piksela o wsp. (x,y) jako
wartość funkcji zależnej od tych współrzędnych. Na tym zbiorze punktów
dokonujemy transformaty Fouriera i mając obrazki w takiej formie próbujemy je
zmontować w jeden. Nie opiszę, co się dzieje dalej bo jeszcze tego nie
ogarniam :(
* propabilistyczna, procesy stochastyczne, nie ogarniam :(
* sieci neuronowe, sporządzamy zbiór zdjęć niskiej rozdzielczości wygenerowanych
ze zdj wysokiej rozdzielczości (o tym, jak to zrobić później), uczymy sieć, by
generowała obrazek możliwie najbardziej zbliżony do oryginału.

Może jeszcze trochę historii, z tego, co wyszukałem, to pierwszą metodą była ta
używająca transformat Fouriera, wykorzystano ją do obróbki zdjęć astronomicznych
amerykańskiego satelity.


== Metoda iteratywna ==

Stałe, które posiadamy:
A. Wartość, o jaką chcemy powiększyć zdjęcie (np. 2 razy)
B. Point spread function
C. Ilość iteracji, które chcemy wykonać lub maksymalny błąd, jaki tolerujemy +
funkcję szacującą błąd
D. Zbiór zdjęć LR, gdzie znamy wektor przesunięcia dla każdego z nich

Robimy tak:
1. Generujemy powiększone zdjęcie (możemy użyć fikuśnych metod ale można je
zwyczajnie powiększyć jakimś dobrym algorytmem do powiększania). Nazwijmy je E
2. W pętli, aż spełnimy warunki z C:
1. Z E generujemy zbiór zdjęć LR o takich samych przesunięciach, jak zdjęcie
LR, które posiadamy
2. Dla każdej pary zdjęć LR, dla każdego piksela, odejmujemy wartość piksela
ze zdjęcia które dostaliśmy od zdjęcia, które wygenerowaliśmy,
3. Różnicę nanosimy na piksele zdjęcia E, na których wartość wpłynął piksel
z 2. Różnicę tę mnożymy wcześniej przez stałą, której dobór zależy od
nas, mówi ona , jak bardzo różnica ma wpłynąć na E, zbyt duża wartość
psuje efekt, zbyt niska sprawia, że efekt jest niewidoczny


Powtarzamy to w do skutku w kolejnych krokach.


Potrzeba nam funkcji, która określiłaby, o ile wygenerowany obrazek odbiega od
oryginału. Ja przyjąłem następującą (nie ma tu edytora texa więc napiszę po
prostu): suma dla każdego obrazka sumy dla każdego piksela z różnicy wartości
oczekiwanej piksela i wartości uzyskanej z modelu. Całość jest znormalizowana
przez podzielenie przez iloraz ilości posiadanych LR zdjęć, długości LR zdjęcia
i jego szerokości. IMHO funkcja jest bardzo dobra, więc polecam :)


== Wyniki ==
1. Jak pisałem skrypt jest kiepski, nie jest gotowy a część kodu to wielkie
copy-paste, tak łatwiej się go zmienia ale jest też mało czytelny/głupi.

Wróćmy jeszcze do stałych, skąd mamy znać PSF, przesunięcia LR zdjęć? Na obie
sprawy są algorytmy (nie przyglądałem się im bliżej), lecz do testów łatwiej
korzystać z obrazków wygenerowanych automatycznie.

Serie obrazków można wygenerować przy użyciu skryptu:

./generate_input_samples.py -i ścieżka_do_zdjęcia -z pomniejszenie

obrazki generowane są do katalogu input_images

Przykładowe obrazki do testów znajdują się w katalogu samples.

By ułatwić sprawę pominąłem szumy.


By odtworzyć obrazek HR odpalamy skrypt:

./super_resolution.py

Zaciągnie on obrazki z w/w katalogu, po każdej iteracji zapisze wynikowy obrazek
w bieżącym katalogu. Wszystkie zmienne i stałe zakodowane są żywcem w skrypcie.

W przyszłości stałe przeniosę do pliku YAML

Skrypt obsługuje tylko zdjęcia czarno-białe.

Jeśli byście chcieli to odpalić u siebie, to możecie zaciągnąć kod z mojego
GitHuba pod adresem:

http://github.com/RobertGawron/supper-resolution

Jeśli macie konstruktywne komentarze, to chętnie wysłucham. To tyle i jak piałem
nie jest to działka, w której czułbym się mocno więc błędów może tu być sporo!
 
Ostatnia edycja:

shoorick

Użytkownik
Dołączył
Lipiec 17, 2008
Posty
66
Ciekawe jest. Można zastosować z niskorozdzielowę kamerką, naprzykład, z optycznej myszki (18x18 sensor), żeby coś zobaczyć ;)
 

RobertG

Użytkownik
Dołączył
Styczeń 3, 2007
Posty
391
Można by, ciekawe by to było ale i trudniejsze, bo trzeba by oszacować kilka stałych. Fajny pomysł :)

Kiedyś miałem pdf'a z treścią wykładów profesora z Alaski, pokazywał on swój soft, gdzie kilka zdjęć z kamerki było składane w jedno, o większej liczbie detali, obraz miał mniej klatek ale był lepszy.

BTW poprawiłem trochę oba skrypty, konfiguracja znajduję się teraz w pliku YAMLa i parę innych drobiazgów.

Zachęcam do testowania :)


EDIT: O skrypcie napisałem też tutaj:
http://rgawron.megiteam.pl/2010/06/09/super-resolution/
 
Ostatnia edycja:

RobertG

Użytkownik
Dołączył
Styczeń 3, 2007
Posty
391
[Odświeżam wątek, bo od ostatniego wpisu sporo minęło i sporo się zmieniło, a już nie mogę edytować posta]

Sama implementacja przeszła kilka ulepszeń (np. użycie numpy), aktualne wyniki (jeden z obrazków przed i obrazek po) pokazane są poniżej (obrazki z oryginalnego posta):
super_resolution_simple_upscale.jpg
super_resolution_image_python.png
Zmieniło się wywołanie skryptów i przechowywanie konfiguracji, jest ono opisanie na wiki projektu. Z większych zmian, to przesunięcie między poszczególnymi oryginalnymi obrazkami nie jest zakodowane na sztywno, lecz jest estymowane przez osobną klasę - link do krótkiego artykułu, który opisuje użyty algorytm. Obecnie zabieram się za napisanie części estymującej psf.

Link do projektu na GitHubie pozostał bez zmian.

Jeśli ktoś ma jakieś uwagi, to zapraszam do dyskusji :)
 
Do góry Bottom