繁体   English   中英

乘以std :: vector <cv::Point3f> 通过cv :: Mat?

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

如上所述,我有一个cv :: Point3f的std :: vector。 我有一个转换矩阵。 我需要将矢量乘以Mat的倒数。

我的垫子:( 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);

(断言错误)

这样做的正确方法是什么(如果有办法!)

谢谢。

正如Rick M.指出的那样,你试图将4x4矩阵乘以长度为3的点。 要使用一个矩阵乘法(即使用4x4组合RT矩阵)执行变换,首先必须在齐次坐标中表示点,这基本上只涉及将1作为点的第4个元素; 在转换之后,将新点除以第4个元素以将其值保持为1. 这是 3D-3D转换一个很好的来源,在幻灯片14上讨论了均匀坐标。

由于OpenCV没有Point4f类,因此当您创建该点的Mat形式时,您必须添加此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);
}

谢谢您的帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM