2016-06-08 23 views
2

Ich habe eine Fischaugenkamera in der Decke und ich möchte einige Punkte auf dem Boden finden. Ich habe den Ursprung meines Referenzsystems (reale Welt) direkt unter der Kamera angegeben und möchte die Position jedes Objekts in Zentimetern wissen. Dieses Bild zeigt dies:Bildpunkte (Pixel) zu realen Welt Koordinaten (Meter)

Reference system - Real world

Zum einen habe ich die Kamerakalibrierung getan, und ich habe das nächste Ergebnis mit einem RMS von 1,11 erhalten:

Undistorted image after calibration

Als Ergebnis der Kalibrierung Ich habe intrinsische Parameter (Kameramatrix) erhalten, also habe ich cv :: solvePnP verwendet, um Rotations- und Translationsvektoren zu erhalten. Für die Anwendung habe ich einige Punkte im unverzerrten Bild (in Pixeln) markiert und sie in der realen Welt gemäß meinem Referenzsystem gemessen.

Zum Beispiel ist der Ursprung in der Mitte eines 1024x768 Bildes, so:

  • Punkt 0: Imagepoint (512, 384) [Pixel] -> ObjectPoint (0,0) [cm]

Der nächste Code zeigt dies:

std::vector<cv::Point2f> imagePointsPix; 
std::vector<cv::Point3f> objectPointsCm; 
imagePointsPix.push_back(cv::Point2f(512.,384.)); 
imagePointsPix.push_back(cv::Point2f(404.,512.));  
imagePointsPix.push_back(cv::Point2f(666.,211.)); 
imagePointsPix.push_back(cv::Point2f(519.,66.)); 

objectPointsCm.push_back(cv::Point3f(0., 0., 0.)); 
objectPointsCm.push_back(cv::Point3f(-80.,-132.,0.)); 
objectPointsCm.push_back(cv::Point3f(120.,188.,0.)); 
objectPointsCm.push_back(cv::Point3f(-40.,268.,0.)); 

cv::Mat rvec(1,3,cv::DataType<double>::type); 
cv::Mat tvec(1,3,cv::DataType<double>::type); 
cv::Mat rotationMatrix(3,3,cv::DataType<double>::type); 

cv::solvePnP(objectPointsCm, imagePointsPix, cameraMatrix, distCoeffs, rvec, tvec, 0, SOLVEPNP_ITERATIVE); 
cv::Rodrigues(rvec,rotationMatrix); 

Jetzt habe ich die Kamera Matrix, die Rotationsmatrix und den traslation Vektor, so von this als Referenz ich bin kann jeden Punkt berechnen, wenn ich seine Position in Pixeln habe. Dies ist der Code:

cv::Mat uvPoint = cv::Mat::ones(3,1,cv::DataType<double>::type); //u,v,1 
uvPoint.at<double>(0,0) = 512.; //img point for which we want its real coordinates 
uvPoint.at<double>(1,0) = 384.; 
cv::Mat tempMat, tempMat2; 
double s; 
tempMat = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint; 
tempMat2 = rotationMatrix.inv() * tvec; 
s = 0 + tempMat2.at<double>(2,0); //before 0 it was 285, which represents the height Zconst 
s /= tempMat.at<double>(2,0); 
std::cout << "P = " << rotationMatrix.inv() * (s * cameraMatrix.inv() * uvPoint - tvec) << std::endl; 

ich diese Ergebnisse für die gleichen Punkte ich für den Erhalt meiner Parameter verwendet:

  • Punkt 0 -> (0,213, 3,391) (es sollte sein (0,0)) ERROR: 3,69 cm
  • Punkt 1 -> (-68,28, -112,82) (es soll (-80, -132)) seine ERROR: 17,49 cm
  • Punkt 2 - -> (84.48, 1 37.61) (es sein soll (120, 188)) ERROR: 49,62 cm

Die restlichen Punkte auch einen Fehler zeigen, zu groß ... Ich habe mehr Punkte verwendet, aber die Ergebnisse nicht verbessern. Ich weiß nicht, wo ich falsch gelaufen bin, könnte mir jemand helfen?

Vielen Dank im Voraus.

Antwort

0

Schließlich habe ich herausgefunden, dass der Fehler durch die Verzerrungskoeffizienten, d. H. Meine Kalibrierung verursacht wurde. Ich setzte die cameraMatrix auf die Identity-Matrix (eye (3)) und die distCoefficients auf NULL, so dass solvePNP annahm, ich hätte eine perfekte Kamera. Unter Verwendung dieses Ansatzes erhielt ich einen viel geringeren Fehler. Ich muss eine bessere Kalibrierung vornehmen.

+0

Es besteht die Möglichkeit, dass die Kalibrierung in Ordnung war und dass Sie das Bild effektiv zweimal entschachtelt haben (siehe meine Antwort für die Erklärung). – rob3c

1

Es sieht so aus, als ob Sie Ihr Bild zweimal effektiv aus der Perspektive solvePNP entschlüsseln können. Dies liegt daran, dass die Verzerrungskoeffizienten zusammen mit Punktkorrespondenzen übergeben werden, die bereits von einem unverzerrten Bild abgeleitet sind.

Versuchen Sie, die tatsächliche Kameramatrix von Ihrer Kalibrierung an solvePNP anstelle einer Identitätsmatrix zu übergeben, aber übergeben Sie NULL für die Verzerrungskoeffizienten, um die doppelte Verzerrung zu vermeiden.