czbiohub-sf / shrimPy

shrimPy: Smart High-throughput Robust Imaging & Measurement in Python
BSD 3-Clause "New" or "Revised" License
8 stars 1 forks source link

replace the np.rot90 with affine transforms in `apply_affine()` #100

Closed edyoshikun closed 10 months ago

edyoshikun commented 1 year ago

The current code used the np.rot90(), which can now be replaced by properly multiplying the transforms. These will also be useful for properly cropping to the maximum overlapping area.

rotate90_affine = utils.rotate_affine(
    (Z_source, Y_source, X_source), 90, (Z_source, X_source, Y_source)
)
rotate_cam_rot_affine = utils.rotate_affine(
    (Z_source, X_source, Y_source), starting_angle, (Z_target, Y_target, X_target)
)
scaling_affine = utils.scale_affine((1, Y_target, X_target), scaling_factor_zyx)
zyx_translation_affine = np.array(
    [
        [1, 0, 0, shift[-3]],
        [0, 1, 0, shift[-2]],
        [0, 0, 1, shift[-1]],
        [0, 0, 0, 1],
    ]
)

compound_affine = (
    zyx_translation_affine @ scaling_affine @ rotate_cam_rot_affine @ rotate90_affine
)

By adding these transformations:

def scale_affine(start_shape_zyx, scaling_factor_zyx=(1, 1, 1), end_shape_zyx=None):
    center_Y_start, center_X_start = np.array(start_shape_zyx)[-2:] / 2
    if end_shape_zyx is None:
        center_Y_end, center_X_end = (center_Y_start, center_X_start)
    else:
        center_Y_end, center_X_end = np.array(end_shape_zyx)[-2:] / 2

    scaling_matrix = np.array(
        [
            [scaling_factor_zyx[-3], 0, 0, 0],
            [
                0,
                scaling_factor_zyx[-2],
                0,
                -center_Y_start * scaling_factor_zyx[-2] + center_Y_end,
            ],
            [
                0,
                0,
                scaling_factor_zyx[-1],
                -center_X_start * scaling_factor_zyx[-1] + center_X_end,
            ],
            [0, 0, 0, 1],
        ]
    )
    return scaling_matrix

def rotate_affine(start_shape_zyx, angle=0.0, end_shape_zyx=None):
    # TODO: make this 3D?
    center_Y_start, center_X_start = np.array(start_shape_zyx)[-2:] / 2
    if end_shape_zyx is None:
        center_Y_end, center_X_end = (center_Y_start, center_X_start)
    else:
        center_Y_end, center_X_end = np.array(end_shape_zyx)[-2:] / 2

    theta = np.radians(angle)

    rotation_matrix = np.array(
        [
            [1, 0, 0, 0],
            [
                0,
                np.cos(theta),
                -np.sin(theta),
                -center_Y_start * np.cos(theta)
                + np.sin(theta) * center_X_start
                + center_Y_end,
            ],
            [
                0,
                np.sin(theta),
                np.cos(theta),
                -center_Y_start * np.sin(theta)
                - center_X_start * np.cos(theta)
                + center_X_end,
            ],
            [0, 0, 0, 1],
        ]
    )

    affine_rot_n_scale_matrix_zyx = rotation_matrix

    return affine_rot_n_scale_matrix_zyx
edyoshikun commented 1 year ago

this will be fixed by #102