{"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":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\nfrom tqdm import tqdm\n\n# Augmentations\nimport albumentations as A","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-02-08T09:40:08.663389Z","iopub.execute_input":"2022-02-08T09:40:08.663699Z","iopub.status.idle":"2022-02-08T09:40:10.963113Z","shell.execute_reply.started":"2022-02-08T09:40:08.663668Z","shell.execute_reply":"2022-02-08T09:40:10.962381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Matplotlib Setup\nplt.rcParams.update({'font.size': 15})\n\n# Global variables\nTRAIN_IMAGE_PATH = '../input/happy-whale-and-dolphin/train_images'\nTRAIN_CSV_PATH = '../input/happy-whale-and-dolphin/train.csv'","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:10.964332Z","iopub.execute_input":"2022-02-08T09:40:10.964534Z","iopub.status.idle":"2022-02-08T09:40:10.969207Z","shell.execute_reply.started":"2022-02-08T09:40:10.964510Z","shell.execute_reply":"2022-02-08T09:40:10.968478Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(TRAIN_CSV_PATH)\ndf['path'] = TRAIN_IMAGE_PATH+'/'+df['image']","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:10.970350Z","iopub.execute_input":"2022-02-08T09:40:10.970803Z","iopub.status.idle":"2022-02-08T09:40:11.095055Z","shell.execute_reply.started":"2022-02-08T09:40:10.970772Z","shell.execute_reply":"2022-02-08T09:40:11.094244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Cleaning","metadata":{}},{"cell_type":"code","source":"# Fixing misspellings\ndf['species'] = df['species'].replace({\n    'kiler_whale': 'killer_whale',\n    'bottlenose_dolpin': 'bottlenose_dolphin',\n    'globis': 'short_finned_pilot_whale'\n})","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:11.097786Z","iopub.execute_input":"2022-02-08T09:40:11.098153Z","iopub.status.idle":"2022-02-08T09:40:11.119733Z","shell.execute_reply.started":"2022-02-08T09:40:11.098109Z","shell.execute_reply":"2022-02-08T09:40:11.119051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Basic Explorations","metadata":{}},{"cell_type":"code","source":"df.head()","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:11.121531Z","iopub.execute_input":"2022-02-08T09:40:11.121756Z","iopub.status.idle":"2022-02-08T09:40:11.138872Z","shell.execute_reply.started":"2022-02-08T09:40:11.121730Z","shell.execute_reply":"2022-02-08T09:40:11.138046Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Number of images: {len(df)}\")\nprint(f\"Number of species: {df['species'].nunique()}\")\nprint(f\"Number of animals: {df['individual_id'].nunique()}\")","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:11.141488Z","iopub.execute_input":"2022-02-08T09:40:11.142234Z","iopub.status.idle":"2022-02-08T09:40:11.164015Z","shell.execute_reply.started":"2022-02-08T09:40:11.142200Z","shell.execute_reply":"2022-02-08T09:40:11.163155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Further Explorations","metadata":{}},{"cell_type":"markdown","source":"## Number of images per species","metadata":{}},{"cell_type":"code","source":"n_images_by_species = df.groupby('species')['image'].agg(len).sort_values()\nn_images_by_species.plot(kind='barh', figsize=(40,20))\n\nplt.xlabel('Number of images')","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:11.165058Z","iopub.execute_input":"2022-02-08T09:40:11.165264Z","iopub.status.idle":"2022-02-08T09:40:11.749988Z","shell.execute_reply.started":"2022-02-08T09:40:11.165238Z","shell.execute_reply":"2022-02-08T09:40:11.749183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Number of animals per species","metadata":{}},{"cell_type":"code","source":"n_animals_by_species = df.groupby('species')['individual_id'].agg(lambda x: x.nunique()).sort_values()\nn_animals_by_species.plot(kind='barh', figsize=(40,20))\n\nplt.xlabel('Number of unique animals')","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:11.751505Z","iopub.execute_input":"2022-02-08T09:40:11.751812Z","iopub.status.idle":"2022-02-08T09:40:12.315381Z","shell.execute_reply.started":"2022-02-08T09:40:11.751785Z","shell.execute_reply":"2022-02-08T09:40:12.314818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Interestingly, bottlenose dolphin, having the most images, are only the 6th in number of animals","metadata":{}},{"cell_type":"markdown","source":"## Number of images per animal","metadata":{}},{"cell_type":"code","source":"n_images_per_animal = df.groupby('individual_id')['image'].agg(len)\nn_images_per_animal.describe()","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:13.640270Z","iopub.execute_input":"2022-02-08T09:40:13.640668Z","iopub.status.idle":"2022-02-08T09:40:13.769534Z","shell.execute_reply.started":"2022-02-08T09:40:13.640631Z","shell.execute_reply":"2022-02-08T09:40:13.768762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_images_per_animal_by_species = df.groupby(['species', 'individual_id'])['image'].agg(len).groupby('species').mean().sort_values()\nn_images_per_animal_by_species.plot(kind='barh', figsize=(40,20))\n\nplt.title('Mean number of images per animal by species')\nplt.xlabel('Mean number of images per animal')","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:14.148523Z","iopub.execute_input":"2022-02-08T09:40:14.149190Z","iopub.status.idle":"2022-02-08T09:40:14.972896Z","shell.execute_reply.started":"2022-02-08T09:40:14.149146Z","shell.execute_reply":"2022-02-08T09:40:14.972101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_images_per_animal.plot(kind='hist',figsize=(40,20),logy=True,bins=100)\n\nplt.title('Distribution of number of images per animal, log scale')\nplt.xlabel('Number of images')\nplt.ylabel('Count of animals with X images')","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:24.092173Z","iopub.execute_input":"2022-02-08T09:40:24.092473Z","iopub.status.idle":"2022-02-08T09:40:25.202065Z","shell.execute_reply.started":"2022-02-08T09:40:24.092417Z","shell.execute_reply":"2022-02-08T09:40:25.201178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Summary","metadata":{}},{"cell_type":"code","source":"pd.DataFrame({\n    'Number of Images': n_images_by_species.index[-1:-6:-1],\n    'Number of Animals': n_animals_by_species.index[-1:-6:-1],\n    'Number of Images per animal': n_images_per_animal_by_species.index[-1:-6:-1]\n}, index = [\"1st\", \"2nd\", \"3rd\", \"4th\", \"5th\"])","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:25.203739Z","iopub.execute_input":"2022-02-08T09:40:25.203959Z","iopub.status.idle":"2022-02-08T09:40:25.216153Z","shell.execute_reply.started":"2022-02-08T09:40:25.203930Z","shell.execute_reply":"2022-02-08T09:40:25.215625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Images","metadata":{}},{"cell_type":"code","source":"def read_image(path):\n    return cv2.cvtColor(cv2.imread(path), cv2.COLOR_BGR2RGB) #BGR to RGB\ndef plot_images(paths, rows, cols, figsize):\n    fig, axes = plt.subplots(nrows = rows, ncols = cols, figsize=figsize)\n    plt.tight_layout(rect=[0, 0.03, 1, 0.97])\n\n    for path, ax in zip(paths, axes.flat):\n        img = read_image(path)\n        ax.imshow(img)\n        ax.axis('off')","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:58:07.352997Z","iopub.execute_input":"2022-02-08T09:58:07.353552Z","iopub.status.idle":"2022-02-08T09:58:07.360863Z","shell.execute_reply.started":"2022-02-08T09:58:07.353515Z","shell.execute_reply":"2022-02-08T09:58:07.359978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Image Samples","metadata":{}},{"cell_type":"code","source":"plot_images(df.sample(20, random_state = 0)['path'], 4, 5, (40,20))\nplt.suptitle('Random Subset of Images', fontsize=30)","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:58:08.032210Z","iopub.execute_input":"2022-02-08T09:58:08.033172Z","iopub.status.idle":"2022-02-08T09:58:28.036029Z","shell.execute_reply.started":"2022-02-08T09:58:08.033116Z","shell.execute_reply":"2022-02-08T09:58:28.035246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Image Resolutions\nImage reading takes too long, so I sampled a subset","metadata":{}},{"cell_type":"code","source":"image_sizes = np.array([cv2.imread(path).shape[:-1] for path in tqdm(df['path'].sample(500, random_state=0))])","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:40:39.178121Z","iopub.execute_input":"2022-02-08T09:40:39.178324Z","iopub.status.idle":"2022-02-08T09:40:43.845618Z","shell.execute_reply.started":"2022-02-08T09:40:39.178298Z","shell.execute_reply":"2022-02-08T09:40:43.844444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_sizes_df = pd.DataFrame(image_sizes, columns = ['height','width'])\nimage_sizes_df['pixels'] = image_sizes_df['height'] * image_sizes_df['width']\nimage_sizes_df.describe()","metadata":{"execution":{"iopub.status.busy":"2022-02-05T02:27:44.952185Z","iopub.execute_input":"2022-02-05T02:27:44.952515Z","iopub.status.idle":"2022-02-05T02:27:44.974273Z","shell.execute_reply.started":"2022-02-05T02:27:44.952483Z","shell.execute_reply":"2022-02-05T02:27:44.973716Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Images have quite high resolutions, on average 1500x2500","metadata":{}},{"cell_type":"markdown","source":"## Image Samples by Species","metadata":{}},{"cell_type":"code","source":"sampled_species = 'bottlenose_dolphin'\nplot_images(df[df['species'] == sampled_species].sample(20, random_state = 0)['path'], 4, 5, (40,20))\nplt.suptitle(sampled_species, fontsize=30)","metadata":{"execution":{"iopub.status.busy":"2022-02-05T02:38:23.657996Z","iopub.execute_input":"2022-02-05T02:38:23.658843Z","iopub.status.idle":"2022-02-05T02:38:53.237461Z","shell.execute_reply.started":"2022-02-05T02:38:23.658801Z","shell.execute_reply":"2022-02-05T02:38:53.236379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Image Samples by Id","metadata":{}},{"cell_type":"code","source":"sampled_id = 'abbeba14a290'\nplot_images(df[df['individual_id'] == sampled_id].sample(\n    min(len(df[df['individual_id'] == sampled_id]), 20),\n    random_state = 0\n)['path'], 4, 5, (40,20))\nplt.suptitle(sampled_id, fontsize=30)","metadata":{"execution":{"iopub.status.busy":"2022-02-05T02:39:02.808732Z","iopub.execute_input":"2022-02-05T02:39:02.809037Z","iopub.status.idle":"2022-02-05T02:39:11.58145Z","shell.execute_reply.started":"2022-02-05T02:39:02.809004Z","shell.execute_reply":"2022-02-05T02:39:11.580705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Lighting makes a huge difference","metadata":{}},{"cell_type":"markdown","source":"# Augmentations\nAll augmentations are done on a 224x224 random resized crop of the original image","metadata":{"execution":{"iopub.status.busy":"2022-02-04T09:46:39.560422Z","iopub.execute_input":"2022-02-04T09:46:39.560803Z","iopub.status.idle":"2022-02-04T09:46:39.565412Z","shell.execute_reply.started":"2022-02-04T09:46:39.560766Z","shell.execute_reply":"2022-02-04T09:46:39.564189Z"}}},{"cell_type":"code","source":"random_paths = df['path'].sample(4, random_state = 0) # For augmentation demonstrations\nrandom_paths","metadata":{"execution":{"iopub.status.busy":"2022-02-08T09:41:09.362289Z","iopub.execute_input":"2022-02-08T09:41:09.362511Z","iopub.status.idle":"2022-02-08T09:41:09.370962Z","shell.execute_reply.started":"2022-02-08T09:41:09.362484Z","shell.execute_reply":"2022-02-08T09:41:09.370471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_augmentations(paths, aug_transform, figsize, n_augs=4):\n    aug_transform = A.Compose([\n        A.Resize(224,224),\n        aug_transform\n    ])\n    fig, axes = plt.subplots(len(paths), n_augs + 1, figsize=figsize)\n    plt.tight_layout(rect=[0, 0.03, 1, 0.94])\n    \n    axes[0][0].set_title('Original', fontsize=30)\n    for i in range(n_augs):\n        axes[0][i+1].set_title(f\"Augmentation {i+1}\", fontsize=30)\n    \n    for row, path in enumerate(paths):\n        img = read_image(path)\n        axes[row][0].imshow(img)\n        axes[row][0].axis('off')\n        \n        for aug in range(1, n_augs+1):\n            axes[row][aug].imshow(aug_transform(image=img)['image'])\n            axes[row][aug].axis('off')","metadata":{"execution":{"iopub.status.busy":"2022-02-08T10:01:03.385165Z","iopub.execute_input":"2022-02-08T10:01:03.385466Z","iopub.status.idle":"2022-02-08T10:01:03.396374Z","shell.execute_reply.started":"2022-02-08T10:01:03.385420Z","shell.execute_reply":"2022-02-08T10:01:03.395696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Horizontal Flip\n","metadata":{}},{"cell_type":"code","source":"hflip_transform = A.HorizontalFlip(p=0.5)\nplot_augmentations(random_paths, hflip_transform, (40,20))\n\nplt.suptitle('Horizontal Flip with probability 0.5', fontsize=35)","metadata":{"execution":{"iopub.status.busy":"2022-02-08T10:01:08.989127Z","iopub.execute_input":"2022-02-08T10:01:08.989354Z","iopub.status.idle":"2022-02-08T10:01:12.609560Z","shell.execute_reply.started":"2022-02-08T10:01:08.989324Z","shell.execute_reply":"2022-02-08T10:01:12.607979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Brightness Change","metadata":{}},{"cell_type":"code","source":"brightness_transform = A.RandomBrightness(0.5)\nplot_augmentations(random_paths, brightness_transform, (40,20))\n\nplt.suptitle('Random brightness change with brightness=0.5', fontsize=35)","metadata":{"execution":{"iopub.status.busy":"2022-02-08T10:01:05.391088Z","iopub.execute_input":"2022-02-08T10:01:05.391415Z","iopub.status.idle":"2022-02-08T10:01:08.987735Z","shell.execute_reply.started":"2022-02-08T10:01:05.391384Z","shell.execute_reply":"2022-02-08T10:01:08.986599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Rotation","metadata":{}},{"cell_type":"code","source":"rot_transform = A.Rotate((0, 45))\nplot_augmentations(random_paths, rot_transform, (40,20))\n\nplt.suptitle('Random rotation between 0 and 45 degrees', fontsize=35)","metadata":{"execution":{"iopub.status.busy":"2022-02-08T10:01:51.162207Z","iopub.execute_input":"2022-02-08T10:01:51.162505Z","iopub.status.idle":"2022-02-08T10:01:54.888278Z","shell.execute_reply.started":"2022-02-08T10:01:51.162470Z","shell.execute_reply":"2022-02-08T10:01:54.887402Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Fog","metadata":{}},{"cell_type":"code","source":"fog_transform = A.RandomFog()\nplot_augmentations(random_paths, fog_transform, (40,20))\n\nplt.suptitle('Random perspective change with distortion_scale=0.4', fontsize=35)","metadata":{"execution":{"iopub.status.busy":"2022-02-08T10:02:56.104738Z","iopub.execute_input":"2022-02-08T10:02:56.105209Z","iopub.status.idle":"2022-02-08T10:03:00.004959Z","shell.execute_reply.started":"2022-02-08T10:02:56.105175Z","shell.execute_reply":"2022-02-08T10:03:00.001129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# All combined","metadata":{}},{"cell_type":"code","source":"all_aug = A.Compose([\n    hflip_transform,\n    brightness_transform,\n    rot_transform,\n    fog_transform\n])\nplot_augmentations(random_paths, all_aug, (40,20))\nplt.suptitle('All Augmentations combined', fontsize=35)","metadata":{"execution":{"iopub.status.busy":"2022-02-08T10:03:31.554472Z","iopub.execute_input":"2022-02-08T10:03:31.555005Z","iopub.status.idle":"2022-02-08T10:03:36.166556Z","shell.execute_reply.started":"2022-02-08T10:03:31.554971Z","shell.execute_reply":"2022-02-08T10:03:36.165501Z"},"trusted":true},"execution_count":null,"outputs":[]}]}