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

时间:2017-06-28 14:05:51

标签: c++ opencv vector

如上所述,我有一个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);

(断言错误)

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

谢谢。

2 个答案:

答案 0 :(得分:2)

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

由于OpenCV没有Point4f类,因此当您创建该点的Mat形式时,您必须添加此1。这是未经测试但可能有效:

def listen_rfid(self):
    dbHost = 'localhost'
    dbName = 'python'
    dbUser = 'python'
    dbPass = 'PASSWORD'

    dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName) # ToDo: This needs some error handling for if MySQL has gone away, and reconnect.
    cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)

    from evdev import InputDevice
    from select import select

    keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX"
    dev = InputDevice('/dev/input/event0')
    rfid_presented = ""

    while True:
       r,w,x = select([dev], [], [])
       for event in dev.read():
            if event.type==1 and event.value==1:
                    if event.code==28:
                        #print("RFID: " + str(rfid_presented))

                        cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (rfid_presented))

                        if cur.rowcount != 1:
                            #print("ACCESS DENIED")
                            ttk.Label(self.tk, text="ACCESS DENIED").pack()
                        else:
                            user_info = cur.fetchone()
                            #print("Welcome %s!!" % (user_info['name']))
                            ttk.Label(self.tk, text="Welcome %s!!" % (user_info['name'])).pack()

                        rfid_presented = ""
                    else:
                        rfid_presented += keys[ event.code ]

测试,但我在工作,并没有在这台电脑上安装OpenCV。

<强>更新

复制到T时,请尝试以下方法:

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)
}

答案 1 :(得分:1)

根据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);
}

感谢您的帮助!