尝试将摄像机位置从Aruco跟踪映射回SceneKit中的摄像机位置。它几乎可以正常工作,但是跟踪确实不稳定,并且似乎无法转换为SceneKit相机姿势,因为它漂浮在相机 View 中的标记上并随着我移动相机而移动。在转换回sceneKit摄像机平移和位置 vector 的转换中,谁能看到我在这里做错的事情?
@interface ArucoPayload : NSObject
@property BOOL valid; // Used to determine if the tracking was valid and hides the scenekit nodes if not
@property UIImage *image;
@property CGRect boardSize;
@property SCNVector4 rotationVector;
@property SCNVector3 translationVector;
@end
Mat rvec(3, 1, DataType<double>::type);
Mat tvec(3, 1, DataType<double>::type);
...
aruco::estimatePoseBoard(corners, markerIds, gridBoard, self.camMatrix, self.distCoeffs, rvec, tvec);
[self updateCameraProjection:payload withRotation:rvec andTranslation:tvec];
...
-(void) updateCameraProjection:(ArucoPayload *)payload withRotation:(Mat)rvec andTranslation:(Mat)tvec {
cv::Mat RotX(3, 3, cv::DataType<double>::type);
cv::setIdentity(RotX);
RotX.at<double>(4) = -1;
RotX.at<double>(8) = -1;
cv::Mat R;
cv::Rodrigues(rvec, R);
R = R.t();
Mat rvecConverted;
Rodrigues(R, rvecConverted);
rvecConverted = RotX * rvecConverted;
Mat tvecConverted = -R * tvec;
tvecConverted = RotX * tvecConverted;
payload.rotationVector = SCNVector4Make(rvecConverted.at<double>(0), rvecConverted.at<double>(1), rvecConverted.at<double>(2), norm(rvecConverted));
payload.translationVector = SCNVector3Make(tvecConverted.at<double>(0), tvecConverted.at<double>(1), tvecConverted.at<double>(2));
}
func updateCameraPosition(payload:ArucoPayload) {
if(payload.valid) {
sceneView.scene?.rootNode.isHidden = false
// Add nodes first time we get an updated position
if(sceneView.scene?.rootNode.childNodes.count == 1) {
// Add box node
addBoxNode(to: sceneView, payload: payload)
}
cameraNode.rotation = payload.rotationVector
cameraNode.position = payload.translationVector
} else {
sceneView.scene?.rootNode.isHidden = true
}
}
在OpenCV中完成的绘图是正确的,视频中可以看到我在Aruco板上的轴和框架正在精确跟踪。
任何帮助深表感谢。
这是场景的视频。应该锁定在标记位置的黄色物体看起来非常不稳定。
https://youtu.be/ZvKtZ3DNdrk
相机校准:
// Wait until we have captured enough frames
if(self.numberOfFramesForCalibration == 0) {
NSLog(@"Starting calibration with 20 images");
vector< vector< Point2f > > allCornersConcatenated;
vector< int > allIdsConcatenated;
vector< int > markerCounterPerFrame;
Mat cameraMatrix, distCoeffs;
vector< Mat > rvecs, tvecs;
double repError;
int calibrationFlags = 0;
// prepare data for calibration
markerCounterPerFrame.reserve(allCorners.size());
for(unsigned int i = 0; i < allCorners.size(); i++) {
markerCounterPerFrame.push_back((int)allCorners[i].size());
for(unsigned int j = 0; j < allCorners[i].size(); j++) {
allCornersConcatenated.push_back(allCorners[i][j]);
allIdsConcatenated.push_back(allIds[i][j]);
}
}
// calibrate camera
repError = aruco::calibrateCameraAruco(allCornersConcatenated, allIdsConcatenated,
markerCounterPerFrame, self.data.board, imgSize, cameraMatrix,
distCoeffs, rvecs, tvecs);
bool saveOk = [self saveCameraParams:imgSize aspect:1 flags:calibrationFlags matrix:cameraMatrix coeff:distCoeffs avgErr:repError];
if(saveOk) {
self.calibrationRequired = false;
}
}
最佳答案
不幸的是,这不是一个完整的示例,因此不清楚错误在哪里。无论如何,您发布的内容似乎仍然有可能是问题,因此也许我的困惑中的谈话会有所帮助。RotX
似乎旨在解决OpenCV(右侧X
,向下Y
,向内Z
)和SceneKit(右侧X
,向上Y
,向外Z
)之间的轴差异。tvec
和rvec
代表相对于OpenCV摄像机的世界原点。R.t()
与正交旋转的R.inv()
相同,因此R
现在是通过rvec
的原始R = R.t()
的逆矩阵。
因此Mat tvecConverted = -R * tvec;
(或更明确地说R * -tvec
)是世界坐标系中的摄像机。 Rodrigues(R, rvecConverted);
似乎与rvec
的世界框架相似。
然后,将每个乘以RotX
以将OpenCV坐标作为SceneKit坐标,并分配给payload
。
更新:更新代码后,我们看到分配给payload
的值最终将分配给cameraNode
position
和rotation
值。由于SceneKit的SCNCamera
始终沿其父SCNNode
的负Z轴以相同的方向指向,因此要定位和定向父SCNNode
的位置并使其自身定向。这表明上面的tvecConverted
和rvecConverted
是正确的,因为相机的SCNNode
似乎是根节点的父级。
但是,仍然存在从ScenKit相机空间投影到显示器像素空间的问题,这似乎不在您发布的代码摘录中。我怀疑这需要匹配在OpenCV侧绘制时使用的固有相机矩阵和失真,以使其正确对齐。
在 SCNCamera
docs page中, projectionTransform
property的描述如下:
This transformation expresses the combination of all the camera’s geometric properties: projection type (perspective or orthographic), field of view, depth limits, and orthographic scale (if applicable). SceneKit uses this transformation to convert points in the camera node’s coordinate space to the renderer’s 2D space when rendering and processing events.
You can use this transformation directly if your app needs to convert between view and renderer coordinates for other purposes. Alternatively, if you compute your own projection transform matrix, you can set this property to override the transformation synthesized from the camera’s geometric properties.
由于您尚未发布与相机内部特性相关的代码,因此尚不清楚这是否是问题所在。但是,我怀疑在OpenCV和SceneKit之间对齐内在函数将解决此问题。同样,SceneKit变换是相对于节点的
pivot
属性进行评估的,因此如果要使用该属性,则需要格外小心(例如,将SCNBox
相对于其角而不是其中心放置)。
关于opencv - 使用Aruco标记(OpenCV)将相机姿势映射到SceneKit,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56667057/