OpenCV+;OpenGL使用solvePnP相机姿势-对象与检测到的标记偏移

OpenCV+;OpenGL使用solvePnP相机姿势-对象与检测到的标记偏移,opencv,opengl-es,augmented-reality,Opencv,Opengl Es,Augmented Reality,我在iOS应用程序中遇到了一个问题,我试图使用solvePnP获取视图矩阵,并使用现代OpenGL渲染3d立方体。当我的代码试图直接在检测到的标记上渲染3d立方体时,它似乎以与标记的某个偏移量进行渲染(例如,请参见视频) (在图像的右下角,您可以看到跟踪器标记周围的单应性的opencv渲染。屏幕的其余部分是摄影机输入帧的opengl渲染和位置(0,0,0)处的3d立方体) 每当我移动标记时,立方体都会正确地旋转和平移,尽管很明显平移的比例有所不同(即,如果我在现实世界中移动标记5厘米,它在屏幕

我在iOS应用程序中遇到了一个问题,我试图使用solvePnP获取视图矩阵,并使用现代OpenGL渲染3d立方体。当我的代码试图直接在检测到的标记上渲染3d立方体时,它似乎以与标记的某个偏移量进行渲染(例如,请参见视频)

(在图像的右下角,您可以看到跟踪器标记周围的单应性的opencv渲染。屏幕的其余部分是摄影机输入帧的opengl渲染和位置(0,0,0)处的3d立方体)

每当我移动标记时,立方体都会正确地旋转和平移,尽管很明显平移的比例有所不同(即,如果我在现实世界中移动标记5厘米,它在屏幕上几乎不会移动1厘米)

以下是我认为可能产生错误的代码相关部分:

从单应性提取视图矩阵:

AVCaptureDevice *deviceInput = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceFormat *format = deviceInput.activeFormat;
CMFormatDescriptionRef fDesc = format.formatDescription;
CGSize dim = CMVideoFormatDescriptionGetPresentationDimensions(fDesc, true, true);

const float cx = float(dim.width) / 2.0;
const float cy = float(dim.height) / 2.0;

const float HFOV = format.videoFieldOfView;
const float VFOV = ((HFOV)/cx)*cy;

const float fx = abs(float(dim.width) / (2 * tan(HFOV / 180 * float(M_PI) / 2)));
const float fy = abs(float(dim.height) / (2 * tan(VFOV / 180 * float(M_PI) / 2)));


Mat camIntrinsic = Mat::zeros(3, 3, CV_64F);
camIntrinsic.at<double>(0, 0) = fx;
camIntrinsic.at<double>(0, 2) = cx;
camIntrinsic.at<double>(1, 1) = fy;
camIntrinsic.at<double>(1, 2) = cy;
camIntrinsic.at<double>(2, 2) = 1.0;

std::vector<cv::Point3f> object3dPoints;
object3dPoints.push_back(cv::Point3f(-0.5f,-0.5f,0));
object3dPoints.push_back(cv::Point3f(+0.5f,-0.5f,0));
object3dPoints.push_back(cv::Point3f(+0.5f,+0.5f,0));
object3dPoints.push_back(cv::Point3f(-0.5f,+0.5f,0));


cv::Mat raux,taux;
cv::Mat Rvec, Tvec;
cv::solvePnP(object3dPoints, mNewImageBounds, camIntrinsic, Mat(),raux,taux); //mNewImageBounds are the 4 corner of the homography detected by perspectiveTransform (the green outline seen in the image)
raux.convertTo(Rvec,CV_32F);
taux.convertTo(Tvec ,CV_64F);

Mat Rot(3,3,CV_32FC1);
Rodrigues(Rvec, Rot);

// [R | t] matrix
Mat_<double> para = Mat_<double>::eye(4,4);
Rot.convertTo(para(cv::Rect(0,0,3,3)),CV_64F);
Tvec.copyTo(para(cv::Rect(3,0,1,3)));

Mat cvToGl = Mat::zeros(4, 4, CV_64F);
cvToGl.at<double>(0, 0) = 1.0f;
cvToGl.at<double>(1, 1) = -1.0f; // Invert the y axis
cvToGl.at<double>(2, 2) = -1.0f; // invert the z axis
cvToGl.at<double>(3, 3) = 1.0f;

para = cvToGl * para;

Mat_<double> modelview_matrix;
Mat(para.t()).copyTo(modelview_matrix); // transpose to col-major for OpenGL
glm::mat4 openGLViewMatrix;
for(int col = 0; col < modelview_matrix.cols; col++)
{
    for(int row = 0; row < modelview_matrix.rows; row++)
    {
        openGLViewMatrix[col][row] = modelview_matrix.at<double>(col,row);
    }
}
AVCaptureDevice*deviceInput=[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceFormat*格式=设备输入.activeFormat;
CMFormatDescriptionRef fDesc=format.formatDescription;
CGSize dim=CMVideoFormatDescriptionGetPresentationDimensions(fDesc,true,true);
常数浮点cx=浮点(尺寸宽度)/2.0;
常数浮动cy=浮动(尺寸高度)/2.0;
const float HFOV=format.videoFieldOfView;
常量浮点VFOV=((HFOV)/cx)*cy;
常数浮点数fx=abs(浮点数(尺寸宽度)/(2*tan(HFOV/180*float(M_PI)/2));
常数浮球fy=abs(浮球(尺寸高度)/(2*tan(VFOV/180*float(M_PI)/2));
Mat CAMU=Mat::零(3,3,CV_64F);
(0,0)=fx;
在(0,2)=cx;
(1,1)=fy;
在(1,2)=cy;
(2,2)=1.0;
std::向量对象点;
object3dPoints.push_back(cv::Point3f(-0.5f,-0.5f,0));
object3dPoints.push_back(cv::Point3f(+0.5f,-0.5f,0));
object3dPoints.push_back(cv::Point3f(+0.5f,+0.5f,0));
object3dPoints.push_back(cv::Point3f(-0.5f,+0.5f,0));
cv::Mat raux,taux;
cv::Mat Rvec,Tvec;
cv::solvePnP(object3dPoints,MnewAgeBounds,CamInquired,Mat(),raux,taux);//MnewAgeBounds是透视变换检测到的单应性的4个角(图像中显示的绿色轮廓)
劳克斯·康弗托(Rvec,CV_32F);
taux.convertTo(Tvec,CV_64F);
垫腐病(3,3,CV_32FC1);
罗德里格斯(Rvec,Rot);
//[R | t]矩阵
Mat_upara=Mat_upara::眼睛(4,4);
Rot.convertTo(第(cv::Rect(0,0,3,3))段),cv_64F);
copyTo(para(cv::Rect(3,0,1,3));
Mat cvToGl=Mat::零(4,4,CV_64F);
(0,0)时的cvToGl=1.0f;
cvToGl.at(1,1)=-1.0f;//反转y轴
cvToGl.at(2,2)=-1.0f;//反转z轴
(3,3)处的cvToGl=1.0f;
para=cvToGl*para;
模型视图矩阵;
Mat(para.t()).copyTo(modelview_matrix);//转置到OpenGL的col MAJURE
glm::mat4 openGLViewMatrix;
对于(int col=0;col
我确保相机内在矩阵包含正确的值,这部分将opencv矩阵转换为opengl视图矩阵,我认为这是正确的,因为立方体在正确的方向上平移和旋转

计算视图矩阵后,我使用它绘制立方体,如下所示:

_projectionMatrix = glm::perspective<float>(radians(60.0f), fabs(view.bounds.size.width / view.bounds.size.height), 0.1f, 100.0f);
_cube_ModelMatrix = glm::translate(glm::vec3(0,0,0));
const mat4 MVP = _projectionMatrix * openGLViewMatrix * _cube_ModelMatrix;
glUniformMatrix4fv(glGetUniformLocation(_cube_program, "ModelMatrix"), 1, GL_FALSE, value_ptr(MVP));

glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
\u projectionMatrix=glm::perspective(弧度(60.0f)、fabs(view.bounds.size.width/view.bounds.size.height)、0.1f、100.0f);
_cube_ModelMatrix=glm::translate(glm::vec3(0,0,0));
const mat4 MVP=\u projectionMatrix*openGLViewMatrix*\u cube\u ModelMatrix;
glUniformMatrix4fv(glGetUniformLocation(_cube_程序,“ModelMatrix”),1,GL_FALSE,value_ptr(MVP));
GLD元素(GLU三角形,36,GLU无符号整数,缓冲区偏移量(0));

有人能发现我的错误吗?

您应该创建透视矩阵,如下所述:

以下是快速代码:

const float fx = intrinsicParams(0, 0); // Focal length in x axis
const float fy = intrinsicParams(1, 1); // Focal length in y axis
const float cx = intrinsicParams(0, 2); // Primary point x
const float cy = intrinsicParams(1, 2); // Primary point y

projectionMatrix(0, 0) = 2.0f * fx;
projectionMatrix(0, 1) = 0.0f;
projectionMatrix(0, 2) = 0.0f;
projectionMatrix(0, 3) = 0.0f;

projectionMatrix(1, 0) = 0.0f;
projectionMatrix(1, 1) = 2.0f * fy;
projectionMatrix(1, 2) = 0.0f;
projectionMatrix(1, 3) = 0.0f;

projectionMatrix(2, 0) = 2.0f * cx - 1.0f;
projectionMatrix(2, 1) = 2.0f * cy - 1.0f;
projectionMatrix(2, 2) = -(far + near) / (far - near);
projectionMatrix(2, 3) = -1.0f;

projectionMatrix(3, 0) = 0.0f;
projectionMatrix(3, 1) = 0.0f;
projectionMatrix(3, 2) = -2.0f * far * near / (far - near);
projectionMatrix(3, 3) = 0.0f;
有关内在矩阵的更多信息: