{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Image Augmentation with Albumentations - Melanoma Dataset","metadata":{}},{"cell_type":"markdown","source":"Sources:\n- https://www.kaggle.com/stopwhispering/augmentation-w-albumentations-melanoma-dataset/edit","metadata":{}},{"cell_type":"code","source":"# running interactively in kaggle or as background job in kaggle\nimport os\nif (get_ipython().config.IPKernelApp.connection_file.startswith('/root/.local/share')\n    or 'SHLVL' in os.environ):\n    BASE_PATH = '/kaggle/input/'\n    \nelse:\n    BASE_PATH = '../data/'","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pathlib import Path\nfrom typing import Union\nimport math\n\nimport albumentations\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport cv2","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-09-24T11:06:24.471242Z","iopub.execute_input":"2023-09-24T11:06:24.471684Z","iopub.status.idle":"2023-09-24T11:06:25.989601Z","shell.execute_reply.started":"2023-09-24T11:06:24.471649Z","shell.execute_reply":"2023-09-24T11:06:25.988668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Data ","metadata":{}},{"cell_type":"code","source":"image_names = ('ISIC_0015719', 'ISIC_0074311', 'ISIC_0083035', 'ISIC_0078712')  # , 'ISIC_0084395')\nimage_paths = [Path(f'{BASE_PATH}siim-isic-melanoma-classification/jpeg/train/{image_name}.jpg') for image_name in image_names]\nimages = [plt.imread(path) for path in image_paths]  # list of np.ndarray (height, width, 3), uint8, values 0..255\n \nfor image in images:\n    print(image.shape, image.dtype, image.min(), image.max())","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:26.104995Z","iopub.execute_input":"2023-09-24T11:06:26.105819Z","iopub.status.idle":"2023-09-24T11:06:27.189748Z","shell.execute_reply.started":"2023-09-24T11:06:26.105773Z","shell.execute_reply":"2023-09-24T11:06:27.188488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Utility Functions","metadata":{}},{"cell_type":"code","source":"def plot_images(images: list[Union[np.array, list[np.array]]], \n                suptitle='', \n                titles=[], \n                display_shape=False,\n                cmap='gray'):  # (n, width, length)\n    \n    assert len(set(len(i) for i in images)) == 1\n    assert len(titles) == 0 or len(titles) == len(images)\n    n_cols = len(images[0])\n    n_rows = len(images)\n    \n    fig, axes = plt.subplots(nrows=n_rows, \n                             ncols=n_cols,\n                             figsize=(n_cols*6, n_rows*4))\n    \n    if len(axes.shape) == 1:\n        axes = axes.reshape(1, n_cols)  # for convenience: (n_cols,) -> (1, n_cols)\n    \n    for row_idx, sub_images in enumerate(images):  # sub_images: list of images or np.ndarray of size (n,h,w,c)\n        \n        if titles:\n            axes[row_idx, 0].set_title(titles[row_idx], fontsize=26)\n                 \n        for col_idx, image in enumerate(sub_images):  # image: np.ndarray\n            \n            ax = axes[row_idx, col_idx]\n            ax.imshow(X=image,\n                      cmap=cmap)  # plt.cm.bone\n            ax.set_xticks([])\n            ax.set_yticks([])\n            \n            if display_shape:\n                ax.set_title(image.shape if not ax.get_title() else f'{ax.get_title()} {image.shape}')\n        \n    if suptitle:\n        plt.suptitle(suptitle, fontsize=30)\n    \n    # plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:27.193021Z","iopub.execute_input":"2023-09-24T11:06:27.193396Z","iopub.status.idle":"2023-09-24T11:06:27.207344Z","shell.execute_reply.started":"2023-09-24T11:06:27.193364Z","shell.execute_reply":"2023-09-24T11:06:27.205855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# original images only\nplot_images([images], titles=['Original'], display_shape=True)","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:27.208738Z","iopub.execute_input":"2023-09-24T11:06:27.209073Z","iopub.status.idle":"2023-09-24T11:06:38.305602Z","shell.execute_reply.started":"2023-09-24T11:06:27.209046Z","shell.execute_reply":"2023-09-24T11:06:38.304387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Augmentation","metadata":{}},{"cell_type":"markdown","source":"Input of albumentation transforms must be a np.array for a single image.\n- No batch processing.\n- No tensors.","metadata":{}},{"cell_type":"code","source":"height = 200\nwidth = 600\n\n# resize  - Resize exactly to the given height and width\ntransform = albumentations.Resize(height=height, \n                                  width=width, \n                                  p=1,  # default: 1 \n                                  interpolation=cv2.INTER_LINEAR  # default: cv2.INTER_LINEAR\n                                 )\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\n# resize w/ LongestMaxSize - Rescale so that maximum side is equal to max_size, keeping the aspect ratio \ntransform2 = albumentations.augmentations.geometric.resize.LongestMaxSize(max_size=600,\n                                                                          p=1)\ntransformed2 = [transform2(image=image) for image in images]\ntransformed_images2 = [t['image'] for t in transformed2]\n\nplot_images([images, transformed_images, transformed_images2], \n            suptitle='Resize/Rescale', \n            titles=['Original', 'Resized', 'Resized LongestMaxSize'],\n            display_shape=True)\n\n# for performance, we will use the rescaled images below\n# in a productive project, one will resize to the the end of the pipeline!\nimages = transformed_images2","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:38.307514Z","iopub.execute_input":"2023-09-24T11:06:38.308364Z","iopub.status.idle":"2023-09-24T11:06:50.926654Z","shell.execute_reply.started":"2023-09-24T11:06:38.308317Z","shell.execute_reply":"2023-09-24T11:06:50.925412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# transpose - swap rows and columns\ntransform = albumentations.Transpose(p=1)\n\n# albumentations transforms <<one>> image (can't provide whole batch)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\n\nplot_images([images, transformed_images], \n            suptitle='Transpose', \n            titles=['Original', 'Transposed'],\n            display_shape=True)","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:50.928335Z","iopub.execute_input":"2023-09-24T11:06:50.928751Z","iopub.status.idle":"2023-09-24T11:06:52.331144Z","shell.execute_reply.started":"2023-09-24T11:06:50.928718Z","shell.execute_reply":"2023-09-24T11:06:52.329869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# transpose - swap rows and columns","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:52.332542Z","iopub.execute_input":"2023-09-24T11:06:52.332888Z","iopub.status.idle":"2023-09-24T11:06:52.338245Z","shell.execute_reply.started":"2023-09-24T11:06:52.332859Z","shell.execute_reply":"2023-09-24T11:06:52.337137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# VerticalFlip - Flip vertically around the x-axis.\ntransform = albumentations.VerticalFlip(p=1)\n\n# albumentations transforms <<one>> image (can't provide whole batch)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'VerticalFlip'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:52.339589Z","iopub.execute_input":"2023-09-24T11:06:52.340581Z","iopub.status.idle":"2023-09-24T11:06:53.961840Z","shell.execute_reply.started":"2023-09-24T11:06:52.340545Z","shell.execute_reply":"2023-09-24T11:06:53.960772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# HorizontalFlip - Flip horizontally around the y-axis.\ntransform = albumentations.HorizontalFlip(p=1)\n\n# albumentations transforms <<one>> image (can't provide whole batch)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'HorizontalFlip'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:53.963221Z","iopub.execute_input":"2023-09-24T11:06:53.963592Z","iopub.status.idle":"2023-09-24T11:06:55.571630Z","shell.execute_reply.started":"2023-09-24T11:06:53.963562Z","shell.execute_reply":"2023-09-24T11:06:55.570334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# RandomBrightnessContrast  - Randomly change brightness and contrast\n\n# The parameters are random for <<each image>> that is processed!\ntransform = albumentations.RandomBrightnessContrast (brightness_limit=0.2, \n                                                     contrast_limit=0.2, \n                                                     p=1)\n\n# albumentations transforms <<one>> image (can't provide whole batch)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'RandomBrightnessContrast'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:55.573034Z","iopub.execute_input":"2023-09-24T11:06:55.573415Z","iopub.status.idle":"2023-09-24T11:06:57.355175Z","shell.execute_reply.started":"2023-09-24T11:06:55.573384Z","shell.execute_reply":"2023-09-24T11:06:57.353878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Blur / Noise\n\ntransform1 = albumentations.MotionBlur(blur_limit=7,\n                                       p=1)\ntransform2 = albumentations.MedianBlur(blur_limit=7,\n                                       p=1)\ntransform3 = albumentations.GaussianBlur(blur_limit=(3,7),\n                                         p=1)\ntransform4 = albumentations.GaussNoise(var_limit=(10.0, 50.0),\n                                         p=1)\n\ntransformed1 = [transform1(image=image) for image in images]\ntransformed2 = [transform2(image=image) for image in images]\ntransformed3 = [transform3(image=image) for image in images]\ntransformed4 = [transform4(image=image) for image in images]\n\ntransformed_images1 = [t['image'] for t in transformed1]\ntransformed_images2 = [t['image'] for t in transformed2]\ntransformed_images3 = [t['image'] for t in transformed3]\ntransformed_images4 = [t['image'] for t in transformed4]\n\nplot_images([images, transformed_images1, transformed_images2, transformed_images3, transformed_images4],\n            titles=['Original', 'MotionBlur', 'MedianBlur', 'GaussianBlur', 'GaussNoise'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:06:57.356826Z","iopub.execute_input":"2023-09-24T11:06:57.357205Z","iopub.status.idle":"2023-09-24T11:07:01.271207Z","shell.execute_reply.started":"2023-09-24T11:06:57.357170Z","shell.execute_reply":"2023-09-24T11:07:01.269737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Apply only one random Blur/Noise to each Image\ntransform = albumentations.OneOf([\n    albumentations.MotionBlur(blur_limit=15),\n    albumentations.MedianBlur(blur_limit=15),\n    albumentations.GaussianBlur(blur_limit=(3,7)),\n    albumentations.GaussNoise(var_limit=(20, 80))], \n    p=1)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'OneOf Blur/Noise'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:01.276140Z","iopub.execute_input":"2023-09-24T11:07:01.276568Z","iopub.status.idle":"2023-09-24T11:07:02.859130Z","shell.execute_reply.started":"2023-09-24T11:07:01.276532Z","shell.execute_reply":"2023-09-24T11:07:02.857487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Distortions\n\ntransform1 = albumentations.OpticalDistortion(distort_limit=1.0,\n                                              p=1)\ntransform2 = albumentations.GridDistortion(num_steps=5, \n                                           distort_limit=1,\n                                           p=1)\ntransform3 = albumentations.ElasticTransform(alpha=3,\n                                             p=1)\n\ntransformed1 = [transform1(image=image) for image in images]\ntransformed2 = [transform2(image=image) for image in images]\ntransformed3 = [transform3(image=image) for image in images]\n\ntransformed_images1 = [t['image'] for t in transformed1]\ntransformed_images2 = [t['image'] for t in transformed2]\ntransformed_images3 = [t['image'] for t in transformed3]\n\nplot_images([images, transformed_images1, transformed_images2, transformed_images3],\n            titles=['Original', 'OpticalDistortion', 'GridDistortion', 'ElasticTransform'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:02.860969Z","iopub.execute_input":"2023-09-24T11:07:02.861391Z","iopub.status.idle":"2023-09-24T11:07:07.476131Z","shell.execute_reply.started":"2023-09-24T11:07:02.861355Z","shell.execute_reply":"2023-09-24T11:07:07.474246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Apply only one distortion to each Image\ntransform = albumentations.OneOf([\n    albumentations.OpticalDistortion(distort_limit=0.5),\n    albumentations.GridDistortion(num_steps=5,\n                                  distort_limit=0.5),\n    albumentations.ElasticTransform(alpha=1.5)],\n    p=1)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'OneOf Distortion'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:07.478181Z","iopub.execute_input":"2023-09-24T11:07:07.478623Z","iopub.status.idle":"2023-09-24T11:07:09.387853Z","shell.execute_reply.started":"2023-09-24T11:07:07.478589Z","shell.execute_reply":"2023-09-24T11:07:09.386432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# CLAHE - Apply Contrast Limited Adaptive Histogram Equalization\ntransform = albumentations.CLAHE(clip_limit=2.0,\n                                 p=1)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'CLAHE'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:09.389275Z","iopub.execute_input":"2023-09-24T11:07:09.389646Z","iopub.status.idle":"2023-09-24T11:07:11.094684Z","shell.execute_reply.started":"2023-09-24T11:07:09.389615Z","shell.execute_reply":"2023-09-24T11:07:11.093326Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# HueSaturationValue - Randomly change hue, saturation and value\ntransform = albumentations.HueSaturationValue (hue_shift_limit=10, \n                                               sat_shift_limit=20, \n                                               val_shift_limit=8,\n                                               p=1)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'HueSaturationValue'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:11.096470Z","iopub.execute_input":"2023-09-24T11:07:11.097193Z","iopub.status.idle":"2023-09-24T11:07:12.708330Z","shell.execute_reply.started":"2023-09-24T11:07:11.097149Z","shell.execute_reply":"2023-09-24T11:07:12.706865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ShiftScaleRotate - Randomly apply affine transforms: translate, scale and rotate\ntransform = albumentations.ShiftScaleRotate (shift_limit=0.1, \n                                             scale_limit=0.1, \n                                             rotate_limit=15, \n                                             border_mode=cv2.BORDER_REFLECT_101,  # default: cv2.BORDER_REFLECT_101\n                                             p=1)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'ShiftScaleRotate'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:12.710217Z","iopub.execute_input":"2023-09-24T11:07:12.710984Z","iopub.status.idle":"2023-09-24T11:07:14.366065Z","shell.execute_reply.started":"2023-09-24T11:07:12.710938Z","shell.execute_reply":"2023-09-24T11:07:14.364442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Cutout - CoarseDropout of the square regions in the image.\nprint('Width: ', width)\nprint('Height: ', height)\ntransform = albumentations.Cutout(max_h_size=int(height * 0.375), \n                                  max_w_size=int(width * 0.375), \n                                  num_holes=1,\n                                  p=1)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'Cutout'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:14.367585Z","iopub.execute_input":"2023-09-24T11:07:14.367984Z","iopub.status.idle":"2023-09-24T11:07:16.212736Z","shell.execute_reply.started":"2023-09-24T11:07:14.367948Z","shell.execute_reply":"2023-09-24T11:07:16.211593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Normalize - formula: img = (img - mean * max_pixel_value) / (std * max_pixel_value)\nprint([(i.shape, i.dtype, i.min(), i.max()) for i in images])\ntransform = albumentations.Normalize(p=1, mean=0.0, std=1.0)\ntransformed = [transform(image=image) for image in images]\ntransformed_images = [t['image'] for t in transformed]  # from uint8 0..255 to float32 0.0..1.0\nprint([(i.shape, i.dtype, i.min(), i.max()) for i in transformed_images])\n\nplot_images([images, transformed_images],\n            titles=['Original', 'Normalize'])","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:16.214281Z","iopub.execute_input":"2023-09-24T11:07:16.215355Z","iopub.status.idle":"2023-09-24T11:07:18.000205Z","shell.execute_reply.started":"2023-09-24T11:07:16.215308Z","shell.execute_reply":"2023-09-24T11:07:17.998985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Compose transforms","metadata":{}},{"cell_type":"code","source":"height = 400\nwidth = 600\n\n# Train Example:\ntransform_train = albumentations.Compose([\n    albumentations.Transpose(p=0.5),\n    albumentations.VerticalFlip(p=0.5),\n    albumentations.HorizontalFlip(p=0.5),\n    albumentations.RandomBrightnessContrast (brightness_limit=0.2, \n                                             contrast_limit=0.2,\n                                             p=0.75),\n    albumentations.OneOf([\n        albumentations.MotionBlur(blur_limit=5),\n        albumentations.MedianBlur(blur_limit=5),\n        albumentations.GaussianBlur(blur_limit=(3,7)),\n        albumentations.GaussNoise(var_limit=(7.0, 40.0)),\n    ], p=0.7),\n\n    albumentations.OneOf([\n        albumentations.OpticalDistortion(distort_limit=1.0),\n        albumentations.GridDistortion(num_steps=5, distort_limit=1.),\n        albumentations.ElasticTransform(alpha=3),\n    ], p=0.7),\n\n    albumentations.CLAHE(clip_limit=3.0, p=0.7),\n    albumentations.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, val_shift_limit=8, p=0.5),\n    albumentations.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.1, rotate_limit=15, border_mode=cv2.BORDER_REFLECT_101, p=0.85),\n    albumentations.Resize(height=height,\n                          width=width,),\n    albumentations.Cutout(max_h_size=int(height * 0.375), max_w_size=int(width * 0.375), num_holes=1, p=0.7),\n    albumentations.Normalize(mean=0.0, std=1.0)\n])\n\ntransformed_images1 = [transform_train(image=image)['image'] for image in images]\ntransformed_images2 = [transform_train(image=image)['image'] for image in images]\ntransformed_images3 = [transform_train(image=image)['image'] for image in images]\ntransformed_images4 = [transform_train(image=image)['image'] for image in images]\n\nplot_images([images, transformed_images1, transformed_images2, transformed_images3, transformed_images4],\n            titles=['Original', 'Transformed 1', 'Transformed 2', 'Transformed 3', 'Transformed 4'],\n            display_shape=True)","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:18.001840Z","iopub.execute_input":"2023-09-24T11:07:18.002532Z","iopub.status.idle":"2023-09-24T11:07:22.710281Z","shell.execute_reply.started":"2023-09-24T11:07:18.002495Z","shell.execute_reply":"2023-09-24T11:07:22.708330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Corresponding Validation:\ntransform_val = albumentations.Compose([\n    albumentations.Resize(height=height,\n                          width=width,),\n    albumentations.Normalize(mean=0.0, std=1.0)\n])\n\ntransformed_images = [transform_val(image=image)['image'] for image in images]\n\nplot_images([images, transformed_images],\n            titles=['Original', 'Transformed'],\n            display_shape=True)","metadata":{"execution":{"iopub.status.busy":"2023-09-24T11:07:22.712151Z","iopub.execute_input":"2023-09-24T11:07:22.712568Z","iopub.status.idle":"2023-09-24T11:07:24.634429Z","shell.execute_reply.started":"2023-09-24T11:07:22.712535Z","shell.execute_reply":"2023-09-24T11:07:24.633257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}