2011-12-12

Metody resamplowania

Nie chodzi mi tyle o filtry, ale o sposób samego resamplowania.

Sposób pierwszy. Robimy podobnie jak podczas zmiany rozdzielczości obrazka (tak działał resampler po staremu) Tworzymy tablice subpixeli, każdy subpixel przyciągamy do odpowiedniego subpixela. Taką tablicę resamplujemy. Wady to duża ilość pamięci, niedokładność związana z nieuwzględnianiem prawdziwych współrzędnych promienia.

Do metody drugiej i trzeciej musimy użyć innego sposobu pamiętania wartości kolorów promieni.

Ponieważ rezygnujemy z bitmapy subpixeli, która także nawiasem mówiąc byłaby kłopotem podczas resamplownania adaptywnego, które zamierzam dodać, musimy jakoś pamiętać wartości kolorów promieni, które będą potrzebne do zresamplowania próbek które jeszcze nie zostały zrenderowane - z innych prostokątów. Przez prostokąt rozumiem tutaj obszar znajdujący się obok, który nie został jeszcze zrenderowany. W obecnej chwili scena jest dzielona na w miarę równe prostokąty o określonej licznie subpikseli i wszystkie są one renderowane równolegle. Ponieważ w procesie resamplingu wartość subpikseli granicznych może być potrzeba do wyliczenia pikseli w sąsiednim prostokącie musimy je jakoś zapamiętać. Dodatkowo aby uniknąć problemów w wyścigiem zabronione jest renderowanie sąsiednich, wzajemnie na siebie wpływających prostokątów. Możemy na przykład pamiętać je w tablicy hashującej, liście o wielkości równej liczbie pikseli na scenie - każdy element listy byłby null-em, ewentualnie bardzo rzadko tablicą wartości i współrzędnych promieni. Z tym, że podczas zmiany sposobu renderowanie np. z prostokątów na linia po linii mogło by się okazać, że kod wyliczający czy dany piksel będzie jeszcze wykorzystywany mógłby okazać się nie uniwersalny. No i jeśli renderujemy prostokątami to subpiksele brzegowe trzeba pamiętać maksymalnie dla 3 kwadratów - potrzebny byłby jakiś licznik referencji - brzegowe 2, rogowe - 3, albo 2 jeśli są na brzegu sceny. Dosyć kłopotliwe... Dlatego zdecydowałem się na rozwiązanie wymagające więcej pamięci, ale za to bardziej uniwersalne. Resamplowanie działa w 2D. Zmiana rozdzielczości obrazka za pomocą filtru 2D jest wolniejsza niż dwukrotne użycie filtru 1D z pionie i w poziome. Wynik jest ten sam. Kształt filtru powstaje poprzez obrót filtra 1D wokół Y, jeśli tak możemy nieprecyzyjnie powiedzieć. Ogólny wzór na wartość zrekonstruowanego piksela ma postać:

$\displaystyle C(x,y) = \frac{\sum f(x-x_i,y-y_i)c(x_i,y_i) }{\sum f(x-x_i,y-y_i)}$

Wartości wag filtra wyliczone z tego wzory nie wymagają normalizacji, nawet jeśli pole pod filtrem jest różne od 1, a ni tylko jeśli wyliczone wagi obarczone są błędem numerycznym. Normalizacja jest wzór - normalizacja to podzielenie wszystkich wag przez sumę wag, tak by ta suma wynosiła 1.

$C(x,y)$ to wynikowy kolor. $c(x_i,y_i)$ to kolor promienia. $f(x-x_i,y-y_i)$ to wartość filtru. Zgodnie z tym wzorem korzystnie jest pamiętać kolor jako iloraz dwóch liczb, dzięki czemu możemy dodawać do piksela wartości nowych promieni. Znika nam także problem pamiętania wartości wyliczonych promieni na potrzeby sąsiednich prostokątów.

Pomimo normalizacji może dojść do przestrzelenia koloru. Weźmy dwie wagi: 2 i -0.5. Niech oba kolory mają wartość 1, wtedy wartość zrekonstruowana to 1, ale jeśli drugi kolor ma w tym punkcie wartość 0, to otrzymamy 2/1.5. Widać to zwłaszcza podczas Samplowania Jitter 1x1 na Lanczos, który ma przedziały ujemne.

No i teraz dwie pozostałe metody.

Druga to liczenie za każdym razem wagi filtru. W metodzie trzeciej budujemy subtablicę wag o określonej wielkości. Centrujemy ją na pikselu wynikowym. Patrzymy w którą komórkę subtablicy trafił promień i bierzemy z niej wagę. Przy czym subtablica może mieć większą rozdzielczość niż wartość ilości próbek na piksel, dzięki czemu może być dokładniejsza niż metoda pierwsza. Przy odpowiednio dużej wielkości powinna być tak samo efektywna jak metoda druga, a przy tym szybsza.

Metody 2 i 3 w stosunku do 1 generują obraz nieznacznie przesunięty. Przesunięcie jest znacznie mniejsze od 0.5 i ... nie wiem skąd się bierze.

Brak komentarzy:

Prześlij komentarz