Skip to content

Commit fcc8fba

Browse files
tanujdhimanfacebook-github-bot
authored andcommitted
Add skew function (#36)
Summary: Add Shearing w.r.t y-axis and x-axis Pull Request resolved: #36 Reviewed By: jbitton Differential Revision: D29581632 Pulled By: zpapakipos fbshipit-source-id: 050df38cd64446b363581daec60b15b1278a2308
1 parent 673073e commit fcc8fba

File tree

9 files changed

+158
-4
lines changed

9 files changed

+158
-4
lines changed
1.05 MB
Loading

augly/image/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
scale,
4141
sharpen,
4242
shuffle_pixels,
43+
skew,
4344
vflip,
4445
)
4546
from augly.image.helpers import aug_np_wrapper
@@ -77,6 +78,7 @@
7778
scale_intensity,
7879
sharpen_intensity,
7980
shuffle_pixels_intensity,
81+
skew_intensity,
8082
vflip_intensity,
8183
)
8284
from augly.image.transforms import (
@@ -119,6 +121,7 @@
119121
Scale,
120122
Sharpen,
121123
ShufflePixels,
124+
Skew,
122125
VFlip,
123126
)
124127

@@ -165,6 +168,7 @@
165168
"Scale",
166169
"Sharpen",
167170
"ShufflePixels",
171+
"Skew",
168172
"VFlip",
169173
"apply_lambda",
170174
"apply_pil_filter",
@@ -200,6 +204,7 @@
200204
"scale",
201205
"sharpen",
202206
"shuffle_pixels",
207+
"skew",
203208
"vflip",
204209
"apply_lambda_intensity",
205210
"apply_pil_filter_intensity",
@@ -234,5 +239,6 @@
234239
"scale_intensity",
235240
"sharpen_intensity",
236241
"shuffle_pixels_intensity",
242+
"skew_intensity",
237243
"vflip_intensity",
238244
]

augly/image/functional.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import numpy as np
1616
from augly import utils
1717
from augly.image import utils as imutils
18+
from augly.image.utils.bboxes import spatial_bbox_helper
1819
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont
1920

2021

@@ -2368,6 +2369,72 @@ def shuffle_pixels(
23682369
return imutils.ret_and_save_image(aug_image, output_path, src_mode)
23692370

23702371

2372+
def skew(
2373+
image: Union[str, Image.Image],
2374+
output_path: Optional[str] = None,
2375+
skew_factor: float = 0.5,
2376+
axis: int = 0,
2377+
metadata: Optional[List[Dict[str, Any]]] = None,
2378+
bboxes: Optional[List[Tuple]] = None,
2379+
bbox_format: Optional[str] = None,
2380+
) -> Image.Image:
2381+
"""
2382+
Skews an image with respect to its x or y-axis
2383+
2384+
@param image: the path to an image or a variable of type PIL.Image.Image
2385+
to be augmented
2386+
2387+
@param output_path: the path in which the resulting image will be stored.
2388+
If None, the resulting PIL Image will still be returned
2389+
2390+
@param skew_factor: the level of skew to apply to the image; a larger absolute value will
2391+
result in a more intense skew. Recommended range is between [-2, 2]
2392+
2393+
@param axis: the axis along which the image will be skewed; can be set to 0 (x-axis)
2394+
or 1 (y-axis)
2395+
2396+
@param metadata: if set to be a list, metadata about the function execution
2397+
including its name, the source & dest width, height, etc. will be appended
2398+
to the inputted list. If set to None, no metadata will be appended or returned
2399+
2400+
@param bboxes: a list of bounding boxes can be passed in here if desired. If
2401+
provided, this list will be modified in place such that each bounding box is
2402+
transformed according to this function
2403+
2404+
@param bbox_format: signifies what bounding box format was used in `bboxes`. Must
2405+
specify `bbox_format` if `bboxes` is provided. Supported bbox_format values are
2406+
"pascal_voc", "pascal_voc_norm", "coco", and "yolo"
2407+
2408+
@returns: the augmented PIL Image
2409+
"""
2410+
image = imutils.validate_and_load_image(image)
2411+
func_kwargs = imutils.get_func_kwargs(metadata, locals())
2412+
src_mode = image.mode
2413+
2414+
w, h = image.size
2415+
2416+
if axis == 0:
2417+
data = (1, skew_factor, -skew_factor * h / 2, 0, 1, 0)
2418+
elif axis == 1:
2419+
data = (1, 0, 0, skew_factor, 1, -skew_factor * w / 2)
2420+
else:
2421+
raise AssertionError(
2422+
f"Invalid 'axis' value: Got '{axis}', expected 0 for 'x-axis' or 1 for 'y-axis'"
2423+
)
2424+
2425+
aug_image = image.transform((w, h), Image.AFFINE, data, resample=Image.BILINEAR)
2426+
imutils.get_metadata(
2427+
metadata=metadata,
2428+
function_name="skew",
2429+
aug_image=aug_image,
2430+
bboxes_helper_func=spatial_bbox_helper,
2431+
aug_function=skew,
2432+
**func_kwargs,
2433+
)
2434+
2435+
return imutils.ret_and_save_image(aug_image, output_path, src_mode) # pyre-ignore
2436+
2437+
23712438
def vflip(
23722439
image: Union[str, Image.Image],
23732440
output_path: Optional[str] = None,

augly/image/intensity.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,11 @@ def shuffle_pixels_intensity(factor: float, **kwargs) -> float:
308308
return factor * 100.0
309309

310310

311+
def skew_intensity(skew_factor: float, **kwargs) -> float:
312+
max_skew_factor = 2.0
313+
return min((abs(skew_factor) / max_skew_factor) * 100.0, 100.0)
314+
315+
311316
def vflip_intensity(**kwargs) -> float:
312317
return 100.0
313318

augly/image/transforms.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,6 +2074,55 @@ def apply_transform(
20742074
)
20752075

20762076

2077+
class Skew(BaseTransform):
2078+
def __init__(self, skew_factor: float = 0.5, axis: int = 0, p: float = 1.0):
2079+
"""
2080+
@param skew_factor: the level of skew to apply to the image; a larger absolute value will
2081+
result in a more intense skew. Recommended range is between [-2, 2]
2082+
2083+
@param axis: the axis along which the image will be skewed; can be set to 0 (x-axis)
2084+
or 1 (y-axis)
2085+
"""
2086+
super().__init__(p)
2087+
self.skew_factor = skew_factor
2088+
self.axis = axis
2089+
2090+
def apply_transform(
2091+
self,
2092+
image: Image.Image,
2093+
metadata: Optional[List[Dict[str, Any]]] = None,
2094+
bboxes: Optional[List[Tuple]] = None,
2095+
bbox_format: Optional[str] = None,
2096+
) -> Image.Image:
2097+
"""
2098+
Skews an image with respect to its x or y-axis
2099+
2100+
@param image: PIL Image to be augmented
2101+
2102+
@param metadata: if set to be a list, metadata about the function execution
2103+
including its name, the source & dest width, height, etc. will be appended to
2104+
the inputted list. If set to None, no metadata will be appended or returned
2105+
2106+
@param bboxes: a list of bounding boxes can be passed in here if desired. If
2107+
provided, this list will be modified in place such that each bounding box is
2108+
transformed according to this function
2109+
2110+
@param bbox_format: signifies what bounding box format was used in `bboxes`. Must
2111+
specify `bbox_format` if `bboxes` is provided. Supported bbox_format values
2112+
are "pascal_voc", "pascal_voc_norm", "coco", and "yolo"
2113+
2114+
@returns: Augmented PIL Image
2115+
"""
2116+
return F.skew(
2117+
image,
2118+
skew_factor=self.skew_factor,
2119+
axis=self.axis,
2120+
metadata=metadata,
2121+
bboxes=bboxes,
2122+
bbox_format=bbox_format,
2123+
)
2124+
2125+
20772126
class VFlip(BaseTransform):
20782127
def apply_transform(
20792128
self,

augly/image/utils/metadata.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ def transform_bboxes(
132132
imbboxes, f"{function_name}_bboxes_helper", lambda bbox, **_: bbox
133133
)
134134

135+
func_kwargs = deepcopy(kwargs)
136+
func_kwargs.pop("src_bboxes", None)
135137
transformed_norm_bboxes = [
136-
bboxes_helper_func(
137-
bbox=bbox, function_name=function_name, src_w=src_w, src_h=src_h, **kwargs
138-
)
138+
bboxes_helper_func(bbox=bbox, src_w=src_w, src_h=src_h, **func_kwargs)
139139
for bbox in norm_bboxes
140140
]
141141

@@ -191,7 +191,7 @@ def get_metadata(
191191
function_name=function_name,
192192
image=image,
193193
aug_image=aug_image,
194-
bbox_helper_func=bboxes_helper_func,
194+
bboxes_helper_func=bboxes_helper_func,
195195
**kwargs,
196196
)
197197

@@ -201,6 +201,11 @@ def get_metadata(
201201
kwargs_types_fixed = dict(
202202
(k, list(v)) if isinstance(v, tuple) else (k, v) for k, v in kwargs.items()
203203
)
204+
if (
205+
bboxes_helper_func is not None
206+
and bboxes_helper_func.__name__ == "spatial_bbox_helper"
207+
):
208+
kwargs_types_fixed.pop("aug_function", None)
204209

205210
metadata.append(
206211
{

augly/tests/image_tests/functional_unit_test.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ def test_sharpen(self):
129129
def test_shuffle_pixels(self):
130130
self.evaluate_function(imaugs.shuffle_pixels, factor=0.5)
131131

132+
def test_skew(self):
133+
self.evaluate_function(imaugs.skew)
134+
132135
def test_vflip(self):
133136
self.evaluate_function(imaugs.vflip)
134137

augly/tests/image_tests/transforms_unit_test.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ def test_Sharpen(self):
206206
def test_ShufflePixels(self):
207207
self.evaluate_class(imaugs.ShufflePixels(factor=0.5), fname="shuffle_pixels")
208208

209+
def test_Skew(self):
210+
self.evaluate_class(imaugs.Skew(), fname="skew")
211+
209212
def test_VFlip(self):
210213
self.evaluate_class(imaugs.VFlip(), fname="vflip")
211214

augly/utils/expected_output/image_tests/expected_metadata.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,22 @@
706706
"src_width": 1920
707707
}
708708
],
709+
"skew": [
710+
{
711+
"bbox_format": "yolo",
712+
"dst_bboxes": [[0.5, 0.5, 0.4614583333333333, 0.75]],
713+
"dst_height": 1080,
714+
"dst_width": 1920,
715+
"skew_factor": 0.5,
716+
"axis": 0,
717+
"intensity": 25.0,
718+
"name": "skew",
719+
"output_path": null,
720+
"src_bboxes": [[0.5, 0.5, 0.25, 0.75]],
721+
"src_height": 1080,
722+
"src_width": 1920
723+
}
724+
],
709725
"vflip": [
710726
{
711727
"bbox_format": "yolo",

0 commit comments

Comments
 (0)