Spaces:
Sleeping
Sleeping
resized_crop_pad readability refactor
Browse files- deployment/transforms.py +21 -18
- tests/test_transforms.py +14 -20
- training/notebooks/transforms-lab.ipynb +2 -2
deployment/transforms.py
CHANGED
@@ -14,9 +14,7 @@ from PIL import Image
|
|
14 |
# # from timm import create_model
|
15 |
|
16 |
|
17 |
-
def
|
18 |
-
image: Union[Image.Image, torch.tensor], size: Tuple[int, int]
|
19 |
-
) -> Image:
|
20 |
"""
|
21 |
Takes a `PIL.Image` and crops it `size` unless one
|
22 |
dimension is larger than the actual image. Padding
|
@@ -71,28 +69,33 @@ def pad(image, size: Tuple[int, int]) -> Image:
|
|
71 |
return tvf.pad(image, [pad_top, pad_left, height, width], padding_mode="constant")
|
72 |
|
73 |
|
74 |
-
def
|
|
|
|
|
|
|
|
|
75 |
"""
|
|
|
|
|
|
|
|
|
76 |
Args:
|
77 |
image (`PIL.Image`):
|
78 |
An image to perform padding on
|
79 |
size (`tuple` of integers):
|
80 |
-
A size to pad to, should be in the form
|
81 |
of (width, height)
|
82 |
-
|
|
|
83 |
"""
|
84 |
-
# return tvtfms.CenterCrop(size)
|
85 |
-
def _crop_pad(img):
|
86 |
-
orig_sz = img.shape
|
87 |
-
xtra = math.ceil(max(*size[:2]) * val_xtra / 8) * 8
|
88 |
-
final_size = (size[0] + xtra, size[1] + xtra)
|
89 |
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
|
96 |
-
|
|
|
97 |
|
98 |
-
return
|
|
|
14 |
# # from timm import create_model
|
15 |
|
16 |
|
17 |
+
def crop(image: Union[Image.Image, torch.tensor], size: Tuple[int, int]) -> Image:
|
|
|
|
|
18 |
"""
|
19 |
Takes a `PIL.Image` and crops it `size` unless one
|
20 |
dimension is larger than the actual image. Padding
|
|
|
69 |
return tvf.pad(image, [pad_top, pad_left, height, width], padding_mode="constant")
|
70 |
|
71 |
|
72 |
+
def resized_crop_pad(
|
73 |
+
image: Union[Image.Image, torch.tensor],
|
74 |
+
size: Tuple[int, int],
|
75 |
+
extra_crop_ratio: float = 0.14,
|
76 |
+
) -> Image:
|
77 |
"""
|
78 |
+
Takes a `PIL.Image`, resize it according to the
|
79 |
+
`extra_crop_ratio`, and then crops and pads
|
80 |
+
it to `size`.
|
81 |
+
|
82 |
Args:
|
83 |
image (`PIL.Image`):
|
84 |
An image to perform padding on
|
85 |
size (`tuple` of integers):
|
86 |
+
A size to crop and pad to, should be in the form
|
87 |
of (width, height)
|
88 |
+
extra_crop_ratio (float):
|
89 |
+
The ratio of size at the edge cropped out. Default 0.14
|
90 |
"""
|
|
|
|
|
|
|
|
|
|
|
91 |
|
92 |
+
maximum_space = max(size[0], size[1])
|
93 |
+
extra_space = maximum_space * extra_crop_ratio
|
94 |
+
extra_space = math.ceil(extra_space / 8) * 8
|
95 |
+
extended_size = (size[0] + extra_space, size[1] + extra_space)
|
96 |
+
resized_image = image.resize(extended_size, resample=Image.Resampling.BILINEAR)
|
97 |
|
98 |
+
if extended_size != size:
|
99 |
+
resized_image = pad(crop(resized_image, size), size)
|
100 |
|
101 |
+
return resized_image
|
tests/test_transforms.py
CHANGED
@@ -7,7 +7,7 @@ from PIL import Image
|
|
7 |
from fastai.vision.data import PILImage
|
8 |
import fastai.vision.augment as fastai_aug
|
9 |
|
10 |
-
from deployment.transforms import
|
11 |
|
12 |
DATA_PATH = "data/kaggle/200-bird-species-with-11788-images"
|
13 |
|
@@ -22,7 +22,7 @@ def get_birds_images(path: Path) -> List[str]:
|
|
22 |
|
23 |
|
24 |
class TestTransforms:
|
25 |
-
im_idx =
|
26 |
|
27 |
@pytest.fixture
|
28 |
def img_paths(self) -> List[str]:
|
@@ -42,28 +42,22 @@ class TestTransforms:
|
|
42 |
def testImageFastaiEqualsPillow(self, im_fastai: PILImage, im_pil: Image):
|
43 |
assert (np.array(im_fastai) == np.array(im_pil)).all()
|
44 |
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
cropped_rrc = crop_rrc(im_fastai, split_idx=1)
|
50 |
-
cropped_fastai = crop_fastai(im_fastai, split_idx=1)
|
51 |
|
52 |
-
|
|
|
53 |
|
54 |
-
|
55 |
-
crop_fastai = fastai_aug.CropPad((460, 460))
|
56 |
-
crop_torch = CenterCropPad((460, 460))
|
57 |
|
58 |
-
|
59 |
-
|
60 |
-
def testRandomResizedCropInValidationEqualsCustomCenterCropPad(
|
61 |
self, im_fastai: PILImage, im_pil: Image
|
62 |
):
|
63 |
crop_rrc = fastai_aug.RandomResizedCrop((460, 460))
|
64 |
-
crop_custom = CenterCropPad((460, 460))
|
65 |
-
|
66 |
-
cropped_rrc = crop_rrc(im_fastai, split_idx=1)
|
67 |
-
cropped_custom = crop_custom(im_fastai)
|
68 |
|
69 |
-
assert (
|
|
|
|
|
|
|
|
7 |
from fastai.vision.data import PILImage
|
8 |
import fastai.vision.augment as fastai_aug
|
9 |
|
10 |
+
from deployment.transforms import resized_crop_pad
|
11 |
|
12 |
DATA_PATH = "data/kaggle/200-bird-species-with-11788-images"
|
13 |
|
|
|
22 |
|
23 |
|
24 |
class TestTransforms:
|
25 |
+
im_idx = 510
|
26 |
|
27 |
@pytest.fixture
|
28 |
def img_paths(self) -> List[str]:
|
|
|
42 |
def testImageFastaiEqualsPillow(self, im_fastai: PILImage, im_pil: Image):
|
43 |
assert (np.array(im_fastai) == np.array(im_pil)).all()
|
44 |
|
45 |
+
# RandomResizedCrop is not exactly equal to CropPad in validation
|
46 |
+
# # def testRandomResizedCropEqualsCropPadInValidation(self, im_fastai: PILImage):
|
47 |
+
# # crop_fastai = fastai_aug.CropPad((460, 460))
|
48 |
+
# # crop_rrc = fastai_aug.RandomResizedCrop((460, 460))
|
|
|
|
|
49 |
|
50 |
+
# # cropped_rrc = crop_rrc(im_fastai, split_idx=1)
|
51 |
+
# # cropped_fastai = crop_fastai(im_fastai, split_idx=1)
|
52 |
|
53 |
+
# # assert (np.array(cropped_rrc) == np.array(cropped_fastai)).all()
|
|
|
|
|
54 |
|
55 |
+
def testRandomResizedCropInValidationEqualsCustomResizedCropPad(
|
|
|
|
|
56 |
self, im_fastai: PILImage, im_pil: Image
|
57 |
):
|
58 |
crop_rrc = fastai_aug.RandomResizedCrop((460, 460))
|
|
|
|
|
|
|
|
|
59 |
|
60 |
+
assert (
|
61 |
+
np.array(crop_rrc(im_fastai, split_idx=1))
|
62 |
+
== np.array(resized_crop_pad(im_pil, (460, 460)))
|
63 |
+
).all()
|
training/notebooks/transforms-lab.ipynb
CHANGED
@@ -569,7 +569,7 @@
|
|
569 |
"metadata": {},
|
570 |
"outputs": [],
|
571 |
"source": [
|
572 |
-
"from deployment.transforms import
|
573 |
]
|
574 |
},
|
575 |
{
|
@@ -578,7 +578,7 @@
|
|
578 |
"metadata": {},
|
579 |
"outputs": [],
|
580 |
"source": [
|
581 |
-
"custom_crop =
|
582 |
]
|
583 |
},
|
584 |
{
|
|
|
569 |
"metadata": {},
|
570 |
"outputs": [],
|
571 |
"source": [
|
572 |
+
"from deployment.transforms import ResizedCropPad"
|
573 |
]
|
574 |
},
|
575 |
{
|
|
|
578 |
"metadata": {},
|
579 |
"outputs": [],
|
580 |
"source": [
|
581 |
+
"custom_crop = ResizedCropPad((460, 460))"
|
582 |
]
|
583 |
},
|
584 |
{
|