Source code for lightning_pose.data.augmentations
"""Functions to build augmentation pipeline."""
import imgaug.augmenters as iaa
from omegaconf import DictConfig
from typeguard import typechecked
# to ignore imports for sphix-autoapidoc
__all__ = [
"imgaug_transform",
]
[docs]
@typechecked
def imgaug_transform(cfg: DictConfig) -> iaa.Sequential:
"""Create simple data transform pipeline that augments images.
Args:
cfg: standard config file that carries around dataset info; relevant is the parameter
"cfg.training.imgaug" which can take on the following values:
- default: resizing only
- dlc: imgaug pipeline implemented in DLC 2.0 package
- dlc-top-down: `dlc` pipeline plus random flipping along both horizontal and vertical
axes
Returns:
imgaug pipeline
"""
kind = cfg.training.get("imgaug", "default")
data_transform = []
if kind == "default":
# resizing happens below
print("using default image augmentation pipeline (resizing only)")
elif kind in ["dlc", "dlc-lr", "dlc-top-down"]:
print(f"using {kind} image augmentation pipeline")
# flip horizontally/vertically
if kind in ["dlc-lr", "dlc-top-down"]:
# horizontal flip
data_transform.append(iaa.Fliplr(p=0.5))
if kind == "dlc-top-down":
# vertical flip
data_transform.append(iaa.Flipud(p=0.5))
apply_prob_0 = 0.5
# rotate
rotation = 25 # rotation uniformly sampled from (-rotation, +rotation)
data_transform.append(iaa.Sometimes(
0.4,
iaa.Affine(rotate=(-rotation, rotation))
))
# motion blur
k = 5 # kernel size of blur
angle = 90 # blur direction uniformly sampled from (-angle, +angle)
data_transform.append(iaa.Sometimes(
apply_prob_0,
iaa.MotionBlur(k=k, angle=(-angle, angle))
))
# coarse dropout
prct = 0.02 # drop `prct` of all pixels by converting them to black pixels
size_prct = 0.3 # drop pix on a low-res version of img that's `size_prct` of og
per_channel = 0.5 # per_channel transformations on `per_channel` frac of images
data_transform.append(iaa.Sometimes(
apply_prob_0,
iaa.CoarseDropout(p=prct, size_percent=size_prct, per_channel=per_channel)
))
# coarse salt and pepper
# bright reflections can often confuse the model into thinking they are paws
# (which can also just be bright blobs) - so include some additional transforms that put
# bright blobs (and dark blobs) into the image
prct = 0.01 # probability of changing a pixel to salt/pepper noise
size_prct = (0.05, 0.1) # drop pix on a low-res version of img that's `size_prct` of og
data_transform.append(iaa.Sometimes(
apply_prob_0,
iaa.CoarseSalt(p=prct, size_percent=size_prct), # bigger chunks than coarse dropout
))
data_transform.append(iaa.Sometimes(
apply_prob_0,
iaa.CoarsePepper(p=prct, size_percent=size_prct),
))
# elastic transform
alpha = (0, 10) # controls strength of displacement
sigma = 5 # cotnrols smoothness of displacement
data_transform.append(iaa.Sometimes(
apply_prob_0,
iaa.ElasticTransformation(alpha=alpha, sigma=sigma)
))
# hist eq
data_transform.append(iaa.Sometimes(
0.1,
iaa.AllChannelsHistogramEqualization()
))
# clahe (contrast limited adaptive histogram equalization) -
# hist eq over image patches
data_transform.append(iaa.Sometimes(
0.1,
iaa.AllChannelsCLAHE()
))
# emboss
alpha = (0, 0.5) # overlay embossed image on original with alpha in this range
strength = (0.5, 1.5) # strength of embossing lies in this range
data_transform.append(iaa.Sometimes(
0.1,
iaa.Emboss(alpha=alpha, strength=strength)
))
# crop
crop_by = 0.15 # number of pix to crop on each side of img given as a fraction
data_transform.append(iaa.Sometimes(
0.4,
iaa.CropAndPad(percent=(-crop_by, crop_by), keep_size=False)
))
else:
raise NotImplementedError("must choose imgaug kind from 'default', 'dlc', 'dlc-top-down'")
# do not resize when using dynamic crop pipeline
if not cfg.data.get('dynamic_crop', False):
data_transform.append(
iaa.Resize({
"height": cfg.data.image_resize_dims.height,
"width": cfg.data.image_resize_dims.width}
))
return iaa.Sequential(data_transform)