Table of Contents

Verwendung von easyar in einer 3D-engine

Um easyar in einer 3D-engine zu verwenden, müssen die kamerabilder und virtuellen objekte gerendert werden. Zum rendern der virtuellen objekte müssen sie mit dem kamerabild ausgerichtet sein. Beim rendern des kamerabilds stimmen einige parameter beim erzeugen des bilds und beim anzeigen möglicherweise nicht überein, beispielsweise die position, ausrichtung, bildausschnitt, seitenverhältnis usw. der physikalischen kamera, die sich von denen des bildschirms unterscheiden können. Dies muss beim rendern berücksichtigt werden. Wenn easyar in eine nicht unterstützte 3D-engine integriert werden soll, sind folgende details besonders zu beachten.

Kamerabild-randfüllung-beschnitt

Das zuschneiden, transponieren und kodieren von bildern erfordert erhebliche rechenleistung. Um die rechenlast und die latenz zu verringern, werden in der regel weniger verarbeitete formate verwendet. Um die videokodierung zu vereinfachen, werden die von der physikalischen kamera ausgegebenen bilder oft an raster wie 8x8, 16x16, 32x32 oder 64x64 angeglichen. Beispielsweise kann bei auswahl einer auflösung von 1920x1080 auf einigen smartphones das ausgegebene bild 1920x1088 betragen, weil 1080 kein vielfaches von 64 ist.

Bild mit randfüllung

Dies erfordert, dass diese überschüssigen randbereiche beim rendern entfernt werden. Es gibt mehrere möglichkeiten: eine besteht darin, beim hochladen des bilds in den speicher die breite anzugeben, z.b. kann in opengl glPixelStorei(GL_PACK_ROW_LENGTH, ...) verwendet werden; eine andere besteht darin, die UV-koordinaten im fragment-shader manuell zu berechnen und die bereiche außerhalb des bilds beim abtasten abzuschneiden.

Rendern entsprechend der bildschirmdrehung

Auf smartphones ist das von der physikalischen kamera aufgenommene bild in der regel relativ zum gehäuse fixiert und ändert sich nicht mit der anzeigeorientierung des bildschirms. Die ausrichtung des smartphone-gehäuses beeinflusst jedoch unsere definition der richtungen oben, unten, links und rechts im bild. Beim rendern beeinflusst auch die aktuelle bildschirmanzeigeorientierung die richtung des angezeigten bilds.

Beim rendern muss in der regel ein drehwinkel des kamerabilds relativ zur anzeigeorientierung des bildschirms bestimmt werden.

Wenn wir mit \(\theta_{screen}\) die bogenmaß der im uhrzeigersinn drehung des bildschirmbilds relativ zur natürlichen bildschirmausrichtung bezeichnen, mit \(\theta_{phycam}\) die bogenmaß, um die das bild der physikalischen kamera im uhrzeigersinn gedreht werden muss, um auf einem bildschirm in natürlicher ausrichtung korrekt angezeigt zu werden, und mit \(\theta\) die bogenmaß, um die das bild der physikalischen kamera gedreht werden muss, um auf dem aktuellen bildschirm angezeigt zu werden.

Für die rückseitige kamera gilt:

\[ \theta = \theta_{phycam} - \theta_{screen} \]

Zum beispiel auf einem android-smartphone, wenn das smartphone in natürlicher ausrichtung verwendet wird, \(\theta_{screen} = 0, \theta_{phycam} = \frac{\pi}{2}\), dann ist \(\theta = \frac{\pi}{2}\).

Für die frontkamera, wenn nach abschluss der drehung eine spiegeln in horizontaler richtung erfolgt, gilt:

\[ \theta = \theta_{phycam} + \theta_{screen} \]
Anmerkung

Wenn sich die bildschirmanzeige dreht, muss \(\theta\) unmittelbar im ersten bild nach der drehung neu berechnet werden, um eine kurzzeitige fehlorientierung des bildschirmbilds zu vermeiden.

Rendern des kamerahintergrunds und der virtuellen objekte

Um virtuelle objekte auf einem smartphone zu rendern, müssen sie mit dem kamerabild ausgerichtet sein. Dies erfordert, dass wir die rendering-kamera und die objekte in einem virtuellen raum platzieren, der dem realen raum vollständig entspricht, und mit dem gleichen sichtfeld und seitenverhältnis der physikalischen kamera rendern. Die perspektivische projektionstransformation, die das kamerabild und die virtuellen objekte durchlaufen, ist fast identisch, mit einem unterschied: die perspektivische projektion des kamerabilds findet größtenteils in der physikalischen kamera statt, während die der virtuellen objekte ein reiner rechenprozess ist.

Im folgenden wird die opengl-konvention verwendet. Bei verwendung anderer konventionen ist eine entsprechende koordinatenachsen-abbildung erforderlich. Angenommen, das kamera-koordinatensystem ist wie folgt definiert: x-achse zeigt nach rechts, y-achse zeigt nach oben, z-achse zeigt nach außen aus dem bildschirm heraus. Das scheren-koordinatensystem ist wie folgt definiert: x-achse zeigt nach rechts, y-achse zeigt nach oben, z-achse zeigt nach außen aus dem bildschirm heraus, w-achse ist die virtuelle achse.

In diesem fall lautet die für das rendern des kamerabilds erforderliche perspektivische projektionsmatrix wie folgt:

\[ P_i=\left( \begin{array}{cccc} (-1)^{\text{flip}} & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & 1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} \cos (-\theta ) & -\sin (-\theta ) & \phantom{0} & \phantom{0} \\ \sin (-\theta ) & \cos (-\theta ) & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} s_x & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & s_y & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right) \]

Dabei gilt: flip gibt an, ob das bild horizontal gespiegelt wird, wert ist 1 bei spiegelung, 0 ohne spiegelung; \(\theta\) ist der drehwinkel des bilds im uhrzeigersinn im bogenmaß; \(s_x\) , \(s_y\) sind skalierungsfaktoren, die für gleichmäßiges skalieren oder auffüllen verwendet werden und sich mit \(\theta\) ändern. Diese transformationsmatrix skaliert zunächst das kamerabild, führt dann eine drehung durch und schließlich eine spiegeln. Beim rendern sollte ein rechteck verwendet werden, das den gesamten bildschirm ausfüllt, z.b. können in opengl die eckpunkte des rechtecks bei \((-1, -1, 0)\) , \((1, -1, 0)\) , \((1, 1, 0)\) , \((-1, 1, 0)\) platziert werden, die UV-koordinaten an den entsprechenden vier ecken gesetzt werden, und dann mit dieser perspektivischen projektionsmatrix gerendert werden.

Die für virtuelle objekte erforderliche perspektivische projektionsmatrix lautet wie folgt:

\[ P=P_i\left( \begin{array}{cccc} 1 & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & 1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & -\frac{f+n}{f-n} & -\frac{2 f n}{f-n} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \end{array} \right)\left( \begin{array}{cccc} \frac{2}{w} & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & \frac{2}{h} & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} 1 & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & -1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} f_x & \phantom{0} & c_x & \phantom{0} \\ \phantom{0} & f_y & c_y & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} 1 & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & -1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right) \]

Dabei gilt: \(n\) , \(f\) sind die in der perspektivischen projektionsmatrix des üblichen 3D-renderings verwendeten parameter für den nahen und fernen scherenbereich; \(w\) , \(h\) sind die pixel-breite und -höhe des kamerabilds; \(f_x\) , \(f_y\) , \(c_x\) , \(c_y\) sind die intrinsischen parameter, die häufig im kameramodell verwendet werden, wobei \(f_x\) , \(f_y\) die pixel-brennweiten sind, \(c_x\) , \(c_y\) die pixel-position des hauptpunkts. Diese projektionsmatrix führt folgende transformationen nacheinander durch: die perspektivische projektionstransformation der intrinsischen kameraparameter (aufgrund der entgegengesetzten y- und z-achsenrichtungen zwischen dem bildkoordinatensystem in opencv und dem kamera-koordinatensystem in opengl werden zwei koordinatensystemtransformationen durchgeführt), die transformation vom pixel-koordinatensystem des bilds in das koordinatensystem des bildrechtecks, die transformation des nahen und fernen scherenbereichs und die perspektivische projektionstransformation beim rendern des kamerabilds.

Nach zusammenfassung ergibt sich:

\[ P=P_i\left( \begin{array}{cccc} \frac{2 f_x}{w} & \phantom{0} & 1-\frac{2 c_x}{w} & \phantom{0} \\ \phantom{0} & \frac{2 f_y}{h} & -1+\frac{2 c_y}{h} & \phantom{0} \\ \phantom{0} & \phantom{0} & -\frac{f+n}{f-n} & -\frac{2 f n}{f-n} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \end{array} \right) \]

Aus dem oben beschriebenen prozess geht hervor, dass das rendering in der regel in zwei schritten erfolgen muss: einmal zum rendern des kamerabilds und einmal zum rendern der virtuellen objekte, wobei die virtuellen objekte über dem kamerabild liegen.

In einigen 3D-engines wird die perspektivische projektionsmatrix mit parametern wie horizontalem sichtfeld, seitenverhältnis usw. dargestellt. Wenn drehung und spiegeln vernachlässigt werden und die hauptpunktverschiebung ignoriert wird, kann sie berechnet werden, wobei das horizontale sichtfeld \(\alpha=2 arctan{\frac{w}{2 f_x}}\) und das seitenverhältnis \(r=\frac{w}{h}\) beträgt.

Es ist zu beachten, dass in diesem prozess die kameraverzerrung nicht berücksichtigt wird, da die kameraverzerrung bei den meisten modernen smartphones sehr gering ist.