如上所述,我有一个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);
(断言错误)
这样做的正确方法是什么(如果有办法!)?
谢谢。
答案 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);
}
感谢您的帮助!