Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Barrel and Pincushion distortions are added. #113

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a885226
Part 1
devrimcavusoglu Sep 5, 2021
edb386e
Add barrel & pincushion distortion.
devrimcavusoglu Sep 6, 2021
61fda43
Fix typo in test fixtures.
devrimcavusoglu Sep 6, 2021
1cde0f7
Black formatting reverted.
devrimcavusoglu Sep 8, 2021
a8460c6
Revert the main state before black formatting.
devrimcavusoglu Sep 8, 2021
4a2a05f
revert to AugLy/main.
devrimcavusoglu Sep 8, 2021
57c010b
Docstring added for `imutils.distort`
devrimcavusoglu Sep 8, 2021
8d1dc24
Docstring added for `functional.distort_barrel` and `functional.disto…
devrimcavusoglu Sep 8, 2021
bcb489a
Revisions for functions and docstrings.
devrimcavusoglu Sep 13, 2021
451f226
Merge branch 'facebookresearch:main' into main
devrimcavusoglu Sep 15, 2021
e963303
Fix tests.
devrimcavusoglu Sep 17, 2021
788ae78
Merge remote-tracking branch 'origin/main' into main
devrimcavusoglu Sep 17, 2021
fe9e3ff
Docstrings revised as max line length is 90.
devrimcavusoglu Sep 17, 2021
8e9c7e5
Helper function added to intensity.
devrimcavusoglu Sep 17, 2021
f6eb08f
Typof fixed.
devrimcavusoglu Sep 17, 2021
2112434
Update augly/image/functional.py
devrimcavusoglu Sep 17, 2021
fd7e9dd
Update augly/image/functional.py
devrimcavusoglu Sep 17, 2021
5c50617
Update augly/image/functional.py
devrimcavusoglu Sep 17, 2021
ee06e38
Update augly/image/functional.py
devrimcavusoglu Sep 17, 2021
19a2edf
Update augly/image/functional.py
devrimcavusoglu Sep 17, 2021
4e3d3e8
Update augly/image/intensity.py
devrimcavusoglu Sep 17, 2021
f30c6be
Update augly/image/intensity.py
devrimcavusoglu Sep 17, 2021
70d159c
Apply suggestions from code review
devrimcavusoglu Sep 17, 2021
a63f9b8
Update augly/image/utils.py
devrimcavusoglu Sep 17, 2021
3bb1510
Docstrins are revised.
devrimcavusoglu Sep 17, 2021
ba6fe56
Docstring corrected.
devrimcavusoglu Sep 17, 2021
22c8d8f
Type hint extended for `distort_intensity`.
devrimcavusoglu Sep 17, 2021
5089547
Typo corrected.
devrimcavusoglu Sep 17, 2021
827fc0e
Requested changes.
devrimcavusoglu Sep 20, 2021
20e7dfb
Apply suggestions from code review
devrimcavusoglu Sep 20, 2021
0f0fa37
Return type added.
devrimcavusoglu Sep 20, 2021
3328c7e
Merge remote-tracking branch 'origin/main' into main
devrimcavusoglu Sep 20, 2021
d53d6d9
Docstring corrected.
devrimcavusoglu Sep 20, 2021
e49be96
Docstring corrected.
devrimcavusoglu Sep 20, 2021
4e1793d
Merge remote-tracking branch 'upstream/main' into main
devrimcavusoglu Sep 26, 2021
6b4d850
Bbox updates.
devrimcavusoglu Sep 30, 2021
7412e8f
Function signatures changed to support bboxes.
devrimcavusoglu Oct 1, 2021
c45c981
Apply suggestions from code review
devrimcavusoglu Oct 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions augly/image/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
contrast,
convert_color,
crop,
distort_barrel,
distort_pincushion,
encoding_quality,
grayscale,
hflip,
Expand Down Expand Up @@ -50,6 +52,8 @@
contrast_intensity,
convert_color_intensity,
crop_intensity,
distort_barrel_intensity,
distort_pincushion_intensity,
encoding_quality_intensity,
grayscale_intensity,
hflip_intensity,
Expand Down Expand Up @@ -86,6 +90,8 @@
Contrast,
ConvertColor,
Crop,
DistortBarrel,
DistortPincushion,
EncodingQuality,
Grayscale,
HFlip,
Expand Down Expand Up @@ -131,6 +137,8 @@
"Contrast",
"ConvertColor",
"Crop",
"DistortBarrel",
"DistortPincushion",
"EncodingQuality",
"Grayscale",
"HFlip",
Expand Down Expand Up @@ -173,6 +181,8 @@
"contrast",
"convert_color",
"crop",
"distort_barrel",
"distort_pincushion",
devrimcavusoglu marked this conversation as resolved.
Show resolved Hide resolved
"encoding_quality",
"grayscale",
"hflip",
Expand Down Expand Up @@ -207,6 +217,8 @@
"contrast_intensity",
"convert_color_intensity",
"crop_intensity",
"distort_barrel_intensity",
"distort_pincushion_intensity",
"encoding_quality_intensity",
"grayscale_intensity",
"hflip_intensity",
Expand Down
166 changes: 166 additions & 0 deletions augly/image/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,172 @@ def crop(
return imutils.ret_and_save_image(aug_image, output_path)


def distort_barrel(
image: Union[str, Image.Image],
output_path: Optional[str] = None,
a: float = 0.0,
b: float = 0.0,
c: float = 0.0,
d: float = 1.0,
metadata: Optional[List[Dict[str, Any]]] = None,
bboxes: Optional[List[Tuple]] = None,
bbox_format: Optional[str] = None,
) -> Image.Image:
"""
Applies barrel distortion to the image with the following equation.

To see effects of the coefficients in detail refer to
https://legacy.imagemagick.org/Usage/distorts/#barrel.
Below is a direct quotation from the document describing how barrel distortion
parameter works.

> The values basically form a distortion equation such that...

Rsrc = r * ( A*r3 + B*r2 + C*r + D )

Where "r" is the destination radius and "Rsrc" is the source pixel to get the
pixel color from. the radii are normalized so that radius = '1.0' for the half
minimum width or height of the input image. This may seem reversed but that is
because the Reverse Pixel Mapping technique is used to ensure complete coverage
of the resulting image.

Setting A = B = C = 0 and D = 1 results in no change in the input image. Negative
values of A, B and C will result in reverse barrel effect closer to pincushion
effect.

@param image: the path to an image or a variable of type PIL.Image.Image
to be augmented

@param output_path: the path in which the resulting image will be stored.
If None, the resulting PIL Image will still be returned

@param a: Coefficient A in the equation Rsrc(r). Larger values results in more
barrel effect, has higher effect than b and c.

@param b: Coefficient B in the equation Rsrc(r). Larger values results in more
barrel effect, has lower effect than a and higher effect than c.

@param c: Coefficient C in the equation Rsrc(r). Larger values results in more
barrel effect, has lower effect than a and b.

@param d: Coefficient D in the equation Rsrc(r). Controls the overall scaling of the
image. In a positive domain, values larger than 1 will shrink the image. Negative
values would result in both vertically and horizontally flipped image scaled in a
mirrored way of positive domain.

@param metadata: if set to be a list, metadata about the function execution
including its name, the source & dest width, height, etc. will be appended
to the inputted list. If set to None, no metadata will be appended or returned

@param bboxes: a list of bounding boxes can be passed in here if desired. If
provided, this list will be modified in place such that each bounding box is
transformed according to this function

@param bbox_format: signifies what bounding box format was used in `bboxes`. Must
specify `bbox_format` if `bboxes` is provided. Supported bbox_format values are
"pascal_voc", "pascal_voc_norm", "coco", and "yolo"

@returns: the augmented PIL Image
"""
image = imutils.validate_and_load_image(image).convert("RGB")
func_kwargs = imutils.get_func_kwargs(metadata, locals())

aug_image = imutils.distort(
image=image,
method="barrel",
distortion_args=(a, b, c, d),
)

imutils.get_metadata(
metadata=metadata,
function_name="distort_barrel",
aug_image=aug_image,
**func_kwargs,
)

return imutils.ret_and_save_image(aug_image, output_path)


def distort_pincushion(
image: Union[str, Image.Image],
output_path: Optional[str] = None,
a: float = 0.0,
b: float = 0.0,
c: float = 0.0,
d: float = 1.0,
metadata: Optional[List[Dict[str, Any]]] = None,
bboxes: Optional[List[Tuple]] = None,
bbox_format: Optional[str] = None,
) -> Image.Image:
"""
To see effects of the coefficients in detail refer to
https://legacy.imagemagick.org/Usage/distorts/#barrelinverse. Below is a direct
quotation from the document describing how pincushion (barrel inverse)
distortion parameter works.

> The 'BarrelInverse' distortion method is very similar to the previous
Barrel Distortion distortion method, and in fact takes the same set of arguments.
However the formula that is applied is slightly different, with the main part of
the equation dividing the radius. that is the Equation has been inverted.

Rsrc = r / ( A*r3 + B*r2 + C*r + D )

NOTE: This equation does NOT produce the 'reverse' the 'Barrel' distortion.
You can NOT use it to 'undo' the previous distortion.

@param image: the path to an image or a variable of type PIL.Image.Image
to be augmented

@param output_path: the path in which the resulting image will be stored.
If None, the resulting PIL Image will still be returned

@param a: Coefficient A in the equation Rsrc(r). Larger values results in more
pincushion effect, has higher effect than b and c.

@param b: Coefficient B in the equation Rsrc(r). Larger values results in more
pincushion effect, has lower effect than a and higher effect than c.

@param c: Coefficient C in the equation Rsrc(r). Larger values results in more
pincushion effect, has lower effect than a and b.

@param d: Coefficient D in the equation Rsrc(r). Controls the overall scaling of
the image. In a positive domain, values larger than 1 will enlarge the image
(zoomed in). Negative values would result in both vertically and horizontally
flipped image scaled in a mirrored way of positive domain.

@param metadata: if set to be a list, metadata about the function execution
including its name, the source & dest width, height, etc. will be appended
to the inputted list. If set to None, no metadata will be appended or returned

@param bboxes: a list of bounding boxes can be passed in here if desired. If
provided, this list will be modified in place such that each bounding box is
transformed according to this function

@param bbox_format: signifies what bounding box format was used in `bboxes`. Must
specify `bbox_format` if `bboxes` is provided. Supported bbox_format values are
"pascal_voc", "pascal_voc_norm", "coco", and "yolo"

@returns: the augmented PIL Image
"""
image = imutils.validate_and_load_image(image).convert("RGB")
func_kwargs = imutils.get_func_kwargs(metadata, locals())

aug_image = imutils.distort(
image=image,
method="barrel_inverse",
distortion_args=(a, b, c, d),
)

imutils.get_metadata(
metadata=metadata,
function_name="distort_pincushion",
aug_image=aug_image,
**func_kwargs,
)

return imutils.ret_and_save_image(aug_image, output_path)


def encoding_quality(
image: Union[str, Image.Image],
output_path: Optional[str] = None,
Expand Down
17 changes: 16 additions & 1 deletion augly/image/intensity.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.

from typing import Any, Dict, Optional, Union
from typing import Any, Dict, Optional, Union, Tuple

import augly.image.utils as imutils
import numpy as np
Expand Down Expand Up @@ -100,6 +100,14 @@ def crop_intensity(metadata: Dict[str, Any], **kwargs) -> float:
return resize_intensity_helper(metadata)


def distort_barrel_intensity(a: float, b: float, c: float, d: float, **kwargs) -> float:
return distort_intensity_helper(coefficients=(a, b, c), scale=d)


def distort_pincushion_intensity(a: float, b: float, c: float, d: float, **kwargs) -> float:
return distort_intensity_helper(coefficients=(a, b, c), scale=d)


def encoding_quality_intensity(quality: int, **kwargs):
assert (
isinstance(quality, int) and 0 <= quality <= 100
Expand Down Expand Up @@ -320,6 +328,13 @@ def normalize_mult_factor(factor: float) -> float:
return factor if factor >= 1 else 1 / factor


def distort_intensity_helper(coefficients: Tuple[float, float, float], scale: float) -> float:
coefficients_magnitude = np.abs(coefficients).sum()
adjusted_scale = np.exp(-(scale-1)**2)
intensity = 100 * (coefficients_magnitude / adjusted_scale)
return float(np.clip(intensity, 0, 100))


def mult_factor_intensity_helper(factor: float) -> float:
factor = normalize_mult_factor(factor)
max_factor = 10
Expand Down
Loading