{"cells":[{"metadata":{},"cell_type":"markdown","source":"<h1>Cassava leaf identification - Visually inspecting images</h1>\n    \nIn this notebook I'll:\n\n<ul>\n    <li>Inspect images of all the categories (different diseases and healthy plants) to get a sense of how difficult it is even for a human to visually classify an image</li>\n    <li>Try different data agumentations and their parameters to create realistic augmentations that help enhance the model</li>\n</ul>"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Imports\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nimport os\nimport cv2\n\nimport albumentations as A","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Definitions\n\nCOMPETITION_DIR = '../input/cassava-leaf-disease-classification'\nTRAIN_DIR = '../input/cassava-leaf-disease-classification/train_images'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>Read data</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Train data\n\ntrain = pd.read_csv(os.path.join(COMPETITION_DIR, 'train.csv'))\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a series to map labels to labels' descriptions\n\ndisease_labels = pd.read_json(os.path.join(COMPETITION_DIR, 'label_num_to_disease_map.json'), typ='series')\ndisease_labels","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>Basic numbers<h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# How many images do we have for every disease?\n\nfrequency = train.groupby('label', as_index=False).agg(count=('image_id', 'count'))\nfrequency['disease'] = frequency.label.map(disease_labels)\nfrequency['fraction'] = frequency['count'] / frequency['count'].sum()\nfrequency = frequency[['label', 'disease', 'count', 'fraction']]\nfrequency","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The train set is imbalanced. We see that more than 60% of images correspond to the <b>Cassava Mosaic Disease (CMD)</b>. The lease frequent disease is <b>Cassava Bacterial Blight (CBB)</b> with roughly 5% of the images. The other two diseases, CBSD and CGM have similar percentage around 10%. Healthy images represent 12% of the total."},{"metadata":{},"cell_type":"markdown","source":"<h2>Show images</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Utility functions\n\ndef show_single_image(idx):\n    \n    img = plt.imread(os.path.join(TRAIN_DIR, train.loc[idx,'image_id']))\n    label = train.loc[idx, 'label']\n    plt.figure(figsize=(10,8))\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\n    plt.title(f'{idx}: {disease_labels[label]}')\n    plt.tight_layout()\n    \n    \ndef show_random_images(disease=None, nrows=3, ncols=5):   \n    \n    if disease is None:\n        population = train.index.values\n    else:\n        population = train.loc[train.label == disease].index.values\n    \n    indices = np.random.choice(population, nrows * ncols)\n    \n    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(5*ncols, 4*nrows), constrained_layout=True)\n    ax = ax.reshape(-1)\n                           \n    fig.suptitle(disease_labels[disease])\n    \n    # Iterate and plot random images\n    for i in range(nrows*ncols):\n        img = plt.imread(os.path.join(TRAIN_DIR, train.loc[indices[i],'image_id']))\n        label = train.loc[indices[i], 'label']\n        ax[i].imshow(img, cmap='gray')\n        ax[i].set_title(f'{indices[i]}')\n        ax[i].axis('off')\n    \n    #plt.tight_layout()\n    plt.show()\n    \n\ndef show_images(images, labels, nrows, ncols, suptitle=''):   \n    \n    assert len(images) == nrows * ncols\n    assert len(labels) == nrows * ncols\n    \n    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(5*ncols, 4*nrows), constrained_layout=True)\n    ax = ax.reshape(-1)\n                           \n    fig.suptitle(suptitle)\n    \n    # Iterate and plot random images\n    for i in range(nrows*ncols):\n        ax[i].imshow(images[i], cmap='gray')\n        ax[i].set_title(f'{labels[i]}')\n        ax[i].axis('off')\n    \n    plt.show()\n\ndef read_train_image(idx):\n    file_path = os.path.join(TRAIN_DIR, train.loc[idx, 'image_id'])\n    image = cv2.imread(file_path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    return image\n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>Disease inspection</h2>\n\nLet's show some images to check how difficult it is to diagnose the differente diseases by visual inspection."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Seed for reproducibility\n\nnp.random.seed(42)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3>Cassava Bacterial Blight</h3>\n\nAt first, angular, water-soaked spots occur on the leaves which are restricted by the veins; the spots are more clearly seen on the lower leaf surface. The spots expand rapidly, join together, especially along the margins of the leaves, and turn brown with yellow borders. Droplets of a creamy-white ooze occur at the centre of the spots; later, they turn yellow. "},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# Cassava Bacterial Blight (CBB)\nshow_random_images(disease=0, nrows=3, ncols=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3>Cassave Brown Streak Disease</h3>\n\nSymptoms of cassava brown streak disease appear as patches of yellow areas mixed with normal green colour. This phenomenon is commonly referred to as chlorosis. It produces characteristic yellow or necrotic vein banding on leaves which may enlarge and join to form comparatively large yellow or necrotic patches. The yellow patches are more prominent on mature (bottom) leaves than younger ones. The infected leaves do not become distorted in shape as occurs with leaves infected by Cassava mosaic disease. Advanced symptoms on the leaves become an irregular yellow blotchy chlorosis that is most pronounced in the periphery (margins or edge) of lower leaves. "},{"metadata":{"trusted":true},"cell_type":"code","source":"# Cassava Brown Streak Disease (CBSD)\nshow_random_images(disease=1, nrows=3, ncols=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3>Cassava Green Mottle</h3>\n\nYoung leaves are puckered with faint to distinct yellow spots, green patterns (mosaics), and twisted margins.\n    "},{"metadata":{"trusted":true},"cell_type":"code","source":"# Cassava Green Mottle (CGM)\nshow_random_images(disease=2, nrows=3, ncols=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3>Cassava Mosaic Disease (CMD)</h3>\n\nCharacteristic leaf mosaic patterns that affect discrete areas and determined at an early stage of leaf development. The chlorotic areas fail to expand fully so that stresses set up by unequal expansion of the lamina cause malformation and distortion. Severely affected leaves are reduced in size, misshapen and twisted, with yello areas separated by areas of normal green colour. The leaf chlorosis may be pale yellow or nearly white, or just discernibly paler than normal. The chlorotic areas are usually clearly demarcated and vary in size from the whole leaflet to small flecks or spots. Leaflets may show a uniform mosaic pattern or the pattern is localised to a few areas which are often at the bases of the leaflets."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Cassava Mosaic Disease (CMD)\nshow_random_images(disease=3, nrows=3, ncols=4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Inspect a single image\n\nshow_single_image(17173)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>Albumentations transformations</h2>\n\nPlay with different albumentations transformations and their parameters to choose the most appropriate for the dataset."},{"metadata":{},"cell_type":"markdown","source":"<h2>HorizontalFlip</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = read_train_image(4573)\ntransform = A.HorizontalFlip(p=1)\ntransformed = transform(image=img)['image']\nshow_images([img, transformed], ['Original', 'Flipped'], nrows=1, ncols=2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>RandomSizedCrop</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = read_train_image(1924)\nimages = [img]\nlabels = ['Original']\ntransform = A.RandomSizedCrop(min_max_height=[256, 600], height=512, width=512, p=1)\nfor i in range(8):\n    transformed = transform(image=img)['image']\n    images.append(transformed)\n    labels.append(str(i + 1))\n\nshow_images(images, labels, nrows=3, ncols=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>GaussianBlur</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = read_train_image(17665)\nimages = [img]\nlabels = ['Original']\ntransform = A.GaussianBlur(blur_limit=[5,11], p=0.5)\nfor i in range(8):\n    transformed = transform(image=img)['image']\n    images.append(transformed)\n    labels.append(str(i + 1))\n\nshow_images(images, labels, nrows=3, ncols=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>Rotate</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = read_train_image(17665)\nimages = [img]\nlabels = ['Original']\ntransform = A.Rotate(limit=20, p=1)\nfor i in range(8):\n    transformed = transform(image=img)['image']\n    images.append(transformed)\n    labels.append(str(i + 1))\n\nshow_images(images, labels, nrows=3, ncols=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>RandomBrightnessContrast</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = read_train_image(17665)\nimages = [img]\nlabels = ['Original']\ntransform = A.RandomBrightnessContrast(brightness_limit=0.3, contrast_limit=0.3, p=1)\nfor i in range(11):\n    transformed = transform(image=img)['image']\n    images.append(transformed)\n    labels.append(str(i + 1))\n\nshow_images(images, labels, nrows=3, ncols=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>CenterCrop</h2>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = read_train_image(16705)\nimages = [img]\nlabels = ['Original']\ntransform = A.CenterCrop(width=512, height=512, p=1)\nfor i in range(11):\n    transformed = transform(image=img)['image']\n    images.append(transformed)\n    labels.append(str(i + 1))\n\nshow_images(images, labels, nrows=3, ncols=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2>Several transforms</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = read_train_image(16705)\nimages = [img]\nlabels = ['Original']\n\ntransform = A.Compose([\n    A.RandomResizedCrop(512, 512),\n    A.Transpose(p=0.5),\n    A.HorizontalFlip(p=0.5),\n    A.VerticalFlip(p=0.1),\n    A.ShiftScaleRotate(p=0.5),\n    A.GaussianBlur(blur_limit=[5,11], p=0.5),\n    A.HueSaturationValue(hue_shift_limit=0.2, sat_shift_limit=0.2, val_shift_limit=0.2, p=0.5),\n    A.RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1,0.1), p=0.5),\n    A.CoarseDropout(p=0.5),\n    A.Cutout(p=0.5)\n], p=1.0)\n\n\nfor i in range(11):\n    transformed = transform(image=img)['image']\n    images.append(transformed)\n    labels.append('T' + str(i + 1))\n\nshow_images(images, labels, nrows=3, ncols=4)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}