Loading imgutils/preprocess/pillow.py +10 −19 Original line number Diff line number Diff line Loading @@ -269,31 +269,22 @@ class PillowNormalize: def __call__(self, array): if not isinstance(array, np.ndarray): raise TypeError('Input should be a numpy.ndarray') if not np.issubdtype(array.dtype, np.floating): raise TypeError(f'Input tensor should ba a float array, but {array.dtype!r} given.') if array.dtype != np.float32: array = array.astype(np.float32) if array.ndim < 3: raise ValueError(f'Expected array to be an array image of size (..., C, H, W). ' f'Got array.shape == {array.shape!r}') else: if not self.inplace: array = array.copy() if array.ndim == 2: if isinstance(self.mean, np.ndarray) or isinstance(self.std, np.ndarray): raise ValueError("Channel-wise mean/std can't be used for single channel data") return self._normalize_single(array) elif array.ndim >= 3: return self._normalize_multi(array) else: raise ValueError(f"Expected 2D or more dims array, got {array.ndim}D") def _normalize_single(self, array): mean = self.mean.reshape(1, 1) std = self.std.reshape(1, 1) array = (array - mean) / std return array def _normalize_multi(self, array): mean = self.mean.reshape(-1, 1, 1) std = self.std.reshape(-1, 1, 1) array = (array - mean) / std array -= mean array /= std return array def __repr__(self) -> str: Loading test/preprocess/test_pillow.py +151 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ from PIL import Image from hbutils.testing import tmatrix from imgutils.preprocess.pillow import PillowResize, _get_pillow_resample, PillowCenterCrop, PillowToTensor, \ PillowMaybeToTensor PillowMaybeToTensor, PillowNormalize from imgutils.preprocess.torchvision import _get_interpolation_mode from test.testings import get_testfile Loading Loading @@ -415,6 +415,7 @@ class TestPreprocessPillow: def test_to_tensor_repr(self): assert repr(PillowToTensor()) == 'PillowToTensor()' @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', Loading Loading @@ -446,3 +447,152 @@ class TestPreprocessPillow: def test_maybe_to_tensor_repr(self): assert repr(PillowMaybeToTensor()) == 'PillowMaybeToTensor()' @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ # 'I', 'I;16', 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ (0.4850, 0.4560, 0.4060), (0.5, 0.5, 0.5), (0.0, 0.0, 0.0), (0.4850,), (0.5,), (0.0,), ], 'std': [ (0.2290, 0.2240, 0.2250), (0.5, 0.5, 0.5), (1.0, 1.0, 1.0), (0.2290,), (0.5,), (1.0,), ] })) def test_maybe_normalize_3dim(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy()) @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ # 'I', 'I;16', 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ (0.4850, 0.4560, 0.4060), (0.5, 0.5, 0.5), (0.0, 0.0, 0.0), (0.4850,), (0.5,), (0.0,), ], 'std': [ (0.2290, 0.2240, 0.2250), (0.5, 0.5, 0.5), (1.0, 1.0, 1.0), (0.2290,), (0.5,), (1.0,), ] })) def test_maybe_normalize_3dim_upgrade(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) arr = arr.unsqueeze(0).unsqueeze(0) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy()) @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim # 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ (0.4850,), (0.5,), (0.0,), ], 'std': [ (0.2290,), (0.5,), (1.0,), ] })) def test_maybe_normalize_1dim(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy()) @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim # 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ 0.4850, 0.5, 0.0, ], 'std': [ 0.2290, 0.5, 1.0, ] })) def test_maybe_normalize_1dim_single_value(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy()) Loading
imgutils/preprocess/pillow.py +10 −19 Original line number Diff line number Diff line Loading @@ -269,31 +269,22 @@ class PillowNormalize: def __call__(self, array): if not isinstance(array, np.ndarray): raise TypeError('Input should be a numpy.ndarray') if not np.issubdtype(array.dtype, np.floating): raise TypeError(f'Input tensor should ba a float array, but {array.dtype!r} given.') if array.dtype != np.float32: array = array.astype(np.float32) if array.ndim < 3: raise ValueError(f'Expected array to be an array image of size (..., C, H, W). ' f'Got array.shape == {array.shape!r}') else: if not self.inplace: array = array.copy() if array.ndim == 2: if isinstance(self.mean, np.ndarray) or isinstance(self.std, np.ndarray): raise ValueError("Channel-wise mean/std can't be used for single channel data") return self._normalize_single(array) elif array.ndim >= 3: return self._normalize_multi(array) else: raise ValueError(f"Expected 2D or more dims array, got {array.ndim}D") def _normalize_single(self, array): mean = self.mean.reshape(1, 1) std = self.std.reshape(1, 1) array = (array - mean) / std return array def _normalize_multi(self, array): mean = self.mean.reshape(-1, 1, 1) std = self.std.reshape(-1, 1, 1) array = (array - mean) / std array -= mean array /= std return array def __repr__(self) -> str: Loading
test/preprocess/test_pillow.py +151 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ from PIL import Image from hbutils.testing import tmatrix from imgutils.preprocess.pillow import PillowResize, _get_pillow_resample, PillowCenterCrop, PillowToTensor, \ PillowMaybeToTensor PillowMaybeToTensor, PillowNormalize from imgutils.preprocess.torchvision import _get_interpolation_mode from test.testings import get_testfile Loading Loading @@ -415,6 +415,7 @@ class TestPreprocessPillow: def test_to_tensor_repr(self): assert repr(PillowToTensor()) == 'PillowToTensor()' @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', Loading Loading @@ -446,3 +447,152 @@ class TestPreprocessPillow: def test_maybe_to_tensor_repr(self): assert repr(PillowMaybeToTensor()) == 'PillowMaybeToTensor()' @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ # 'I', 'I;16', 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ (0.4850, 0.4560, 0.4060), (0.5, 0.5, 0.5), (0.0, 0.0, 0.0), (0.4850,), (0.5,), (0.0,), ], 'std': [ (0.2290, 0.2240, 0.2250), (0.5, 0.5, 0.5), (1.0, 1.0, 1.0), (0.2290,), (0.5,), (1.0,), ] })) def test_maybe_normalize_3dim(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy()) @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ # 'I', 'I;16', 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ (0.4850, 0.4560, 0.4060), (0.5, 0.5, 0.5), (0.0, 0.0, 0.0), (0.4850,), (0.5,), (0.0,), ], 'std': [ (0.2290, 0.2240, 0.2250), (0.5, 0.5, 0.5), (1.0, 1.0, 1.0), (0.2290,), (0.5,), (1.0,), ] })) def test_maybe_normalize_3dim_upgrade(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) arr = arr.unsqueeze(0).unsqueeze(0) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy()) @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim # 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ (0.4850,), (0.5,), (0.0,), ], 'std': [ (0.2290,), (0.5,), (1.0,), ] })) def test_maybe_normalize_1dim(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy()) @skipUnless(_TORCHVISION_AVAILABLE, 'Torchvision required.') @pytest.mark.parametrize(*tmatrix({ 'src_image': [ 'png_640.png', 'png_640_m90.png', ], 'mode': [ 'F', '1', 'L', 'P', # 1dim # 'LA', # 2dim # 'RGB', 'YCbCr', # 3dim # 'RGBA', 'CMYK', # 4dim ], 'mean': [ 0.4850, 0.5, 0.0, ], 'std': [ 0.2290, 0.5, 1.0, ] })) def test_maybe_normalize_1dim_single_value(self, src_image, mode, mean, std): from torchvision.transforms import ToTensor, Normalize image = Image.open(get_testfile(src_image)) image = image.convert(mode) assert image.mode == mode arr = ToTensor()(image) pnormalize = PillowNormalize(mean=mean, std=std) tnormalize = Normalize(mean=mean, std=std) np.testing.assert_array_almost_equal(pnormalize(arr.numpy()), tnormalize(arr).numpy())