The image preprocessor loads an image from disk and prepares it as needed for batching. This includes cropping, resizing, normalization, data type casting, and transposing. This Image Batcher implements two algorithms: * V2: The algorithm for EfficientNet V2, as defi
(self, image_path)
| 102 | self.preprocessor = preprocessor |
| 103 | |
| 104 | def preprocess_image(self, image_path): |
| 105 | """ |
| 106 | The image preprocessor loads an image from disk and prepares it as needed for batching. This includes cropping, |
| 107 | resizing, normalization, data type casting, and transposing. |
| 108 | This Image Batcher implements two algorithms: |
| 109 | * V2: The algorithm for EfficientNet V2, as defined in automl/efficientnetv2/preprocessing.py. |
| 110 | * V1: The algorithm for EfficientNet V1, aka "Legacy", as defined in automl/efficientnetv2/preprocess_legacy.py. |
| 111 | :param image_path: The path to the image on disk to load. |
| 112 | :return: A numpy array holding the image sample, ready to be contacatenated into the rest of the batch. |
| 113 | """ |
| 114 | |
| 115 | def pad_crop(image): |
| 116 | """ |
| 117 | A subroutine to implement padded cropping. This will create a center crop of the image, padded by 32 pixels. |
| 118 | :param image: The PIL image object |
| 119 | :return: The PIL image object already padded and cropped. |
| 120 | """ |
| 121 | # Assume square images |
| 122 | assert self.height == self.width |
| 123 | width, height = image.size |
| 124 | ratio = self.height / (self.height + 32) |
| 125 | crop_size = int(ratio * min(height, width)) |
| 126 | y = (height - crop_size) // 2 |
| 127 | x = (width - crop_size) // 2 |
| 128 | return image.crop((x, y, x + crop_size, y + crop_size)) |
| 129 | |
| 130 | image = Image.open(image_path) |
| 131 | image = image.convert(mode="RGB") |
| 132 | if self.preprocessor == "V2": |
| 133 | # For EfficientNet V2: Bilinear Resize and [-1,+1] Normalization |
| 134 | if self.height < 320: |
| 135 | # Padded crop only on smaller sizes |
| 136 | image = pad_crop(image) |
| 137 | image = image.resize((self.width, self.height), resample=Image.BILINEAR) |
| 138 | image = np.asarray(image, dtype=self.dtype) |
| 139 | image = (image - 128.0) / 128.0 |
| 140 | elif self.preprocessor == "V1": |
| 141 | # For EfficientNet V1: Padded Crop, Bicubic Resize, and [0,1] Normalization |
| 142 | # (Mean subtraction and Std Dev scaling will be part of the graph, so not done here) |
| 143 | image = pad_crop(image) |
| 144 | image = image.resize((self.width, self.height), resample=Image.BICUBIC) |
| 145 | image = np.asarray(image, dtype=self.dtype) |
| 146 | image = image / 255.0 |
| 147 | elif self.preprocessor == "V1MS": |
| 148 | # For EfficientNet V1: Padded Crop, Bicubic Resize, and [0,1] Normalization |
| 149 | # Mean subtraction and Std dev scaling are applied as a pre-processing step outside the graph. |
| 150 | image = pad_crop(image) |
| 151 | image = image.resize((self.width, self.height), resample=Image.BICUBIC) |
| 152 | image = np.asarray(image, dtype=self.dtype) |
| 153 | image = image - np.asarray([123.68, 116.28, 103.53]) |
| 154 | image = image / np.asarray([58.395, 57.120, 57.375]) |
| 155 | else: |
| 156 | print("Preprocessing method {} not supported".format(self.preprocessor)) |
| 157 | sys.exit(1) |
| 158 | if self.format == "NCHW": |
| 159 | image = np.transpose(image, (2, 0, 1)) |
| 160 | return image |
| 161 |