Voici le problème: J'ai écrit un code pour afficher la théière OpenGL sur une feuille de papier avec dessin. Pour cela, je parcours les 4 coins du papier (en utilisant la détection SURF & correspondant suivi par le calcul de la matrice d'homographie, puis la moyenne mobile de la position des coins pour réduire la gigue). Les coordonnées des coins sont utilisées pour calculer les matrices extrinsèques intrinsèques de la caméra (en utilisant calibrateCamera()
et solvePnP()
, respectivement). La matrice de rotation est ensuite calculée en utilisant Rodrigues()
. Ensuite, j'ai calculé les angles de rotation en utilisant decomposeProjectionMatrix()
. Voici la partie OpenCV du code:AR avec OpenCV & OpenGL
...
objPoints.push_back(objCorners);
scenePoints.push_back(sceneCorners);
calibrateCamera(objPoints, scenePoints, Size(640,480), camMtx, distortCoeff, RVecs, tVecs);
solvePnP(objCorners, sceneCorners, camMtx, distortCoeff, RVec, tVec);
Rodrigues(RVec, rotMtx);
getAngles(rotMtx, rotAngles);
objCorners
sont les coins coordonnées dans l'image modèle ([1 1], [img largeur 1], [img largeur img hauteur], [1 hauteur img]). sceneCorners sont les coordonnées des coins dans le cadre de la webcam, calculées à l'aide de la matrice d'homographie. La fonction getAngles()
est la suivante:
void getAngles(Mat &rotCamMtx, Vec3d &angles)
{
Mat camMtx, rotMtx, transVec, rotMtxX, rotMtxY, rotMtxZ;
double *r = rotCamMtx.ptr<double>();
double projMtx[12] = {r[0], r[1], r[2], 0,
r[3], r[4], r[5], 0,
r[6], r[7], r[8], 0};
decomposeProjectionMatrix(Mat(3,4,CV_64FC1,projMtx), camMtx, rotMtx, transVec, rotMtxX, rotMtxY, rotMtxZ, angles);
}
Ensuite, je mets l'élément de la matrice de vue du modèle OpenGL comme suit:
modelViewMat[0] = 1.0;
modelViewMat[1] = 0.0;
modelViewMat[2] = 0.0;
modelViewMat[3] = 0.0;
modelViewMat[4] = 0.0;
modelViewMat[5] = 1.0;
modelViewMat[6] = 0.0;
modelViewMat[7] = 0.0;
modelViewMat[8] = 0.0;
modelViewMat[9] = 0.0;
modelViewMat[10] = 1.0;
modelViewMat[11] = 0.0;
modelViewMat[12] = 2*matCenter.x/639 - 641/639;
modelViewMat[13] = 481/479 - 2*matCenter.y/479;
modelViewMat[14] = -0.25;
modelViewMat[15] = 1.0;
matCenter
est le centre de coordonnées du papier, obtenue en prenant la moyenne les 4 coins. Les valeurs dans modelViewMat[12]
et modelViewMat[13]
sont obtenues en mappant les coordonnées de pixels ([1 640], [1 480]) à ([-1 1], [1 -1]). La partie OpenGL du code:
...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd(modelViewMat);
glRotated(-45, 1.0, 0.0, 0.0);
glRotated(rotAngles[2], 0.0, 1.0, 0.0);
glShadeModel(GL_SMOOTH);
glColor3f(1.0, 1.0, 1.0);
glutSolidTeapot(0.3);
Je tourné la théière -45 degrés autour de l'axe x pour le rendre apparaît « assis » sur le papier. Le résultat est le suivant: si je traduis le papier sur le bureau, l'emplacement de la théière sur le papier est plus ou moins correct (au même endroit). Si je fais tourner le papier, la théière suivra la rotation correctement (autour de l'axe y), mais l'emplacement n'est plus correct. La question est: comment "épingler" la théière toujours au même endroit du papier? J'ai essayé d'utiliser le résultat de Rodrigues()
et solvePnP()
directement dans la matrice de vue de modèle OpenGL (comme suggéré dans OpenCV + OpenGL: proper camera pose using solvePnP), mais le résultat est incorrect.