将 std::vector<cv::P oint3f> 乘以 cv::Mat?

Multiply std::vector<cv::Point3f> by a cv::Mat?

本文关键字:cv gt 乘以 Mat oint3f lt std vector      更新时间:2023-10-16

如上所述,我有一个cv :: point3f的std ::向量。我有一个转换矩阵。我需要将向量乘以垫子的倒数。

我的垫子:( T是由此产生的转换(

cv::Mat R(3,3,rvec.type());
cv::Rodrigues(rvec, R); // R is 3x3
cv::Mat T(4, 4, R.type()); // T is 4x4
T(cv::Range(0, 3), cv::Range(0, 3)) = R * 1; // copies R into T
T(cv::Range(0, 3), cv::Range(3, 4)) = tvec * 1; // copies tvec into T
float *p = T.ptr<float>(3);
p[0] = p[1] = p[2] = 0; p[3] = 1;

我的向量:

std::vector<cv::Point3f> objectPoints;

我尝试过:

cv::Mat V = T.inv() * cv::Mat(objectPoints, false) 
V.copyTo(cv::Mat(objectPoints, false));

(断言失败,键入错误(

for (int i = 0; i < objectPoints.size(); i++)
{
    cv::Mat dst = cv::Mat(objectPoints[i], false);  
    dst = -T*dst; //USE MATRIX ALGEBRA 
//  cv::Point3f tmp3 = cv::Point3f(dst(0, 0), dst(1, 0), dst(2, 0));
}

(断言失败(

    std::vector<cv::Point3f> p3d;
perspectiveTransform(objectPoints, p3d, -T);

(运行,但值不正确(

cv::transform(objectPoints, p3d, -T);

(断言错误(

正确的方法(如果有办法!(?

谢谢。

正如里克·M(Rick M.要执行仅使用一个矩阵乘法(即使用4x4组合的R-T矩阵(进行转换,您首先必须表示均匀坐标中的点,这基本上仅涉及将1作为您点的第四个元素固定。转换后,您将新点除以第四元素以保持其值为1。这是3D-3D变换的不错源,在幻灯片14上讨论了均匀的坐标。

由于OpenCV没有Point4F类,因此在创建点的垫子表格时必须添加此1。这是未经测试的,但可能起作用:

std::vector<cv::Point3f> dstPoint;
for (int i = 0; i < objectPoints.size(); i++) {
    // Convert Point3f to 4x1 Mat (in homogeneous coordinates, with 1 as 4th element)
    cv::Point3f pt = objectPoints[i];
    cv::Mat ptMat = (cv::Mat_<float>(4,1) << pt.x, pt.y, pt.z, 1);
    // Perform matrix multiplication and store as Mat_ for easy element access
    cv::Mat_<float> dstMat(T.inv() * ptMat); 
    // Divide first three resulting elements by the 4th (homogenizing 
    // the point) and store as Point3f
    float scale = dstMat(0,3);
    cv::Point3f dst(dstMat(0,0)/scale, dstMat(0,1)/scale, dstMat(0,2)/scale);
    dstPoints.push_back(dst)
}

会测试,但是我在工作,并且在这台计算机上没有OpenCV。

更新:

复制到t时,请尝试使用:

cv::Mat T(4, 4, cv::DataType<float>::type);
cv::Mat rot   = T(cv::Range(0, 3), cv::Range(0, 3));
cv::Mat trans = T(cv::Range(0, 3), cv::Range(3, 4));
R.copyTo(rot);
tvec.copyTo(trans);

基于DCSMITH的答案,我可以工作。我必须做出这个小的改变:

cv::Mat T(4, 4, cv::DataType<float>::type);
R.copyTo(T(cv::Rect(0, 0, 3, 3)));
tvec.copyTo(T(cv::Rect(3, 0, 1, 3)));

使整个功能看起来像:

std::vector<cv::Point3f> p3d;
cv::Mat R(3,3, cv::DataType<float>::type);
cv::Rodrigues(rvec, R); // R is 3x3
cv::Mat T(4, 4, cv::DataType<float>::type);
R.copyTo(T(cv::Rect(0, 0, 3, 3)));
tvec.copyTo(T(cv::Rect(3, 0, 1, 3)));
float *p = T.ptr<float>(3);
p[0] = p[1] = p[2] = 0; p[3] = 1;

std::vector<cv::Point3f> dstPoint;
for (int i = 0; i < objectPoints.size(); i++) {
    cv::Point3f pt = objectPoints[i];
    cv::Mat ptMat = (cv::Mat_<float>(4, 1) << pt.x, pt.y, pt.z, 1);
    // Perform matrix multiplication and store as Mat_ for easy element access
    cv::Mat_<float> dstMat = T.inv() * ptMat;
    // Divide first three resulting elements by the 4th (homogenizing 
    // the point) and store as Point3f
    float scale = dstMat(0, 3);
    cv::Point3f dst(dstMat(0, 0) / scale, dstMat(0, 1) / scale, dstMat(0, 2) / scale);
    p3d.push_back(dst);
}

谢谢您的帮助!