J'ai pour tâche de localiser un objet dans un système de coordonnées 3D. Comme je dois obtenir des coordonnées X et Y presque exactes, j'ai décidé de suivre un marqueur de couleur dont la coordonnée Z est connue et qui sera placé au sommet de l'objet en mouvement, comme la balle orange sur cette image :
D'abord, j'ai fait le calibrage de la caméra pour obtenir les paramètres intrinsèques et ensuite j'ai utilisé cv::solvePnP pour obtenir les vecteurs de rotation et de translation comme dans le code suivant :
std::vector<cv::Point2f> imagePoints;
std::vector<cv::Point3f> objectPoints;
//img points are green dots in the picture
imagePoints.push_back(cv::Point2f(271.,109.));
imagePoints.push_back(cv::Point2f(65.,208.));
imagePoints.push_back(cv::Point2f(334.,459.));
imagePoints.push_back(cv::Point2f(600.,225.));
//object points are measured in millimeters because calibration is done in mm also
objectPoints.push_back(cv::Point3f(0., 0., 0.));
objectPoints.push_back(cv::Point3f(-511.,2181.,0.));
objectPoints.push_back(cv::Point3f(-3574.,2354.,0.));
objectPoints.push_back(cv::Point3f(-3400.,0.,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(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
cv::Rodrigues(rvec,rotationMatrix);
Après avoir eu toutes les matrices, voici l'équation qui peut m'aider à transformer le point d'image en coordonnées mondiales :
où M est cameraMatrix, R - rotationMatrix, t - tvec, et s est une inconnue. Zconst représente la hauteur où se trouve la balle orange, dans cet exemple elle est de 285 mm. Donc, d'abord je dois résoudre l'équation précédente, pour obtenir "s", et ensuite je peux trouver les coordonnées X et Y en sélectionnant le point d'image :
En résolvant ceci, je peux trouver la variable "s", en utilisant la dernière ligne des matrices, parce que Zconst est connu, donc voici le code suivant pour cela :
cv::Mat uvPoint = (cv::Mat_<double>(3,1) << 363, 222, 1); // u = 363, v = 222, got this point using mouse callback
cv::Mat leftSideMat = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint;
cv::Mat rightSideMat = rotationMatrix.inv() * tvec;
double s = (285 + rightSideMat.at<double>(2,0))/leftSideMat.at<double>(2,0));
//285 represents the height Zconst
std::cout << "P = " << rotationMatrix.inv() * (s * cameraMatrix.inv() * uvPoint - tvec) << std::endl;
Après cela, j'ai obtenu le résultat : P = [-2629.5, 1272.6, 285.]
et quand je le compare à la mesure, qui est : Préal = [-2629.6, 1269.5, 285.]
l'erreur est très faible, ce qui est très bien, mais lorsque je déplace cette boîte vers les bords de cette pièce, les erreurs sont peut-être de 20-40 mm et je voudrais améliorer cela. Quelqu'un peut-il m'aider à ce sujet, avez-vous des suggestions ?