예제 #1
0
 def test_relative_so3(self):
     a = lie.random_so3()
     b = lie.random_so3()
     self.assertTrue(lie.is_so3(a) and lie.is_so3(b))
     a_to_b = lie.relative_so3(a, b)
     b_from_a = a.dot(a_to_b)
     self.assertTrue(np.allclose(b_from_a, b))
예제 #2
0
def filter_pairs_by_angle(poses: typing.Sequence[np.ndarray],
                          delta: float,
                          tol: float = 0.0,
                          degrees: bool = False,
                          all_pairs: bool = False) -> IdPairs:
    """
    filters pairs in a list of SE(3) poses by their relative angle
     - by default, the angle accumulated on the path between the two pair poses
       is considered
     - if <all_pairs> is set to True, the direct angle between the two pair
       poses is considered
    :param poses: list of SE(3) poses
    :param delta: the angle in radians used for filtering
    :param tol: absolute angle tolerance to accept or reject pairs
                in all_pairs mode
    :param degrees: set to True if <delta> is in degrees instead of radians
    :param all_pairs: use all pairs instead of consecutive pairs
    :return: list of index tuples of the filtered pairs
    """
    # Angle-axis angles are within [0, pi] / [0, 180] (Euler theorem).
    bounds = [0., 180.] if degrees else [0, np.pi]
    if delta < bounds[0] or delta > bounds[1]:
        raise FilterException(f"delta angle must be within {bounds}")
    delta = np.deg2rad(delta) if degrees else delta
    tol = np.deg2rad(tol) if degrees else tol
    if all_pairs:
        upper_bound = delta + tol
        lower_bound = delta - tol
        id_pairs = []
        ids = list(range(len(poses)))
        # All pairs search is O(n^2) here. Use vectorized operations with
        # scipy.spatial.transform.Rotation for quicker processing.
        logger.info("Searching all pairs with matching rotation delta,"
                    " this can take a while.")
        start_indices = ids[:-1]
        for i in start_indices:
            if not i % 100:
                print(int(i / len(start_indices) * 100), "%", end="\r")
            offset = i + 1
            end_indices = ids[offset:]
            rotations_i = lie.sst_rotation_from_matrix(
                np.array([poses[i][:3, :3]] * len(end_indices)))
            rotations_j = lie.sst_rotation_from_matrix(
                np.array([poses[j][:3, :3] for j in end_indices]))
            delta_angles = np.linalg.norm(
                (rotations_i.inv() * rotations_j).as_rotvec(), axis=1)
            matches = np.argwhere((lower_bound <= delta_angles)
                                  & (delta_angles <= upper_bound)) + offset
            id_pairs.extend([(i, j) for j in matches.flatten().tolist()])
    else:
        delta_angles = [
            lie.so3_log_angle(lie.relative_so3(p1[:3, :3], p2[:3, :3]))
            for p1, p2 in zip(poses, poses[1:])
        ]
        accumulated_delta = 0.0
        current_start_index = 0
        id_pairs = []
        for i, current_delta in enumerate(delta_angles):
            end_index = i + 1
            accumulated_delta += current_delta
            if accumulated_delta >= delta:
                id_pairs.append((current_start_index, end_index))
                accumulated_delta = 0.0
                current_start_index = end_index
    return id_pairs