5.23. Korekce perspektivy

Varování

Libovolná matice transform o rozměru 3 na 3 je podporována pouze na OpenMV Cam N6 – na každé jiné desce se toto klíčové slovo tiše ignoruje. Aplikace, které musí běžet kdekoli jinde, musí použít hotovou metodu rotation_corr() (s její formou corners=) nebo opravený obraz předpočítat mimo desku.

Hotová metoda rotation_corr() balí určitou rodinu perspektivních deformací za malou sadu parametrů a běží na každé podporované desce. Některé aplikace potřebují deformaci, která do této formy nezapadá: libovolné projektivní přemapování z jednoho čtyřúhelníku na druhý, kalibrovanou korekci pro známé uchycení, která už byla vypočtena off-line, deformační matici předanou hotovou od nějakého předřazeného algoritmu. Pro ně metoda draw_image() – spolu s copy(), crop() a scale() – přijímá klíčové slovo transform, které bere ručně sestavenou matici 3 na 3 popisující deformaci přímo.

5.23.1. Afinní a projektivní transformace

Geometrické deformace se vyjadřují v homogenních souřadnicích: pozice pixelu (x, y) s připojenou 1, vynásobená maticí 3 na 3.

Místem, kde začít, je afinní forma. Její spodní řádek je pevně dán jako \((0, 0, 1)\):

\[\begin{split}\begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} = \begin{bmatrix} a & b & c \\ d & e & f \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}\end{split}\]

Rozepsáno, každá výstupní souřadnice je lineární kombinací vstupních souřadnic plus konstanta:

\[x' = a x + b y + c, \qquad y' = d x + e y + f\]

což pokrývá škálování, rotaci, zkosení a posun v jakékoli kombinaci – a při všech z nich zůstávají rovnoběžné čáry rovnoběžné.

Projektivní (perspektivní) forma uvolňuje spodní řádek:

\[\begin{split}\begin{bmatrix} x'' \\ y'' \\ w' \end{bmatrix} = \begin{bmatrix} a & b & c \\ d & e & f \\ g & h & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}, \qquad (x', y') = \left( \frac{x''}{w'}, \; \frac{y''}{w'} \right)\end{split}\]

Rozepsáno:

\[x' = \frac{a x + b y + c}{g x + h y + 1}, \qquad y' = \frac{d x + e y + f}{g x + h y + 1}\]

Dělení \(w' = g x + h y + 1\) je to, co činí transformaci projektivní, a nikoli pouze afinní. Když jsou \(g\) i \(h\) nulové, \(w'\) zůstává jedničkou a dělení nic nedělá – opět afinní forma. Když je některé z nich nenulové, \(w'\) se mění s pozicí na vstupu a pixely na různých pozicích se zkracují o různé hodnoty, což už neudržuje rovnoběžné čáry rovnoběžnými – je to přesně lichoběžníkový efekt pohledu na plochou rovinu ze šikmého úhlu. Projektivní transformace je nejobecnější geometrická deformace, která převádí rovné čáry na rovné čáry; škálování, převracení, transponování, rotace a korekce rotace pomocí čtyř rohů jsou všechny zvláštními případy jedné z nich.

Pojmenované transformace vyplývají přímo z afinní formy. Identická transformace je jednotková matice a:

\[\begin{split}\underbrace{\begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{bmatrix}}_{\text{translate by } (t_x, \; t_y)} \qquad \underbrace{\begin{bmatrix} s_x & 0 & 0 \\ 0 & s_y & 0 \\ 0 & 0 & 1 \end{bmatrix}}_{\text{scale by } (s_x, \; s_y)} \qquad \underbrace{\begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix}}_{\text{rotate by } \theta}\end{split}\]

Pro většinu ručně sestavených transformací aplikace začne s jednou z nich jako základem a pro každou další operaci přinásobí další matice, přičemž skončí s jedinou maticí 3 na 3, která popisuje složenou deformaci. Matice se aplikují zprava doleva: \(M = T R S\) spouští nejprve škálování, pak rotaci a nakonec posun. Složením, které nakonec každý potřebuje, je rotace kolem středu obrazu – holá rotační matice otáčí obraz kolem počátku pixelů v levém horním rohu, takže vystředěná verze přesune střed \((c_x, c_y)\) do počátku, otočí jej a přesune zpět:

\[\begin{split}M = \underbrace{\begin{bmatrix} 1 & 0 & c_x \\ 0 & 1 & c_y \\ 0 & 0 & 1 \end{bmatrix}}_{\text{move centre back}} \underbrace{\begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix}}_{\text{rotate}} \underbrace{\begin{bmatrix} 1 & 0 & -c_x \\ 0 & 1 & -c_y \\ 0 & 0 & 1 \end{bmatrix}}_{\text{move centre to origin}}\end{split}\]

5.23.2. Klíčové slovo transform

Matice se předává klíčovým slovem transform jako ulab.numpy.ndarray o rozměru 3 na 3. Metodou, po které sáhnout, je draw_image(), která deformuje zdroj skrz matici, když jej vykresluje do cíle – výsledek skončí v bufferu, který aplikace ovládá, a deformace se skládá se vším ostatním ve volání: se škálováním, alfa prolínáním i maskováním.

import ulab.numpy as np

M = np.array([[1.2,  0.0, -20.0],
              [0.0,  1.2, -15.0],
              [0.0,  0.0,   1.0]])

canvas.draw_image(img, transform=M)

Příklad deformuje img na canvas se škálováním 1,2 v každém směru a s posunem doleva a nahoru o 20, respektive 15 pixelů – afinní deformace sestavená přímo z prvků matice popsaných výše. Totéž klíčové slovo u copy(), crop() a scale() aplikuje deformaci na samotný obraz.