![](/img/trans.png)
[英]Perform a translation / rotation of a CMSampleBuffer OpenGL Swift
[英]OpenCV: rotation/translation vector to OpenGL modelview matrix
我正在尝试使用OpenCV来做一些基本的增强现实。 我正在采用的方法是使用findChessboardCorners
从相机图像中获取一组点。 然后,我沿着z = 0平面创建一个3D四边形,并使用solvePnP
在成像点和平面点之间获得单应性。 从那以后,我想我应该能够设置一个模型视图矩阵,这将允许我在图像顶部渲染一个具有正确姿势的立方体。
solvePnP
的文档说它输出一个旋转矢量“(与[平移矢量一起])将点从模型坐标系带到摄像机坐标系。” 我认为这与我想要的相反; 由于我的四边形在z = 0的平面上,我想要一个模型视图矩阵,它将该四边形转换为适当的3D平面。
我认为通过以相反的顺序执行相反的旋转和平移,我可以计算出正确的模型视图矩阵,但这似乎不起作用。 虽然渲染的对象(立方体)确实随着摄像机图像一起移动,并且看起来在翻译时大致正确,但旋转根本不起作用; 当它应该仅在一个轴上旋转时,它在多个轴上,有时在错误的方向上旋转。 这是我到目前为止所做的事情:
std::vector<Point2f> corners;
bool found = findChessboardCorners(*_imageBuffer, cv::Size(5,4), corners,
CV_CALIB_CB_FILTER_QUADS |
CV_CALIB_CB_FAST_CHECK);
if(found)
{
drawChessboardCorners(*_imageBuffer, cv::Size(6, 5), corners, found);
std::vector<double> distortionCoefficients(5); // camera distortion
distortionCoefficients[0] = 0.070969;
distortionCoefficients[1] = 0.777647;
distortionCoefficients[2] = -0.009131;
distortionCoefficients[3] = -0.013867;
distortionCoefficients[4] = -5.141519;
// Since the image was resized, we need to scale the found corner points
float sw = _width / SMALL_WIDTH;
float sh = _height / SMALL_HEIGHT;
std::vector<Point2f> board_verts;
board_verts.push_back(Point2f(corners[0].x * sw, corners[0].y * sh));
board_verts.push_back(Point2f(corners[15].x * sw, corners[15].y * sh));
board_verts.push_back(Point2f(corners[19].x * sw, corners[19].y * sh));
board_verts.push_back(Point2f(corners[4].x * sw, corners[4].y * sh));
Mat boardMat(board_verts);
std::vector<Point3f> square_verts;
square_verts.push_back(Point3f(-1, 1, 0));
square_verts.push_back(Point3f(-1, -1, 0));
square_verts.push_back(Point3f(1, -1, 0));
square_verts.push_back(Point3f(1, 1, 0));
Mat squareMat(square_verts);
// Transform the camera's intrinsic parameters into an OpenGL camera matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Camera parameters
double f_x = 786.42938232; // Focal length in x axis
double f_y = 786.42938232; // Focal length in y axis (usually the same?)
double c_x = 217.01358032; // Camera primary point x
double c_y = 311.25384521; // Camera primary point y
cv::Mat cameraMatrix(3,3,CV_32FC1);
cameraMatrix.at<float>(0,0) = f_x;
cameraMatrix.at<float>(0,1) = 0.0;
cameraMatrix.at<float>(0,2) = c_x;
cameraMatrix.at<float>(1,0) = 0.0;
cameraMatrix.at<float>(1,1) = f_y;
cameraMatrix.at<float>(1,2) = c_y;
cameraMatrix.at<float>(2,0) = 0.0;
cameraMatrix.at<float>(2,1) = 0.0;
cameraMatrix.at<float>(2,2) = 1.0;
Mat rvec(3, 1, CV_32F), tvec(3, 1, CV_32F);
solvePnP(squareMat, boardMat, cameraMatrix, distortionCoefficients,
rvec, tvec);
_rv[0] = rvec.at<double>(0, 0);
_rv[1] = rvec.at<double>(1, 0);
_rv[2] = rvec.at<double>(2, 0);
_tv[0] = tvec.at<double>(0, 0);
_tv[1] = tvec.at<double>(1, 0);
_tv[2] = tvec.at<double>(2, 0);
}
然后在绘图代码中......
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, -tv[1], -tv[0], -tv[2]);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -rv[0], 1.0f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -rv[1], 0.0f, 1.0f, 0.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -rv[2], 0.0f, 0.0f, 1.0f);
我正在渲染的顶点创建一个围绕原点的单位长度的立方体(即沿着每条边从-0.5到0.5)。我知道OpenGL翻译函数以“逆序”执行变换,所以上面应该沿着z,y,然后x轴,然后翻译它。 然而,似乎它首先被翻译然后轮换,所以也许Apple的GLKMatrix4
工作方式不同?
这个问题看起来与我的非常相似,特别是coder9的答案似乎可能或多或少都是我正在寻找的。 但是,我尝试了它并将结果与我的方法进行了比较,我在两种情况下得到的矩阵是相同的。 我觉得这个答案是正确的,但我错过了一些关键的细节。
我不是IOS程序员,所以这个答案可能会产生误导! 如果问题不是应用旋转和平移的顺序,那么建议使用更简单和更常用的坐标系。
角矢量中的点在图像的左上角具有原点(0,0),并且y轴朝向图像的底部。 通常从数学中我们习惯于考虑坐标系,其中心位于原点,y轴位于图像顶部。 从您正在推入board_verts的坐标我猜你犯了同样的错误。 如果是这种情况,可以通过以下方式轻松转换角落的位置:
for (i=0;i<corners.size();i++) {
corners[i].x -= width/2;
corners[i].y = -corners[i].y + height/2;
}
然后你调用solvePnP()。 调试这并不困难,只需打印四个角的位置和估计的R和T,看看它们是否有意义。 然后,您可以继续执行OpenGL步骤。 请告诉我它是怎么回事。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.