获取Mediapipe的Landmark3D坐标,并将其转换为相对于UE5中玩家出生点的坐标系 c++
时间: 2024-02-05 08:11:15 浏览: 25
要获取Mediapipe的Landmark3D坐标并将其转换为相对于UE5中玩家出生点的坐标系,你可以按照以下步骤进行:
1. 首先,使用Mediapipe库中的Landmark3D模块来获取3D关键点的坐标。这可以通过以下代码完成(假设你已经导入了Mediapipe库):
```cpp
// 这里示例获取左手腕的坐标
// 输入图像为input_image
// 输出结果为output_landmarks
mp::PoseTracker pose_tracker;
mp::Status status = pose_tracker.Process(input_image);
if (status.ok()) {
const auto& pose_landmarks = pose_tracker.pose_landmarks();
if (!pose_landmarks.landmark().empty()) {
const auto& left_wrist = pose_landmarks.landmark(0); // 左手腕的关键点索引为0
const auto& x = left_wrist.x();
const auto& y = left_wrist.y();
const auto& z = left_wrist.z();
// 这里可以将x、y、z保存到数组或结构体中
}
}
```
2. 接下来,需要将获取到的3D坐标从相机坐标系转换为世界坐标系。这可以通过以下代码完成:
```cpp
// 假设相机坐标系在(0, 0, 0),朝向正Z方向
// 假设相机内参矩阵为K,畸变矩阵为D
// 假设3D关键点坐标为(x, y, z)
cv::Mat K(3, 3, cv::DataType<double>::type); // 内参矩阵
cv::Mat D(1, 5, cv::DataType<double>::type); // 畸变矩阵
cv::Mat rvec(3, 1, cv::DataType<double>::type); // 旋转向量
cv::Mat tvec(3, 1, cv::DataType<double>::type); // 平移向量
// 这里需要根据相机参数设置K、D、rvec和tvec
std::vector<cv::Point3d> object_points;
std::vector<cv::Point2d> image_points;
cv::Point3d point3d(x, y, z);
cv::Point2d point2d;
cv::projectPoints(object_points, rvec, tvec, K, D, image_points); // 将3D点从相机坐标系转换为图像坐标系
double fx = K.at<double>(0, 0); // 内参矩阵第一行第一列
double fy = K.at<double>(1, 1); // 内参矩阵第二行第二列
double cx = K.at<double>(0, 2); // 内参矩阵第一行第三列
double cy = K.at<double>(1, 2); // 内参矩阵第二行第三列
double x_norm = (point2d.x - cx) / fx; // 将图像坐标系下的点归一化到[-1, 1]范围
double y_norm = (point2d.y - cy) / fy;
double z_norm = 1; // 相机坐标系朝向正Z方向
cv::Point3d point3d_norm(x_norm, y_norm, z_norm);
cv::Mat R(3, 3, cv::DataType<double>::type); // 旋转矩阵
cv::Rodrigues(rvec, R); // 旋转向量转换为旋转矩阵
cv::Mat point3d_mat(3, 1, cv::DataType<double>::type); // 3D点的列向量
point3d_mat.at<double>(0, 0) = point3d_norm.x;
point3d_mat.at<double>(1, 0) = point3d_norm.y;
point3d_mat.at<double>(2, 0) = point3d_norm.z;
cv::Mat world_point_mat = R.inv() * (point3d_mat - tvec); // 将相机坐标系下的点转换为世界坐标系下的点
cv::Point3d world_point(world_point_mat.at<double>(0, 0), world_point_mat.at<double>(1, 0), world_point_mat.at<double>(2, 0));
```
3. 最后,需要将获取到的3D坐标从世界坐标系转换为UE5中的坐标系。这可以通过以下代码完成:
```cpp
// 假设玩家出生点在(0, 0, 0)
// 获取玩家出生点的位置
FVector player_spawn_location = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation();
// 将世界坐标系下的点转换为相对于玩家出生点的坐标系下的点
FVector relative_location = FVector(world_point.x, -world_point.y, world_point.z); // UE5中Y轴朝向相反方向,需要取反
FVector final_location = player_spawn_location + relative_location;
```
现在,你已经成功将Mediapipe的Landmark3D坐标转换为相对于UE5中玩家出生点的坐标系!