2016-04-12 13 views
2

Ich verwende "OpenCV for Unity3d" (es ist dasselbe OpenCV-Paket für Java, aber übersetzt in C# für Unity3d), um eine Augmented Reality-Anwendung zu erstellen für meine Masterarbeit (Informatik).OpenCV-Rotation (Rodrigues) und Übersetzungsvektoren zum Positionieren von 3D-Objekten in Unity3D

Bisher bin ich in der Lage, ein Objekt von Videorahmen mit ORB-Feature-Detektor zu erkennen und auch die 3D-zu-2D-Beziehung mit OpenCVs SolvePnP-Methode zu finden (ich habe auch die Kamerakalibrierung durchgeführt). Von dieser Methode bekomme ich die Translation und Rotation Vektoren. Das Problem tritt bei der Augmentationsphase auf, wo ich ein 3D-Objekt als virtuelles Objekt zeigen und seine Position und Rotation bei jedem Frame aktualisieren muss. OpenCV gibt die Rodrigues-Rotationsmatrix zurück, aber Unity3d arbeitet mit der Quaternion-Rotation, so dass ich die Position und Drehung des Objekts falsch aktualisiere, und ich kann nicht herausfinden, wie das Umstellungsforum (von Rodrigues nach Quaternion) implementiert wird.

gibt es die rvec und TVEC:

Mat rvec = new Mat(); 
    Mat tvec = new Mat(); 
    Mat rotationMatrix = new Mat(); 

    Calib3d.solvePnP (object_world_corners, scene_flat_corners, CalibrationMatrix, DistortionCoefficientsMatrix, rvec, tvec); 
    Calib3d.Rodrigues (rvec, rotationMatrix); 

die Position des virtuellen Objekts aktualisiert:

Vector3 objPosition = new Vector3(); 
    objPosition.x = (model.transform.position.x + (float)tvec.get (0, 0)[0]); 
    objPosition.y = (model.transform.position.y + (float)tvec.get (1, 0)[0]); 
    objPosition.z = (model.transform.position.z - (float)tvec.get (2, 0)[0]); 
    model.transform.position = objPosition; 

ich ein Minuszeichen für die Z-Achse haben, denn wenn man OpenCV ist zu Unty3d System konvertieren koordinieren Sie müssen die Z-Achse invertieren (ich habe die Systemkoordinaten selbst überprüft).

Unity3d Koordinatensystem (Grün ist Y, Rot X und Blau ist Z):

enter image description here

OpenCV Koordinatensystem:

enter image description here

Dazu habe ich die gleiche Sache tat für die Rotationsmatrix und ich aktualisierte die Rotation des virtuellen Objekts.

ps. Ich fand eine ähnliche Frage, aber der Typ, der danach gefragt hat, hat die Lösung nicht eindeutig gepostet.

Danke!

Antwort

3

Sie haben Ihre Rotation 3x3 Matrix direkt nach cv :: solvePnP. Diese Matrix ist, da es sich um eine Rotation handelt, sowohl orthogonal als auch normalisiert. Somit Spalten dieser Matrix sind, um von links nach rechts:

  1. rechten Vektor (X-Achse);
  2. Hoch-Vektor (auf Y-Achse);
  3. Vorwärtsvektor (auf der Z-Achse).

OpenCV verwendet ein rechtshändiges Koordinatensystem. Wenn Sie auf der optischen Achse sitzen, bewegt sich die X-Achse nach rechts, die Y-Achse nach unten und die Z-Achse nach vorne.

Weiterleiten von Vektor F = (fx, fy, fz) und Aufwärtsvektor U = (ux, uy, uz) an Unity. Dies sind die dritte und die zweite Spalte. Keine Notwendigkeit zu normalisieren; Sie sind bereits normalisiert.

In Unity, bauen Sie Ihre quaternion wie folgt aus:

Vector3 f; // from OpenCV 
Vector3 u; // from OpenCV 

// notice that Y coordinates here are inverted to pass from OpenCV right-handed coordinates system to Unity left-handed one 
Quaternion rot = Quaternion.LookRotation(new Vector3(f.x, -f.y, f.z), new Vector3(u.x, -u.y, u.z)); 

Und das ist es ziemlich viel. Hoffe das hilft!

FüR POSITION IM ZUSAMMENHANG KOMMENTAR EDITED

HINWEIS: Z-Achse in OpenCV ist die optische Achse der auf Kamera, die in der Nähe von Mitte durch Bild geht aber nicht genau in der Mitte im Allgemeinen. Zu Ihren Kalibrierungsparametern gehören Cx- und Cy-Parameter. Diese kombiniert ist der 2D-Versatz im Bildraum von der Mitte zu der Stelle, an der die Z-Achse durch das Bild geht. Diese Verschiebung muss berücksichtigt werden, um 3D-Objekte über 2D-Hintergrund abzubilden.

richtige Positionierung in der Einheit erhalten:

// STEP 1 : fetch position from OpenCV + basic transformation 
Vector3 pos; // from OpenCV 
pos = new Vector3(pos.x, -pos.y, pos.z); // right-handed coordinates system (OpenCV) to left-handed one (Unity) 

// STEP 2 : set virtual camera's frustrum (Unity) to match physical camera's parameters 
Vector2 fparams; // from OpenCV (calibration parameters Fx and Fy = focal lengths in pixels) 
Vector2 resolution; // image resolution from OpenCV 
float vfov = 2.0f * Mathf.Atan(0.5f * resolution.y/fparams.y) * Mathf.Rad2Deg; // virtual camera (pinhole type) vertical field of view 
Camera cam; // TODO get reference one way or another 
cam.fieldOfView = vfov; 
cam.aspect = resolution.x/resolution.y; // you could set a viewport rect with proper aspect as well... I would prefer the viewport approach 

// STEP 3 : shift position to compensate for physical camera's optical axis not going exactly through image center 
Vector2 cparams; // from OpenCV (calibration parameters Cx and Cy = optical center shifts from image center in pixels) 
Vector3 imageCenter = new Vector3(0.5f, 0.5f, pos.z); // in viewport coordinates 
Vector3 opticalCenter = new Vector3(0.5f + cparams.x/resolution.x, 0.5f + cparams.y/resolution.y, pos.z); // in viewport coordinates 
pos += cam.ViewportToWorldPoint(imageCenter) - cam.ViewportToWorldPoint(opticalCenter); // position is set as if physical camera's optical axis went exactly through image center 

Sie Bilder von der physischen Kamera direkt auf seiner vorderen Achse zentriert vor virtuellen Kamera abgerufen setzen (skaliert Stumpfes passen), dann haben Sie die richtige 3D-Positionen abgebildet über 2D Hintergrund!

+0

Jetzt machen alle Sinn :) Übrigens denke ich, dass mein Übersetzungsvektor falsch ist. Das 3D-Objekt bewegt sich in der Szene falsch! Was mache ich da falsch? – user43053534

+2

Für die Position, invertieren Sie die Y-Koordinate, wie Sie für Orientierungsvektoren tun müssen. Eine wirklich wichtige Sache zu beachten: Z-Achse ist die optische Achse der Kamera, die im Allgemeinen nicht durch Bildmitte geht. Zu Ihren Kalibrierungsparametern gehören Cx- und Cy-Parameter. Diese sind der 2D-Versatz im Bildraum von der Bildmitte, den die optische Achse der Kamera (Z-Achse) im Bild durchläuft. Wirklich wichtig, 3D Sachen über 2D Hintergrund für AR Anwendungen abzubilden! – RCYR

+0

Also welche Änderungen müssen vorgenommen werden, damit es richtig funktioniert? Nach der Kamerakalibrierung habe ich die intrinsischen Parameter der Kamera erhalten. Wie muss ich sie verwenden, um das virtuelle Objekt richtig zu positionieren? – user43053534

Verwandte Themen