| import numpy as np |
|
|
| class Cutout: |
|
|
| def __init__(self, size=16) -> None: |
| self.size = size |
|
|
| def _create_cutout_mask(self, img_height, img_width, num_channels, size): |
| """Creates a zero mask used for cutout of shape `img_height` x `img_width`. |
| Args: |
| img_height: Height of image cutout mask will be applied to. |
| img_width: Width of image cutout mask will be applied to. |
| num_channels: Number of channels in the image. |
| size: Size of the zeros mask. |
| Returns: |
| A mask of shape `img_height` x `img_width` with all ones except for a |
| square of zeros of shape `size` x `size`. This mask is meant to be |
| elementwise multiplied with the original image. Additionally returns |
| the `upper_coord` and `lower_coord` which specify where the cutout mask |
| will be applied. |
| """ |
| |
|
|
| |
| height_loc = np.random.randint(low=0, high=img_height) |
| width_loc = np.random.randint(low=0, high=img_width) |
|
|
| size = int(size) |
| |
| upper_coord = (max(0, height_loc - size // 2), max(0, width_loc - size // 2)) |
| lower_coord = ( |
| min(img_height, height_loc + size // 2), |
| min(img_width, width_loc + size // 2), |
| ) |
| mask_height = lower_coord[0] - upper_coord[0] |
| mask_width = lower_coord[1] - upper_coord[1] |
| assert mask_height > 0 |
| assert mask_width > 0 |
|
|
| mask = np.ones((img_height, img_width, num_channels)) |
| zeros = np.zeros((mask_height, mask_width, num_channels)) |
| mask[upper_coord[0]: lower_coord[0], upper_coord[1]: lower_coord[1], :] = zeros |
| return mask, upper_coord, lower_coord |
|
|
| def __call__(self, pil_img): |
| pil_img = pil_img.copy() |
| img_height, img_width, num_channels = (*pil_img.size, 3) |
| _, upper_coord, lower_coord = self._create_cutout_mask( |
| img_height, img_width, num_channels, self.size |
| ) |
| pixels = pil_img.load() |
| for i in range(upper_coord[0], lower_coord[0]): |
| for j in range(upper_coord[1], lower_coord[1]): |
| pixels[i, j] = (125, 122, 113, 0) |
| return pil_img |