def validate_vectors_mapping(self, angles, radii, expected):
     target = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
     # Rotate
     rotm = geometry.build_rotation_matrix(*angles)
     source = [np.dot(rotm, v) for v in target]
     # Sort vectors order to mimic SVD
     source = [v for _, v in sorted(zip(radii, source), reverse=True)]
     # Find mapping and validate it
     indices = geometry.find_vectors_mapping(source, target)
     self.assertEqual(indices, expected)
    def test_scalar_projection(self):
        source = [1, 0, 0]
        target = [1, 0, 0]
        proj = geometry.scalar_projection(source, target)
        self.assertEqual(proj, 1)

        # Build rotation matrices and transform the source vector
        angle_xyz = np.deg2rad([0, 0, 30])
        rotm = geometry.build_rotation_matrix(*angle_xyz)
        source_30 = np.dot(rotm, source)

        angle_xyz = np.deg2rad([0, 0, 60])
        rotm = geometry.build_rotation_matrix(*angle_xyz)
        source_60 = np.dot(rotm, source)

        proj_30 = abs(geometry.scalar_projection(source_30, target))
        proj_60 = abs(geometry.scalar_projection(source_60, target))

        self.assertGreater(proj_30, proj_60)
    def test_sequece(self):
        angles = np.deg2rad([[0, 10, 0], [0, 10, 0], [0, 10, 5], [0, 10, 5],
                             [0, 0, -5]])
        vectors = [np.array([0, 0, 1])]
        for entry in angles:
            rotm = geometry.build_rotation_matrix(*entry)
            vectors.append(np.dot(rotm, vectors[-1].T))

        for src_vec, dst_vec in zip(vectors, vectors[1:]):
            rotm = geometry.find_relative_vector_rotation(src_vec, dst_vec)
            res_vec = np.dot(rotm, src_vec.T)
            res_vec = res_vec.squeeze()
            err = np.linalg.norm(res_vec - dst_vec)
            self.assertLess(err, 1e-5)
    def test_relative_axes_rotation(self):
        original_axes = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
        rot_angles = np.deg2rad([60, 30, 45])  # Rotate around Z-axis by 45 deg

        # Build rotation matrix and rotate the axes
        rotm = geometry.build_rotation_matrix(*rot_angles)
        rotated_axes = np.dot(rotm, original_axes.T).T

        # Find relative rotation
        rel_rotm = geometry.find_relative_axes_rotation(
            original_axes, rotated_axes)

        # Validate relative rotation matrix
        rel_rotated_axes = np.dot(rel_rotm, original_axes.T).T

        # Validate
        err = np.linalg.norm(rotated_axes - rel_rotated_axes)
        self.assertLess(err, 1e-5)
    def test_relative_vector_rotation(self):
        angle_xyz = np.deg2rad([0, 0, 45])
        src_vec = [0, 1, 0]
        exp_vec = [-0.70710678, 0.70710678, 0.]

        # Build rotation matrix and transform the src_vector
        rotm = geometry.build_rotation_matrix(*angle_xyz)
        res_vec = np.dot(rotm, src_vec)

        # Validate
        err = np.linalg.norm(res_vec - exp_vec)
        self.assertLess(err, 1e-5)

        # Find rotation matrix between source and res vector
        found_rotm = geometry.find_relative_vector_rotation(src_vec, exp_vec)

        # Extract Euler angles
        found_angles = geometry.rotation_matrix_to_angles(found_rotm)

        # Validate
        err = np.linalg.norm(found_angles - angle_xyz)
        self.assertLess(err, 1e-5)
Beispiel #6
0
def make_ellipsoid_image(shape, center, radii, angle):
    """Draw a 3D binary image containing a 3D ellipsoid.

    Arguments:
        shape {list} -- image shape [z, y, x]
        center {list} -- center of the ellipsoid [x, y, z]
        radii {list} -- radii [x, y, z]
        angle {list} -- rotation angles [x, y, z]

    Raises:
        ValueError -- arguments are wrong

    Returns:
        [numpy.array] -- image with ellipsoid
    """

    if len(shape) != 3:
        raise ValueError('Only 3D ellipsoids are supported.')

    if not (len(center) == len(radii) == len(shape)):
        raise ValueError(
            'Center, radii of ellipsoid and image shape have different dimensionality.'
        )

    # Do opposite rotation since it is an axes rotation.
    angle = -1 * np.array(angle)
    R = build_rotation_matrix(*angle)

    # Convert to numpy
    radii = np.array(radii)

    # Build a grid and get its points as a list
    xi = tuple(np.linspace(0, s - 1, s) - np.floor(0.5 * s) for s in shape)

    # Build a list of points forming the grid
    xi = np.meshgrid(*xi, indexing='ij')
    points = np.array(xi).reshape(3, -1)[::-1]

    # Reorder coordinates to match XYZ order and rotate
    points = np.dot(R, points).T

    # Find grid center and rotate
    grid_center = np.array(center) - 0.5 * np.array(shape[::-1])
    grid_center = np.dot(R, grid_center)

    # Reorder coordinates back to ZYX to match the order of numpy array axis
    points = points[:, ::-1]
    grid_center = grid_center[::-1]
    radii = radii[::-1]

    # Draw the ellipsoid
    # dx**2 + dy**2 + dz**2 = r**2
    # dx**2 / r**2 + dy**2 / r**2 + dz**2 / r**2 = 1
    dR = (points - grid_center)**2
    dR = dR / radii**2
    # Sum dx, dy, dz / r**2
    nR = np.sum(dR, axis=1).reshape(shape)

    ell = (nR <= 1).astype(np.uint8)

    return ell