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)
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