使用solvePnP()与SOLVEPNP_IPPE_SQUARE的ARKit相机位姿估计异常问题
解决ARKit+OpenCV solvePnP获取相机位置的距离错误问题
看了你的代码和日志输出,你这里犯了两个典型的solvePnP使用错误,直接导致了translationVector.z的结果完全不符合预期,下面逐一拆解并给出修复方案:
1. 图像点坐标转换错误
Vision框架检测到的二维码角点(visionResult.topLeft等)本身就是像素坐标系下的原始坐标,不需要再乘以图像分辨率。你的convertImagePoints函数错误地对坐标做了放大,导致图像点位置完全偏离,这会直接让solvePnP计算出错误的姿态。
修复代码:
修改convertImagePoints方法,直接使用原始CGPoint的x和y值:
+ (vector<Point2f>) convertImagePoints: (NSArray<NSValue *> *) array toSize: (CGSize) size { vector<Point2f> points; for (NSValue * value in array) { CGPoint point = [value CGPointValue]; // 移除错误的分辨率乘法,直接使用像素坐标 points.push_back(Point2f(point.x, point.y)); } return points; }
2. 图像点与物体点的顺序不匹配
solvePnP要求图像点数组和3D物体点数组的顺序必须严格一一对应,否则姿态估计会完全错误。你的代码中:
- 图像点顺序:
topLeft→topRight→bottomLeft→bottomRight - 物体点顺序:左上 → 右上 → 右下 → 左下
两者的第三、第四个点顺序不匹配,导致solvePnP无法正确关联2D和3D点。
修复代码:
调整3D物体点的顺序,和图像点保持一致:
+ (vector<Point3f>) getObjectPointsWithSquareLength: (NSNumber*) squareLength { vector<Point3f> points; double squareLengthDouble = [squareLength doubleValue]; float halfSize = squareLengthDouble / 2.0; // 顺序对应:topLeft, topRight, bottomLeft, bottomRight points.push_back(Point3f(-halfSize, halfSize, 0)); // 左上 points.push_back(Point3f(halfSize, halfSize, 0)); // 右上 points.push_back(Point3f(-halfSize, -halfSize, 0)); // 左下(对应图像的bottomLeft) points.push_back(Point3f(halfSize, -halfSize, 0)); // 右下(对应图像的bottomRight) return points; }
3. 坐标系转换的额外验证
解决前两个问题后,再确认坐标系转换逻辑:
- OpenCV的坐标系是:X向右,Y向下,Z向前
- SceneKit的坐标系是:X向右,Y向上,Z向后
你当前的RotX矩阵绕X轴旋转180度的转换是正确的,修复前两个问题后,tvec scenekit的z值应该接近-2(因为SceneKit的Z轴向后,相机到二维码的距离是2米,二维码处于相机Z=-2的位置,对应相机相对于二维码的位置Z=2),你可以根据这个逻辑调整最终translation向量的符号。
内容的提问来源于stack exchange,提问作者Dim Roe
相关产品推荐
相关产品推荐

