Changes image intensity with gamma transform. Each pixel/voxel intensity is updated as:: x = ((x - min) / intensity_range) ^ gamma * intensity_range + min Args: gamma: gamma value to adjust the contrast as function. invert_image: whether to invert the image before
| 1182 | |
| 1183 | |
| 1184 | class AdjustContrast(Transform): |
| 1185 | """ |
| 1186 | Changes image intensity with gamma transform. Each pixel/voxel intensity is updated as:: |
| 1187 | |
| 1188 | x = ((x - min) / intensity_range) ^ gamma * intensity_range + min |
| 1189 | |
| 1190 | Args: |
| 1191 | gamma: gamma value to adjust the contrast as function. |
| 1192 | invert_image: whether to invert the image before applying gamma augmentation. If True, multiply all intensity |
| 1193 | values with -1 before the gamma transform and again after the gamma transform. This behaviour is mimicked |
| 1194 | from `nnU-Net <https://www.nature.com/articles/s41592-020-01008-z>`_, specifically `this |
| 1195 | <https://github.com/MIC-DKFZ/batchgenerators/blob/7fb802b28b045b21346b197735d64f12fbb070aa/batchgenerators/augmentations/color_augmentations.py#L107>`_ |
| 1196 | function. |
| 1197 | retain_stats: if True, applies a scaling factor and an offset to all intensity values after gamma transform to |
| 1198 | ensure that the output intensity distribution has the same mean and standard deviation as the intensity |
| 1199 | distribution of the input. This behaviour is mimicked from `nnU-Net |
| 1200 | <https://www.nature.com/articles/s41592-020-01008-z>`_, specifically `this |
| 1201 | <https://github.com/MIC-DKFZ/batchgenerators/blob/7fb802b28b045b21346b197735d64f12fbb070aa/batchgenerators/augmentations/color_augmentations.py#L107>`_ |
| 1202 | function. |
| 1203 | """ |
| 1204 | |
| 1205 | backend = [TransformBackends.TORCH, TransformBackends.NUMPY] |
| 1206 | |
| 1207 | def __init__(self, gamma: float, invert_image: bool = False, retain_stats: bool = False) -> None: |
| 1208 | if not isinstance(gamma, (int, float)): |
| 1209 | raise ValueError(f"gamma must be a float or int number, got {type(gamma)} {gamma}.") |
| 1210 | self.gamma = gamma |
| 1211 | self.invert_image = invert_image |
| 1212 | self.retain_stats = retain_stats |
| 1213 | |
| 1214 | def __call__(self, img: NdarrayOrTensor, gamma=None) -> NdarrayOrTensor: |
| 1215 | """ |
| 1216 | Apply the transform to `img`. |
| 1217 | gamma: gamma value to adjust the contrast as function. |
| 1218 | """ |
| 1219 | img = convert_to_tensor(img, track_meta=get_track_meta()) |
| 1220 | gamma = gamma if gamma is not None else self.gamma |
| 1221 | |
| 1222 | if self.invert_image: |
| 1223 | img = -img |
| 1224 | |
| 1225 | if self.retain_stats: |
| 1226 | mn = img.mean() |
| 1227 | sd = img.std() |
| 1228 | |
| 1229 | epsilon = 1e-7 |
| 1230 | img_min = img.min() |
| 1231 | img_range = img.max() - img_min |
| 1232 | ret: NdarrayOrTensor = ((img - img_min) / float(img_range + epsilon)) ** gamma * img_range + img_min |
| 1233 | |
| 1234 | if self.retain_stats: |
| 1235 | # zero mean and normalize |
| 1236 | ret = ret - ret.mean() |
| 1237 | ret = ret / (ret.std() + 1e-8) |
| 1238 | # restore old mean and standard deviation |
| 1239 | ret = sd * ret + mn |
| 1240 | |
| 1241 | if self.invert_image: |
no outgoing calls
searching dependent graphs…