diff --git a/giford/action/__init__.py b/giford/action/__init__.py index 4c9527f..3bde43b 100644 --- a/giford/action/__init__.py +++ b/giford/action/__init__.py @@ -1,5 +1,6 @@ from .abstract_frame_action import AbstractFrameAction +from .rotate import Rotate, RotateMany from .reshape import Reshape, ReshapeMethod from .scroll import Scroll from .shake import Shake diff --git a/giford/action/rotate.py b/giford/action/rotate.py new file mode 100644 index 0000000..25198d4 --- /dev/null +++ b/giford/action/rotate.py @@ -0,0 +1,87 @@ +from typing import Optional + +import numpy as np +from PIL import Image as PillowImage + +from giford.frame.frame_batch import FrameBatch +from giford.frame.raw_data import RawDataFrame + +from .abstract_frame_action import AbstractFrameAction + + +class Rotate(AbstractFrameAction): + def __init__(self) -> None: + super().__init__() + + FULL_ROTATION_DEGREES: int = 360 + + def process( + self, + input_batch: FrameBatch, + rotate_degrees: int = 0, + is_clockwise: bool = True, + ) -> FrameBatch: + """ + rotate images in batch + + :param input_batch: input framebatch + :param rotate_degrees: degrees to rotate, defaults to 0 + :param is_clockwise: rotate clockwise, defaults to True + :return: batch of rotated frames + """ + + if rotate_degrees == 0: + return input_batch.clone() + + if not is_clockwise: + rotate_degrees = Rotate.FULL_ROTATION_DEGREES - rotate_degrees + + output_batch = FrameBatch() + for frame in input_batch.frames: + # will clone data + rdf = RawDataFrame(frame.get_data_arr()) + + # cheating using pimg, but tbh idc they did a good job + # use reference because already cloning data + pimg = PillowImage.fromarray(rdf.get_data_arr(is_return_reference=True)) + pimg = pimg.rotate(rotate_degrees) + output_batch.add_frame(RawDataFrame(np.asarray(pimg))) + + return output_batch + + +class RotateMany(AbstractFrameAction): + def __init__(self) -> None: + super().__init__() + + def process( + self, + input_batch: FrameBatch, + rotate_count: int = 30, + is_clockwise: bool = True, + ) -> FrameBatch: + """ + Completes a full rotation for each frame in the input batch + + :param input_batch: input framebatch + :param rotate_count: number of frames to Rotate, defaults to None + :param is_clockwise: if true, rotate clockwise + :return: frame batch + """ + + rotate_degrees = 360 + step_size: float = rotate_degrees / rotate_count + + r = Rotate() + output_batch = FrameBatch() + for frame in input_batch.frames: + for step_idx in range(rotate_count): + rotate_step: int = int(step_idx * step_size) + + temp_in_batch = FrameBatch.create_from_frame(frame) + temp_out_batch = r.process( + temp_in_batch, rotate_degrees=rotate_step, is_clockwise=is_clockwise + ) + output_batch.add_batch(temp_out_batch) + + return output_batch diff --git a/giford/frame/frame_batch.py b/giford/frame/frame_batch.py index e56d0a0..12fe98f 100644 --- a/giford/frame/frame_batch.py +++ b/giford/frame/frame_batch.py @@ -80,3 +80,9 @@ def create_from_image(cls, img: AbstractImage) -> "FrameBatch": for rdf in img.raw_data_frames: batch.add_frame(rdf) return batch + + @classmethod + def create_from_frame(cls, Frame: RawDataFrame) -> "FrameBatch": + batch = cls() + batch.add_frame(Frame) + return batch diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_0.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_0.png new file mode 100644 index 0000000..89d4af0 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_0.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_1.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_1.png new file mode 100644 index 0000000..0678b3b Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_1.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_10.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_10.png new file mode 100644 index 0000000..6597260 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_10.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_11.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_11.png new file mode 100644 index 0000000..0690131 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_11.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_12.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_12.png new file mode 100644 index 0000000..fcacfd2 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_12.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_2.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_2.png new file mode 100644 index 0000000..bdeec0b Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_2.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_3.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_3.png new file mode 100644 index 0000000..acbdb4d Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_3.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_4.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_4.png new file mode 100644 index 0000000..24f361c Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_4.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_5.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_5.png new file mode 100644 index 0000000..31046fe Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_5.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_6.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_6.png new file mode 100644 index 0000000..18889c9 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_6.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_7.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_7.png new file mode 100644 index 0000000..f1415e6 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_7.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_8.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_8.png new file mode 100644 index 0000000..ebf9598 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_8.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_13_9.png b/tests/baseline_data/rotate_many/test_rotate_many_False_13_9.png new file mode 100644 index 0000000..1479fe2 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_13_9.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_4_0.png b/tests/baseline_data/rotate_many/test_rotate_many_False_4_0.png new file mode 100644 index 0000000..89d4af0 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_4_0.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_4_1.png b/tests/baseline_data/rotate_many/test_rotate_many_False_4_1.png new file mode 100644 index 0000000..22cee01 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_4_1.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_4_2.png b/tests/baseline_data/rotate_many/test_rotate_many_False_4_2.png new file mode 100644 index 0000000..3ba70b7 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_4_2.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_False_4_3.png b/tests/baseline_data/rotate_many/test_rotate_many_False_4_3.png new file mode 100644 index 0000000..f461513 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_False_4_3.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_0.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_0.png new file mode 100644 index 0000000..89d4af0 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_0.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_1.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_1.png new file mode 100644 index 0000000..bc9f191 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_1.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_10.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_10.png new file mode 100644 index 0000000..f9061b4 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_10.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_11.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_11.png new file mode 100644 index 0000000..6657614 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_11.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_12.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_12.png new file mode 100644 index 0000000..6cf0427 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_12.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_2.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_2.png new file mode 100644 index 0000000..f4ba792 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_2.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_3.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_3.png new file mode 100644 index 0000000..e7a912c Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_3.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_4.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_4.png new file mode 100644 index 0000000..ce8e7fc Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_4.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_5.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_5.png new file mode 100644 index 0000000..47a796a Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_5.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_6.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_6.png new file mode 100644 index 0000000..d794454 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_6.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_7.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_7.png new file mode 100644 index 0000000..c99481a Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_7.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_8.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_8.png new file mode 100644 index 0000000..77a7237 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_8.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_13_9.png b/tests/baseline_data/rotate_many/test_rotate_many_True_13_9.png new file mode 100644 index 0000000..875fac3 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_13_9.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_4_0.png b/tests/baseline_data/rotate_many/test_rotate_many_True_4_0.png new file mode 100644 index 0000000..89d4af0 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_4_0.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_4_1.png b/tests/baseline_data/rotate_many/test_rotate_many_True_4_1.png new file mode 100644 index 0000000..f461513 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_4_1.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_4_2.png b/tests/baseline_data/rotate_many/test_rotate_many_True_4_2.png new file mode 100644 index 0000000..3ba70b7 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_4_2.png differ diff --git a/tests/baseline_data/rotate_many/test_rotate_many_True_4_3.png b/tests/baseline_data/rotate_many/test_rotate_many_True_4_3.png new file mode 100644 index 0000000..22cee01 Binary files /dev/null and b/tests/baseline_data/rotate_many/test_rotate_many_True_4_3.png differ diff --git a/tests/baseline_data/test_rotate_False_220.png b/tests/baseline_data/test_rotate_False_220.png new file mode 100644 index 0000000..fc23c24 Binary files /dev/null and b/tests/baseline_data/test_rotate_False_220.png differ diff --git a/tests/baseline_data/test_rotate_False_30.png b/tests/baseline_data/test_rotate_False_30.png new file mode 100644 index 0000000..1b1941d Binary files /dev/null and b/tests/baseline_data/test_rotate_False_30.png differ diff --git a/tests/baseline_data/test_rotate_True_220.png b/tests/baseline_data/test_rotate_True_220.png new file mode 100644 index 0000000..9efe8fb Binary files /dev/null and b/tests/baseline_data/test_rotate_True_220.png differ diff --git a/tests/baseline_data/test_rotate_True_30.png b/tests/baseline_data/test_rotate_True_30.png new file mode 100644 index 0000000..83048cf Binary files /dev/null and b/tests/baseline_data/test_rotate_True_30.png differ diff --git a/tests/test_rotate.py b/tests/test_rotate.py new file mode 100644 index 0000000..70be895 --- /dev/null +++ b/tests/test_rotate.py @@ -0,0 +1,61 @@ +import os +import pytest + +from giford.action import Rotate, RotateMany +from giford.frame import FrameBatch + +from tests.util import BASELINE_DIRECTORY, save_batch_and_compare + + +@pytest.mark.parametrize( + "is_clockwise, rotate_degrees", + [ + (False, 30), + (False, 220), + (True, 30), + (True, 220), + ], +) +def test_rotate( + temp_output_png, + orange_image_batch: FrameBatch, + is_clockwise: bool, + rotate_degrees: int, +): + baseline = os.path.join( + BASELINE_DIRECTORY, f"test_rotate_{is_clockwise}_{rotate_degrees}.png" + ) + + r = Rotate() + output_batch = r.process(orange_image_batch, rotate_degrees, is_clockwise) + + assert save_batch_and_compare(baseline, output_batch, temp_output_png) + + +@pytest.mark.parametrize( + "is_clockwise, rotate_count", + [ + (False, 4), + (False, 13), + (True, 4), + (True, 13), + ], +) +def test_rotate_many( + temp_out_png_generator, + orange_image_batch: FrameBatch, + is_clockwise: bool, + rotate_count: int, +): + + + r = RotateMany() + output_batch = r.process(orange_image_batch, is_clockwise=is_clockwise, rotate_count=rotate_count) + + for idx, frame in enumerate(output_batch.frames): + baseline = os.path.join( + BASELINE_DIRECTORY, f"rotate_many/test_rotate_many_{is_clockwise}_{rotate_count}_{idx}.png" + ) + temp_output_png = next(temp_out_png_generator) + test_batch = FrameBatch.create_from_frame(frame) + assert save_batch_and_compare(baseline, test_batch, temp_output_png) diff --git a/tests/util.py b/tests/util.py index 75fc344..1003dda 100644 --- a/tests/util.py +++ b/tests/util.py @@ -68,6 +68,9 @@ def save_batch_and_compare( is_force_multi_image: bool = False, target_format: SingleImageFormat = DEFAULT_TEST_SINGLE_IMAGE_FORMAT, is_overwrite_existing: bool = False, + is_create_baseline: bool = False, + # overwriting a baseline should be rare, and this will prevent accidents + yes_overwrite_confirmation: bool = False, ) -> bool: assert not batch.is_empty() @@ -85,4 +88,9 @@ def save_batch_and_compare( wrapper.save(test_filepath, overwrite_existing=is_overwrite_existing) + if is_create_baseline: + if not yes_overwrite_confirmation and os.path.exists(baseline_filepath): + raise FileExistsError("baseline exists dummyhead") + wrapper.save(baseline_filepath, overwrite_existing=yes_overwrite_confirmation) + return compare_image_files(baseline_filepath, test_filepath)