【问题标题】:How to compute quaternion from max and min coordinate values of the Cube?如何从立方体的最大和最小坐标值计算四元数?
【发布时间】:2020-07-20 10:30:59
【问题描述】:

我在创建立方体的方向时遇到了一些问题(ROS 中检测到的对象的边界框)。我知道最大和最小坐标值(xmin、xmax、ymin、ymax、zmin、zmax)。所以,我可以很容易地找到 Bounding BOX (Cube) 的对象的顶点,它们是

[xmin ymin zmin; 
 xmax ymin zmin; 
 xmax ymax zmin; 
 xmin ymax zmin;
 xmin ymin zmax; 
 xmax ymin zmax; 
 xmax ymax zmax;
 xmin ymax zmax]

现在如何从这些顶点创建四元数以获得边界框的方向?我知道四元数是一组 4 个数字 [x y z w],它表示旋转方式如下:

// RotationAngle is in radians
x = RotationAxis.x * sin(RotationAngle / 2)
y = RotationAxis.y * sin(RotationAngle / 2)
z = RotationAxis.z * sin(RotationAngle / 2)
w = cos(RotationAngle / 2)

在知道对象的顶点(在我的例子中是立方体或 3D 矩形)时如何获得 RotationAxis 和 RotationAngle? 谢谢

【问题讨论】:

    标签: c++ ros quaternions vertex


    【解决方案1】:

    (我不知道 ROS 是什么,但这里是对您问题的抽象讨论。)

    首先,“轮换”从“从”状态开始,以“到”状态结束。你知道你的“to”状态,但你必须指定“from”状态。假设您的盒子以默认状态开始,一个角位于 (0, 0, 0),另一个角位于 (1, 1, 1)。

    这个默认的盒子状态,就像你的最后一个是“轴对齐”盒子。现在,盒子可能旋转了 90、180 或 270 度,但如果盒子的不同面彼此没有区别,这可能无关紧要。这个场景会有一个 0 度的旋转,代表这个旋转的四元数被简单地计算为 (0, 0, 0, 1)。您仍然需要缩放和平移(计算起来也很简单)才能从默认状态变为 BB,但不需要旋转。

    现在,如果面孔实际上不同,那么我们确实会进行旋转。让我们称之为“轴对齐旋转”或 AAR,它可以将默认框带入 24 种不同状态中的任何一种。可以这样想:旋转轴可以是任一方向(+x、-x、+y、-y、+z、-z)的 6 个基向量中的任何一个,角度可以是 0、90、 180 或 270 度(6 * 4 为 24!)

    当您这样考虑时,每种情况都完全定义了一个易于构建的旋转四元数。那么问题就变成了在我们拥有的 24 个旋转中寻找。

    我可以为此想到两个心智模型:要么为你的盒子选择一个“正面”面和一个“顶”面,然后找出它们最终处于“to”状态的位置(“front”和“顶部”有 4 个位置。)或者您可以选择一个“原点”顶点和一个“邻居”顶点并找到它们最终的位置(“原点”有 8 个位置,“邻居”有 3 个位置。)在任何一种情况下,您都可以可能会有一个包含 24 个条目的表来预先计算的四元数,您可以根据自己的“旋转”从中选择。

    【讨论】:

      【解决方案2】:

      您使用最小值和最大值创建边界框的方式会导致边界框与 x、y 和 z 轴对齐。因此,它没有任何旋转,其四元数为 [0, 0, 0, 1]。

      如果您知道哪个顶点与立方体/矩形的哪个角相关,那么获取随机方向的立方体或矩形的旋转矩阵并不复杂。然后,您可以只使用两个垂直边作为对象坐标系中的 x 和 y 轴。标准化这些向量后,您可以通过构建 x 和 y 向量的叉积来在对象框架中创建 z 轴。 3x3 旋转矩阵的列就是这三个向量:

          | x_0  y_0  z_0 |
      R = | x_1  y_1  z_1 |
          | x_2  y_2  z_2 |
      

      您可以在互联网上搜索资源以从旋转矩阵中获取旋转轴和四元数。

      对于一般对象,如果在对象坐标系中的两个垂直轴上有点的顶点,则可以使用相同的方法。如果您不知道顶点的对象框架中的 corespondig 点,它会变得更加复杂。如果您的顶点均匀地覆盖您的对象(例如,来自 3D 相机或激光扫描的顶点),您可以使用主成分分析来查找顶点的主轴。这些轴形成旋转矩阵的列(确保主轴形成右手框架,即旋转矩阵的行列式为 +1)。

      如果这些方法也不适用于您,您可以搜索点云上下文中的姿态估计方法(例如:点云库PCLOpen3D)。

      【讨论】:

      • 但如果我知道 8 个顶点,那么我仍然可以创建立方体。这个立方体必须有一些方向。如何获得旋转矩阵以及如何知道哪个顶点与立方体/矩形的哪个角相关?
      • 如果您使用问题中提到的 8 个顶点创建立方体,其边缘将平行于 x、y 和 z 轴。在没有任何进一步的信息或约束的情况下,没有任何旋转,即作为旋转矩阵的单位矩阵,与将立方体的边缘转换为平行于 x、y 和 z 轴的任何其他旋转一样好。正如在另一个答案中提到的,您有几次旋转会导致类似的结果(一个边缘平行于 x、y 和 z 轴的立方体)。因此,额外的限制或假设可以帮助您缩小范围。但是你没有提到任何这样的限制。
      • 但我知道那个立方体的 8 个角点 (x,y,z)。所以它必须有方向。正确,知道任何立方体的8个角坐标点,从那里可以找到它的方向。我说的对吗?
      • 当然,立方体有一个方向(单位矩阵也是一个旋转)。问题是,方向不是唯一的:旋转是从初始位置到最终位置的转换的一部分。如果您不知道立方体的初始方位,则不清楚要选择 24 种可能的旋转中的哪一种。
      • 那么你为什么对轴对齐边界框的方向感兴趣呢?
      【解决方案3】:

      提取 OBB 的代码(来自教程):

      pcl::MomentOfInertiaEstimation <pcl::PointXYZ> feature_extractor;
      feature_extractor.setInputCloud (cloud);
      feature_extractor.compute ();
      
      pcl::PointXYZ min_point_OBB;
      pcl::PointXYZ max_point_OBB;
      pcl::PointXYZ position_OBB;
      Eigen::Matrix3f rotational_matrix_OBB;
      Eigen::Vector3f major_vector, middle_vector, minor_vector;
      Eigen::Vector3f mass_center;
      
      feature_extractor.getOBB (min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
      feature_extractor.getEigenVectors (major_vector, middle_vector, minor_vector);
      feature_extractor.getMassCenter (mass_center);
      

      所以要获得最终的 OBB - 坐标:

      Eigen::Vector3f p1 (min_point_OBB.x, min_point_OBB.y, min_point_OBB.z);
      Eigen::Vector3f p2 (min_point_OBB.x, min_point_OBB.y, max_point_OBB.z);
      Eigen::Vector3f p3 (max_point_OBB.x, min_point_OBB.y, max_point_OBB.z);
      Eigen::Vector3f p4 (max_point_OBB.x, min_point_OBB.y, min_point_OBB.z);
      Eigen::Vector3f p5 (min_point_OBB.x, max_point_OBB.y, min_point_OBB.z);
      Eigen::Vector3f p6 (min_point_OBB.x, max_point_OBB.y, max_point_OBB.z);
      Eigen::Vector3f p7 (max_point_OBB.x, max_point_OBB.y, max_point_OBB.z);
      Eigen::Vector3f p8 (max_point_OBB.x, max_point_OBB.y, min_point_OBB.z);
      
      p1 = rotational_matrix_OBB * p1 + position;
      p2 = rotational_matrix_OBB * p2 + position;
      p3 = rotational_matrix_OBB * p3 + position;
      p4 = rotational_matrix_OBB * p4 + position;
      p5 = rotational_matrix_OBB * p5 + position;
      p6 = rotational_matrix_OBB * p6 + position;
      p7 = rotational_matrix_OBB * p7 + position;
      p8 = rotational_matrix_OBB * p8 + position
      

      rotational_matrix_OBB怎么获得?

      【讨论】:

      • 我正在使用 ZED 深度相机。那么我可以应用主成分分析来找到顶点的主轴吗?那么如何获得顶点的主轴呢?那么在那之后你能得到旋转矩阵吗?但在 PCA 教程中,我有 major_value、middle_value、minor_value;然后 Eigen::Vector3f major_vector, middle_vector, minor_vector;和 Eigen::Vector3f mass_center;如何获得它们?
      猜你喜欢
      • 1970-01-01
      • 2015-10-29
      • 2011-10-26
      • 2015-12-03
      • 2014-11-20
      • 1970-01-01
      • 2016-07-26
      • 1970-01-01
      • 2013-02-02
      相关资源
      最近更新 更多