AR with OpenCV & OpenGL
AR with OpenCV & OpenGL
这是一个问题:我写了一个代码,在带有图纸的纸上显示OpenGL茶壶。为此,我跟踪纸张的四个角(使用冲浪检测及匹配,然后计算同型矩阵,然后移动拐角位置的平均位置以减少抖动)。角坐标用于计算固有的&相机的外部矩阵(分别使用calibrateCamera()
和solvePnP()
)。然后使用Rodrigues()
计算旋转矩阵。之后,我使用decomposeProjectionMatrix()
计算了旋转角度。这是代码的OPENCV部分:
...
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
是模板图像中的角坐标([1 1],[img宽度1],[IMG宽度IMG高度],[1 IMG高度])。SceneCorners是使用同型矩阵计算的网络摄像头框架中的角落坐标。功能getAngles()
如下:
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);
}
然后,我设置OpenGL模型视图矩阵的元素如下:
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
是纸的中心坐标,通过取4个角的平均值获得。modelViewMat[12]
和modelViewMat[13]
中的值是通过映射像素坐标([1 640],[1 480])到([-1 1],[1 -1])获得的。代码的OpenGL部分:
...
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);
我在X轴周围旋转-45度-45度,使其看起来"坐着"在纸上。结果是:如果我在桌子上翻译纸张,则茶壶在纸上的位置或多或少正确(在同一地点)。如果我旋转纸张,茶壶将正确遵循旋转(y轴周围),但是位置不再正确。问题是:如何始终在纸张的同一地点"固定"茶壶?我已经尝试直接在OpenGL模型视图矩阵中使用Rodrigues()
和solvePnP()
的结果(如OpenCV OpenGl:使用SolvePNP的正确相机姿势),但结果不正确。
几天前,基于http://blog.yarrago.com/2011/08/introduction-to-aig-aigmented-reality.html的代码解决了此问题。要正确显示3D对象,首先设置OpenGL投影矩阵,然后是OpenGL模型视图矩阵。投影矩阵的元素是从摄像机的固有矩阵计算的,如下所示:
calibrateCamera(objPoints, scenePoints, Size(640,480), camMtx, distortCoeff, RVecs, tVecs);
...
projectionMat[0] = 2*camMtx.at<double>(0,0)/frameW;
projectionMat[1] = 0;
projectionMat[2] = 0;
projectionMat[3] = 0;
projectionMat[4] = 0;
projectionMat[5] = 2*camMtx.at<double>(1,1)/frameH;
projectionMat[6] = 0;
projectionMat[7] = 0;
projectionMat[8] = 1 - 2*camMtx.at<double>(0,2)/frameW;
projectionMat[9] = -1 + (2*camMtx.at<double>(1,2) + 2)/frameH;
projectionMat[10] = (zNear + zFar)/(zNear - zFar);
projectionMat[11] = -1;
projectionMat[12] = 0;
projectionMat[13] = 0;
projectionMat[14] = 2*zNear*zFar/(zNear - zFar);
projectionMat[15] = 0;
frameW
和frameH
分别为640
和480
。zNear
是0.1
,zFar
是100
。
OpenGL模型视图矩阵的元素是从旋转矩阵和翻译向量计算的(从solvePnP()
和Rodrigues()
获得)。为了获得3D对象的正确定位,在计算模型视图矩阵之前,需要对翻译向量进行转换。
// Offset value to move the translation vector
double offsetC[3][1] = {424, 600, 0};
Mat offset(3, 1, CV_64F, offsetC);
...
solvePnP(objCorners, sceneCorners, camMtx, distortCoeff, RVec, tVec);
Rodrigues(RVec, rotMtx);
tVec = tVec + rotMtx*offset; // Move tVec to refer to the center of the paper
tVec = tVec / 250.0; // Converting pixel coordinates to OpenGL world coordinates
...
modelviewMat[0] = rotMtx.at<double>(0,0);
modelviewMat[1] = -rotMtx.at<double>(1,0);
modelviewMat[2] = -rotMtx.at<double>(2,0);
modelviewMat[3] = 0;
modelviewMat[4] = rotMtx.at<double>(0,1);
modelviewMat[5] = -rotMtx.at<double>(1,1);
modelviewMat[6] = -rotMtx.at<double>(2,1);
modelviewMat[7] = 0;
modelviewMat[8] = rotMtx.at<double>(0,2);
modelviewMat[9] = -rotMtx.at<double>(1,2);
modelviewMat[10] = -rotMtx.at<double>(2,2);
modelviewMat[11] = 0;
modelviewMat[12] = tVec.at<double>(0,0);
modelviewMat[13] = -tVec.at<double>(1,0);
modelviewMat[14] = -tVec.at<double>(2,0);
modelviewMat[15] = 1;
offsetC
的数值是纸的中心的像素坐标。然后,代码的OpenGL部分是:
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projectionMat);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(modelviewMat);
glRotatef(90, -1.0, 0.0, 0.0); // Rotate the teapot first so that it will be displayed correctly on the paper
glutSolidTeapot(1.0);
茶壶正确定位的重要一件事是tVec
的转换。
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 尝试导入pybind-opencv模块时出现libgtk错误
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- OpenCv 边框顶部和左侧 OpenGL 帧 c++
- AR with OpenCV & OpenGL
- Opencv Mat to opengl with OSVR
- 使用opengl和opencv加载纹理
- Qt 中 OpenCV "Can't load OpenGL extension [glBindBuffer] in function IntGetProcAddress"例外
- 纹理绑定:OpenGL+OpenCV
- OpenGL Support with OpenCV-3.0
- Opencv在Opengl中的应用
- 使用 OpenCV 为 OpenGL 加载纹理
- OpenGL与OpenCV结合的计算机视觉教程
- 使用OpenGL在OpenCV中绘制
- OpenCV-OpenGL互操作性
- 将OpenGL纹理转换为OpenCV矩阵
- OpenCV:是否可以使用它执行openGL像素着色
- 将灰度OpenCV图像传递到OpenGL纹理