5.2. Współrzędne i obszary

Przetwarzanie obrazu działa na pikselach, a żeby zadziałać na piksel, algorytm musi go zaadresować za pomocą współrzędnych. Aby zadziałać na prostokąt złożony z pikseli, jest tak samo – prostokąt musi zostać opisany w sposób, co do którego algorytm i kod aplikacji są zgodne. Konwencja, której moduł image używa dla współrzędnych i prostokątów, jest prosta, z jednym szczegółem, który zaskakuje czytelników przyzwyczajonych do konwencji matematycznej, a nie do konwencji grafiki komputerowej, i o którym warto powiedzieć wprost na wstępie.

5.2.1. Siatka pikseli

Piksel (0, 0) to lewy górny róg obrazu. Oś x biegnie w prawo, więc większe x oznacza dalej w prawo. Oś y biegnie w dół, więc większe y oznacza dalej w dół obrazu. Obraz o wymiarach szerokość na wysokość zawiera piksele o całkowitych współrzędnych od (0, 0) aż do (width - 1, height - 1); nie ma piksela w (width, 0) ani w (0, height) – te pozycje to prawa i dolna krawędź, jeden krok za ostatnim rzeczywistym pikselem w każdym kierunku.

Skierowana w dół oś y to wspomniany wyżej szczegół. Czytelnik przyzwyczajony do geometrii z papieru milimetrowego oczekuje, że większe y oznacza wyżej; tutaj ta intuicja jest dokładnie odwrócona. Powodem odwrócenia jest to, że zarówno cyfrowe sensory, jak i cyfrowe wyświetlacze pracują od lewego górnego rogu i przesuwają się w prawo wzdłuż każdego wiersza, z góry na dół, a rozmieszczenie pikseli w pamięci w tej samej kolejności sprawia, że relacja między „pozycją i w buforze” a „wierszem r, kolumną c obrazu” staje się tak prostym działaniem arytmetycznym, jak to tylko możliwe – pozycja i piksela (x, y) to po prostu y * width + x. Każda biblioteka do przetwarzania obrazu zgodziła się na ten układ dekady temu z tego samego powodu, a kosztem jest jedno drobne dostosowanie mentalne przy pierwszej pracy z obrazami.

Prostokąt reprezentujący obraz. Znacznik w jego lewym górnym rogu jest opisany jako (0, 0). Strzałka wzdłuż górnej krawędzi wskazuje w prawo i jest oznaczona jako x; strzałka w dół wzdłuż lewej krawędzi wskazuje w dół i jest oznaczona jako y. Mniejszy prostokąt narysowany wewnątrz jest oznaczony jako ROI, z jego lewym górnym rogiem w (x, y) i jego wymiarami w oraz h zaznaczonymi wzdłuż krawędzi.

Układ współrzędnych obrazu: początek w lewym górnym rogu, x biegnie w prawo, y biegnie w dół. Prostokątny obszar wewnątrz obrazu jest nazywany przez jego lewy górny róg (x, y) oraz jego wymiary (w, h).

5.2.2. Prostokąty

Większości operacji na obrazie mniej zależy na pojedynczym pikselu niż na prostokącie pikseli – obszarze do przeszukania, regionie do skopiowania, ramce wewnątrz ramki, dla której obliczane są statystyki. Forma nazywania prostokąta wybiera najprostsze możliwe rozszerzenie konwencji pojedynczego piksela: podaj współrzędną lewego górnego rogu, a po niej wymiary prostokąta, spakowane w czteroelementową krotkę (x, y, w, h). Piksele wewnątrz prostokąta znajdują się w kolumnach od x do x + w - 1 oraz w wierszach od y do y + h - 1.

Szczegółem, który warto tu wskazać wprost, jest to, że w i h to rozmiary, a nie współrzędne prawego dolnego rogu. Prostokąt (10, 20, 4, 3) obejmuje kolumny 10, 11, 12, 13 oraz wiersze 20, 21, 22 – łącznie dwanaście pikseli – a nie obszar biegnący od (10, 20) do (4, 3). Konwencja jest jednolita w całym module, więc gdy zostanie przyswojona, pomyłki ustają, ale za pierwszym razem rzeczywiście potrafi zmylić.

Forma (x, y, w, h) pojawia się w trzech miejscach, które wyglądają odmiennie, lecz współdzielą tę konwencję. Pierwsze to sytuacja, gdy obraz opisuje swój własny obszar: prostokąt obejmujący cały obraz to (0, 0, width, height). Drugie to sytuacja, gdy metoda wykrywania zwraca wynik z ramką ograniczającą – blob, rect, apriltag – a ramka jest raportowana jako (x, y, w, h). Trzecie to sytuacja, gdy metodzie trzeba powiedzieć, aby działała na pewnym podobszarze obrazu, a nie na całej ramce; argument nazwany roi, który zawęża zakres operacji, przyjmuje tę samą czteroelementową krotkę.

Pobranie ramki ograniczającej z jednej metody i przekazanie jej do argumentu roi kolejnej metody to jeden z najczęstszych wzorców w przetwarzaniu obrazu. Ramka ograniczająca zgrubnego pierwszego wykrycia zawęża obszar przeszukiwania dla dokładniejszego drugiego, a jednolite słownictwo dla wyników wykrywania i argumentów metod sprawia, że ten wzorzec jest tak prosty, jak jest – jedna forma krotki, używana w ten sam sposób po obu stronach przekazania.

5.2.3. Całkowite adresy, ułamkowe centroidy

Same adresy pikseli są liczbami całkowitymi. Piksel albo jest, albo nie jest w danej całkowitej kolumnie i wierszu, a pytanie o to, co znajduje się we współrzędnej (40.5, 30.7), nie jest dobrze postawione – nie ma piksela siedzącego dokładnie w tej pozycji. Garść wielkości, które moduł image wyprowadza z pozycji pikseli, jest jednak ułamkowa i warto zrozumieć dlaczego, aby to rozróżnienie nie zaskoczyło aplikacji później.

Najczęstszym przypadkiem jest centroid – środek masy obszaru. Dla spójnego obszaru pikseli centroid w postaci zmiennoprzecinkowej jest średnią pozycji pikseli składowych, ważoną ich gęstością. Obszar, którego piksele rozkładają się na dwie kolumny, będzie miał centroid x wynoszący na przykład 41,6 – rzeczywistą pozycję, którą oko opisałoby jako „środek tego obszaru”, mimo że żaden faktyczny piksel nie znajduje się dokładnie w tym x. Obiekty wyników wykrywania niosą obie formy jako właściwości tylko do odczytu: parę całkowitą (cx / cy, przydatną przy podawaniu pozycji z powrotem do czegoś, co oczekuje całkowitych współrzędnych pikselowych) oraz parę zmiennoprzecinkową (cxf / cyf, przydatną, gdy pozycja trafia do pętli sterowania, która korzysta z rozdzielczości subpikselowej).

Drugim przypadkiem jest przemieszczenie między dwiema ramkami mierzone w dziedzinie częstotliwości. Techniki, które analizują zawartość widmową obrazu, a nie bezpośrednio jego piksele, potrafią rozróżnić przesunięcia drobniejsze niż jeden piksel i raportują te przesunięcia jako zmiennoprzecinkowe wartości (dx, dy).

Zasada praktyczna: adresy pikseli są liczbami całkowitymi; pozycje i przesunięcia, które wychodzą z algorytmu, mogą być liczbami zmiennoprzecinkowymi. Metody rysowania przyjmują dowolną formę i zaokrąglają liczby zmiennoprzecinkowe w dół do najbliższego całkowitego piksela, gdy wynik musi trafić na siatkę.

5.2.4. Kartezjański i biegunowy

Opisany dotychczas układ jest kartezjański: każdy piksel jest nazywany przez swoje poziome i pionowe przesunięcie względem początku. To układ, w którym przechowywane są bajty – piksel i w buforze odpowiada pikselowi w kolumnie i % width i wierszu i // width, przechodząc przez wiersze od góry – i jest to układ, w którym domyślnie działa każda metoda.

Drugą reprezentację warto poznać, ponieważ niektóre algorytmy działają w niej znacznie lepiej. Współrzędne biegunowe nazywają każdy piksel przez jego odległość od wybranego punktu środkowego oraz kąt między nim a kierunkiem odniesienia. Piksele obrazu nie przesunęły się – bajty wciąż znajdują się w tym samym buforze wierszowym – ale schemat adresowania przełączył się z „jak daleko w prawo i jak daleko w dół” na „jak daleko od środka i pod jakim kątem wokół niego”.

Dwa prostokąty obok siebie, każdy reprezentujący ten sam obraz. Lewy pokazuje współrzędne kartezjańskie -- początek w lewym górnym rogu, osie x i y, przykładowy punkt P o współrzędnych (x, y). Prawy pokazuje współrzędne biegunowe -- znacznik środka C wewnątrz prostokąta, z linią od C do tego samego punktu P oznaczoną r (odległość), oraz łukiem oznaczonym theta (kąt).

Ten sam punkt P, nazwany na dwa sposoby: kartezjańsko (x, y) względem początku w lewym górnym rogu, biegunowo (r, theta) względem wybranego środka.

Po co się przełączać? Z powodu dwóch tożsamości, które zamieniają trudne wyszukiwania w łatwe.

We współrzędnych biegunowych obrót obrazu wokół wybranego środka jest tą samą operacją co translacja jego pikseli wzdłuż osi kąta – kierunku x w przeprojektowanym obrazie. Obrócona kopia to oryginał przesunięty w lewo lub w prawo w postaci biegunowej.

W wariancie logarytmiczno-biegunowym – oś odległości używa skali logarytmicznej, oś kąta pozostaje liniowa – skalowanie obrazu wokół wybranego środka jest tą samą operacją co translacja jego pikseli wzdłuż osi odległości – kierunku y. Przeskalowana kopia to oryginał przesunięty w górę lub w dół w postaci logarytmiczno-biegunowej.

Zatem algorytm, który musi rozpoznać znany wzorzec przy obrocie lub skalowaniu, może prowadzić swoje przeszukiwanie w przestrzeni biegunowej, gdzie obie transformacje zamieniają się w zwykłe translacje. Translacji jest znacznie taniej szukać niż obrotów i skalowań, a przeprojektowanie biegunowe to właśnie to, co umożliwia tę zamianę.

Współrzędne biegunowe nie zastępują kartezjańskich przy przechowywaniu pikseli; bajty zawsze mieszkają na siatce kartezjańskiej. Moduł udostępnia parę metod, które na żądanie przeprojektowują obraz z postaci kartezjańskiej na biegunową, algorytm, który potrzebuje współrzędnych biegunowych, wykonuje swoją pracę, a następnie albo wynik jest projektowany z powrotem, albo pomiar w przestrzeni biegunowej jest używany bezpośrednio. Ten mechanizm to jedyny powód, dla którego współrzędne biegunowe pojawiają się gdziekolwiek na powierzchni modułu.

Mając współrzędne kartezjańskie do nazywania pojedynczych pikseli, czteroelementową krotkę (x, y, w, h) do nazywania ich prostokątów oraz współrzędne biegunowe dostępne, gdy algorytm na nich korzysta, aplikacja dysponuje kompletnym słownictwem do nazywania, gdzie w obrazie coś się znajduje. To, co faktycznie jest przechowywane w którejkolwiek z tych pozycji, to kolejna warstwa fundamentu.