对于我的本科论文,我正在使用openCV开发iPhone应用程序以检测多米诺骨牌。该检测在近距离区域效果很好,但是当摄像机倾斜时,很难检测到远处的瓷砖。
解决这个问题的方法是,我想进行一些空间计算。为此,我需要将2D像素值转换为世界坐标,使用 vector 计算新的3D位置,然后将这些坐标转换回2D,然后检查该位置的颜色/形状。
另外,我需要了解增强现实技术的3D位置。
我通过这个链接通过create opencv camera matrix for iPhone 5 solvepnp相机矩阵
我从Core Motion获得的相机的Rotationmatrix。
使用Aruco记号笔将是我的最后选择,因为我无法获得纸张所需的确定效果。
现在我的问题是,当我知道一个有5的平铺瓷砖上的圆圈的位置和距离时,我可以不进行计算吗?
我不需要以毫米/英寸为单位进行测量,我可以使用没有测量值的 vector 。
相机需要能够自由旋转。
我试图将计算sm'= A [R | t] M'求反,以便能够计算3D中的2D坐标。但是我仍然坚持将[R | t]反转,即使在纸上,我也不知道如何在Swift或C++中做到这一点。
我在论坛,书籍等上阅读了很多不同的文章,我完全被困住了,并感谢您能给我的任何帮助/投入。否则我就被搞砸了。
非常感谢你的帮助。
更新:
通过使用Micka建议的SolvePnP,我可以获取相机 Angular “旋转”和平移 vector 。
这意味着,如果您能够识别图像中的多个2D点并知道它们各自的3D世界坐标(以mm,cm,inch,...为单位),则可以使用将已知3D世界坐标中的点投影到坐标上的机制。图像中的各个2D坐标。 (使用opencv projectPoints函数)。
接下来要解决的是从2D到3D坐标的转换,在这里我需要遵循ozlsn的方法,从solvePnP接收矩阵的逆。
更新2:
使用俯 View ,我可以很好地检测到瓷砖及其在3D世界中的位置:
tile from top Down
但是,如果我现在正在倾斜 View ,则我的计算不再起作用。例如,我检查9点组的底部边缘和黑色分隔条的中心是否有90°角。如果Corner1-> Middle Edge->钢筋中心和Corner2-> Middle Edge->钢筋中心均为90°角,则找到中间的钢筋,并可以找到瓷砖的位置。
当 View 成 Angular 时,这些 Angular 将由于透视而移动,例如可以说是130°和50°。 (我稍后会提供图片)。
我现在的想法是制作一个4点的solvePNP(底边加中间),包容solvePNP,然后将所需的点和中心条从2d位置旋转到3d位置(高度应该无关紧要吗?)。然后,我可以检查转换点的 Angular 是否为90°,并进行其他所需的距离计算。
这是我要完成的工作的图像:
Markings for Problem
我首先找到9个点并进行排列。对于每个Edge,我都尝试找到黑条。如上所述,从顶部看,蓝色角,绿色中间边缘与黄色条中心的夹角为90°。
但是,当摄像机倾斜时,该 Angular 不再为90°。我也无法检查两个 Angular 是否都为180°,这会给我带来误报。
因此,我想执行以下步骤:
现在,我想知道如何将这些点的2D坐标转换为3D。我不在乎距离,因为我只是在引用其他距离(例如1.4倍距离Middle-Edge)等进行计算,如果我可以以mm为单位测量距离,那会更好。会给我更好的结果。
通过solvePnP,我得到了可以转换为旋转矩阵的rvec(我相信可以使用Rodrigues())。要测量 Angular ,我的理解是,我不需要应用来自solvePnP的转换(tvec)。
这导致了我的最后一个问题,当使用iPhone时,我不能使用运动检测中的 Angular 预先构建旋转矩阵,而仅使用它来旋转瓦片以从顶部显示它吗?当我不必为每个图块求解PnP(最多可以有约100个图块)时,我觉得这将为我节省很多CPU时间。
查找同形异义词
vector<Point2f> tileDots;
tileDots.push_back(corner1);
tileDots.push_back(edgeMiddle);
tileDots.push_back(corner2);
tileDots.push_back(middle.Dot->ellipse.center);
vector<Point2f> realLivePos;
realLivePos.push_back(Point2f(5.5,19.44));
realLivePos.push_back(Point2f(12.53,19.44));
realLivePos.push_back(Point2f(19.56,19.44));
realLivePos.push_back(Point2f(12.53,12.19));
Mat M = findHomography(tileDots, realLivePos, CV_RANSAC);
cout << "M = "<< endl << " " << M << endl << endl;
vector<Point2f> barPerspective;
barPerspective.push_back(corner1);
barPerspective.push_back(edgeMiddle);
barPerspective.push_back(corner2);
barPerspective.push_back(middle.Dot->ellipse.center);
barPerspective.push_back(possibleBar.center);
vector<Point2f> barTransformed;
if (countNonZero(M) < 1)
{
cout << "No Homography found" << endl;
} else {
perspectiveTransform(barPerspective, barTransformed, M);
}
但是,这给了我错误的值,而且我不知道该去哪里找东西了。
Image Coordinates /image/c67EH.png
World Coordinates /image/Im6M8.png
Points to Transform /image/hHjBM.png
Transformed Points /image/P6lLS.png
您看到我什至太愚蠢,无法在此处发布4张图片吗?
第四个索引项应为x 2007 y 717。
我不知道我在这里做错了什么。
更新3:
我找到了以下Computing x,y coordinate (3D) from image point帖子,它正是我所需要的。我不知道也许有更快的方法来做,但是我无法找到它。目前,我可以进行检查,但是如果算法现在足够健壮,则仍然需要进行测试。
Result with SolvePnP to find bar Center
最佳答案
矩阵[R | t]不是正方形,因此按定义,您不能对其进行求逆。但是,该矩阵存在于投影空间中,它只是R ^ n(欧几里德空间)的扩展,添加了一个“1”作为第(n + 1)个元素。对于兼容性问题,与投影空间 vector 相乘的矩阵在其右下角附加了“1”。即:R变为
[R|0]
[0|1]
在您的情况下[R | t]变为
[R|t]
[0|1]
您可以将其取为
[R'|-Rt]
[0 | 1 ]
其中'是转置。您需要的部分是第一行。
由于手机在3D空间中平移,因此需要考虑像素的距离。这意味着您是否需要以毫米/英寸为单位的距离这个问题的答案是肯定的。仅当您可以假定摄影机平移与深度的比率非常小且称为弱透视摄影机时,答案才会更改。您要解决的问题并非易事。仍然有人在博士学位上对此进行研究。
关于c++ - OpenCV从2D像素获取3D坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48038817/