diff --git a/fastembed/image/transform/functional.py b/fastembed/image/transform/functional.py index ed6f880a..e3b977db 100644 --- a/fastembed/image/transform/functional.py +++ b/fastembed/image/transform/functional.py @@ -42,9 +42,10 @@ def center_crop( new_shape = image.shape[:-2] + (new_height, new_width) new_image = np.zeros_like(image, shape=new_shape, dtype=np.float32) - top_pad = (new_height - orig_height) // 2 + # Round padding up to offset the floor-rounded crop origin when the difference is odd. + top_pad = (new_height - orig_height + 1) // 2 bottom_pad = top_pad + orig_height - left_pad = (new_width - orig_width) // 2 + left_pad = (new_width - orig_width + 1) // 2 right_pad = left_pad + orig_width new_image[..., top_pad:bottom_pad, left_pad:right_pad] = image diff --git a/tests/test_image_transform.py b/tests/test_image_transform.py index d152719c..ceed9e35 100644 --- a/tests/test_image_transform.py +++ b/tests/test_image_transform.py @@ -3,6 +3,27 @@ from PIL import Image from fastembed.image.transform.functional import normalize, resize +from fastembed.image.transform.operators import Compose + + +def test_center_crop_odd_padding_keeps_batch_shape_and_pixels() -> None: + pixels = np.arange(1, 28, dtype=np.uint8).reshape(3, 3, 3) + processor = Compose.from_config( + { + "do_resize": False, + "do_center_crop": True, + "crop_size": 4, + "do_rescale": False, + } + ) + images = [Image.fromarray(pixels), Image.new("RGB", (4, 4))] + + batch = np.array(processor(images)) + expected = np.zeros((3, 4, 4), dtype=np.float32) + expected[:, 1:, 1:] = pixels.transpose(2, 0, 1) + + assert batch.shape == (2, 3, 4, 4) + np.testing.assert_array_equal(batch[0], expected) @pytest.mark.parametrize(