5.23. Perspektíva-korrekció

Figyelem

A tetszőleges 3-szor-3-as transform mátrix csak az OpenMV Cam N6-on támogatott – a kulcsszót minden más kártyán csendben figyelmen kívül hagyja. Az olyan alkalmazásoknak, amelyeknek máshol is futniuk kell, a kész rotation_corr() metódust (a corners= formájával) kell használniuk, vagy a korrigált képet a kártyán kívül kell előre kiszámítaniuk.

A kész rotation_corr() metódus a perspektíva-torzítások egy adott családját csomagolja egy kis paraméterkészlet mögé, és minden támogatott kártyán fut. Egyes alkalmazásoknak olyan torzításra van szükségük, amely nem illik ehhez a formához: egy tetszőleges projektív átleképezés az egyik négyszögből a másikba, egy kalibrált korrekció egy ismert rögzítéshez, amelyet már offline kidolgoztak, egy torzítási mátrix, amelyet valamilyen korábbi algoritmus készen ad át. Ezekhez a draw_image() – a copy(), crop() és scale() mellett – elfogad egy transform kulcsszót, amely egy kézzel felépített 3-szor-3-as mátrixot vesz át, amely közvetlenül leírja a torzítást.

5.23.1. Affin és projektív transzformációk

A geometriai torzításokat homogén koordinátákban fejezzük ki: a (x, y) képpontpozíciót, egy hozzáfűzött 1 értékkel, megszorozva egy 3-szor-3-as mátrixszal.

Az affin forma a kiindulópont. Az alsó sora rögzítve van a \((0, 0, 1)\) értéken:

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

Kifejtve minden kimeneti koordináta a bemeneti koordináták lineáris kombinációja plusz egy konstans:

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

amely lefedi a skálázást, forgatást, nyírást és eltolást bármilyen kombinációban – és mindegyik alatt a párhuzamos vonalak párhuzamosak maradnak.

A projektív (perspektíva) forma felszabadítja az alsó sort:

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

Kifejtve:

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

A \(w' = g x + h y + 1\) szerinti osztás teszi a transzformációt projektívvé, nem pedig pusztán affinná. Amikor \(g\) és \(h\) egyaránt nulla, \(w'\) egynek marad, és az osztás nem csinál semmit – ismét az affin forma. Amikor bármelyik nem nulla, \(w'\) a bemeneti pozícióval változik, és a különböző pozíciókban lévő képpontok különböző mértékben rövidülnek meg, ami már nem tartja párhuzamosan a párhuzamos vonalakat – pontosan ez a trapéztorzítás, amely egy lapos sík ferde szögből való nézéséből ered. A projektív transzformáció a legáltalánosabb geometriai torzítás, amely az egyenes vonalakat egyenes vonalakká alakítja; a skálázás, tükrözés, transzponálás, forgatás és a négysarkú forgáskorrekció mind ennek egy-egy speciális esete.

A megnevezett transzformációk közvetlenül az affin formából adódnak. Az identitás-transzformáció az egységmátrix, és:

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

A legtöbb kézzel felépített transzformációhoz egy alkalmazás ezek egyikéből indul ki alapként, és további mátrixokkal szoroz be minden egyes további művelethez, egyetlen 3-szor-3-as mátrixszal zárva, amely leírja az összetett torzítást. A mátrixok jobbról balra alkalmazódnak: a \(M = T R S\) először a skálázást futtatja, majd a forgatást, majd az eltolást. Az összetett művelet, amelyre mindenkinek előbb-utóbb szüksége van, a kép középpontja körüli forgatás – egy önmagában álló forgatási mátrix a képet a bal felső sarokban lévő képpont-origó körül pörgeti, így a központosított változat a \((c_x, c_y)\) középpontot az origóba mozgatja, forgat, majd visszamozgatja:

\[\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. A transform kulcsszó

A mátrix egy transform kulcsszón keresztül kerül be, egy 3-szor-3-as ulab.numpy.ndarray formájában megadva. A használandó metódus a draw_image(), amely a forrást a mátrixon keresztül torzítja, miközben egy célra rajzolja – az eredmény egy alkalmazás által vezérelt pufferben landol, és a torzítás komponálódik minden mással a híváson: a skálázással, az alfa-keveréssel, a maszkolással.

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)

A példa az img képet a canvas képre torzítja mindkét irányban 1,2-szeresére skálázva, és balra, illetve felfelé 20, illetve 15 képponttal eltolva – egy affin torzítás, amely közvetlenül a fent leírt mátrixelemekből épül fel. Ugyanaz a kulcsszó a copy(), crop() és scale() metódusokon a torzítást magára a képre alkalmazza.