5.23. Korekcija perspektive

Upozorenje

Proizvoljna matrica transform veličine 3 puta 3 podržana je samo na OpenMV Cam N6 – na svim ostalim pločama ključna riječ tiho se zanemaruje. Aplikacije koje trebaju raditi bilo gdje drugdje moraju koristiti gotovu metodu rotation_corr() (s njezinim oblikom corners=) ili unaprijed izračunati ispravljenu sliku izvan ploče.

Gotova metoda rotation_corr() pakira određenu obitelj perspektivnih izobličenja iza malog skupa parametara i radi na svakoj podržanoj ploči. Nekim aplikacijama treba izobličenje koje ne odgovara tom obliku: proizvoljno projektivno preslikavanje iz jednog četverokuta u drugi, kalibrirana korekcija za poznato postavljanje koje je već riješeno izvan mreže, matrica izobličenja koju je neki prethodni algoritam predao gotovu. Za njih draw_image() – zajedno s copy(), crop() i scale() – prihvaća ključnu riječ transform koja prima ručno izgrađenu matricu 3 puta 3 koja izravno opisuje izobličenje.

5.23.1. Afine i projektivne transformacije

Geometrijska izobličenja izražavaju se u homogenim koordinatama: položaj piksela (x, y) s dodanom 1, pomnožen s matricom 3 puta 3.

Afini oblik mjesto je za početak. Njegov je donji redak fiksiran na \((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}\]

Raspisano, svaka izlazna koordinata linearna je kombinacija ulaznih koordinata uvećana za konstantu:

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

što obuhvaća skaliranje, rotaciju, smicanje i translaciju u bilo kojoj kombinaciji – i pod svima njima paralelne linije ostaju paralelne.

Projektivni (perspektivni) oblik oslobađa donji redak:

\[\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}\]

Raspisano:

\[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}\]

Dijeljenje s \(w' = g x + h y + 1\) ono je što transformaciju čini projektivnom, a ne tek afinom. Kada su \(g\) i \(h\) oboje nula, \(w'\) ostaje jedan i dijeljenje ne čini ništa – ponovno afini oblik. Kada je bilo koji različit od nule, \(w'\) se mijenja s ulaznim položajem i pikseli na različitim položajima skraćuju se za različite iznose, što više ne održava paralelne linije paralelnima – to je upravo trapezni efekt gledanja ravne plohe iz kosog kuta. Projektivna transformacija najopćenitije je geometrijsko izobličenje koje ravne linije preslikava u ravne linije; skaliranje, zrcaljenje, transponiranje, rotiranje i korekcija rotacije s četiri kuta sve su posebni slučajevi jedne takve.

Imenovane transformacije izravno proizlaze iz afinog oblika. Identitetska transformacija jedinična je matrica, 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}\]

Za većinu ručno izgrađenih transformacija aplikacija počinje s jednom od ovih kao osnovom i množi dalje matrice za svaku dodatnu operaciju, završavajući s jednom matricom 3 puta 3 koja opisuje složeno izobličenje. Matrice se primjenjuju zdesna nalijevo: \(M = T R S\) prvo pokreće skaliranje, zatim rotaciju, pa translaciju. Složena operacija koja svakomu na kraju zatreba jest rotacija oko središta slike – gola rotacijska matrica vrti sliku oko ishodišta piksela u gornjem lijevom kutu, pa centrirana inačica pomiče središte \((c_x, c_y)\) u ishodište, rotira i vraća ga natrag:

\[\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. Ključna riječ transform

Matrica ulazi kroz ključnu riječ transform, dostavljena kao ulab.numpy.ndarray veličine 3 puta 3. Metoda kojoj treba posegnuti jest draw_image(), koja izvor izobličuje kroz matricu dok ga crta na odredište – rezultat završava u međuspremniku koji aplikacija kontrolira, a izobličenje se slaže sa svim ostalim u pozivu: skaliranjem, alfa stapanjem, maskiranjem.

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)

Primjer izobličuje img na canvas skaliran 1,2 puta u svakom smjeru i pomaknut lijevo i gore za 20 odnosno 15 piksela – afino izobličenje izgrađeno izravno iz unosa matrice opisanih gore. Ista ključna riječ na copy(), crop() i scale() primjenjuje izobličenje na samu sliku.