{"cells":[{"metadata":{},"cell_type":"markdown","source":"**Shallow clouds play a huge role in determining the Earth's climate. They’re also difficult to understand and to represent in climate models. By classifying different types of cloud organization, researchers at Max Planck hope to improve our physical understanding of these clouds, which in turn will help us build better climate models.**"},{"metadata":{},"cell_type":"markdown","source":"## A brief history about the purpose of this competition\n\nIt all started around two years ago at a workshop where 12 cloud experts came together to discuss shallow clouds over the ocean. These clouds look benign compared to big thunderstorms but, in fact, for the Earth’s climate they play a huge role. The reason is that they reflect a lot of sunlight back into space, thereby cooling our planet, while only contributing marginally to the greenhouse effect. This means that it’s really important to figure out how these clouds will change as our planet warms. Current climate models, however, struggle with that. They do not even agree whether there will be more or less of these shallow clouds.\n\n\nPart of the reason is that shallow clouds aren’t just the result of the global circulation of the atmosphere. Rather, they have a life of their own and arrange themselves in a variety of patterns. For many of these patterns, the basic mechanisms behind them are poorly understood. This brings us back to our group of scientists. As they were looking through hundreds of satellite images like the ones shown on this page, they noticed that some structures occur more often than others. After some discussion, they agreed on four common patterns and called them Sugar, Flower, Fish and Gravel.\n\n![](https://miro.medium.com/max/1050/1*Wz8Rosw9W0VDorCwcLIxkg.png)\n\nSource: Awesome article by Stephan Rasp https://medium.com/@raspstephan"},{"metadata":{},"cell_type":"markdown","source":"# Let's dive in the clouds and explore the data"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd\npd.set_option(\"display.max_rows\", 100)\nimport os\nprint(os.listdir(\"../input\"))\n# print(os.listdir(\"../\"))\nimport cv2\nimport json\nimport matplotlib.pyplot as plt\n%matplotlib inline\nplt.rcParams[\"font.size\"] = 14\nimport seaborn as sns\nfrom collections import Counter\nfrom PIL import Image\nimport math\nimport seaborn as sns\nfrom collections import defaultdict\nfrom pathlib import Path\nimport cv2\nfrom tqdm import tqdm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(\"../input/understanding_cloud_organization/train.csv\")\nsample_df = pd.read_csv(\"../input/understanding_cloud_organization/sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(f'There are {train_df.shape[0]} records in train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['Image_Label'].apply(lambda x : x.split('_')[1]).value_counts().plot(kind='bar')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We have approx 5.5k images in train dataset and they can have up to 4 masks: Fish, Flower, Gravel and Sugar."},{"metadata":{"trusted":true},"cell_type":"code","source":"len_train = len(os.listdir(\"../input/understanding_cloud_organization/train_images\"))\nlen_test = len(os.listdir(\"../input/understanding_cloud_organization/test_images\"))\nprint(f'There are {len_train} images in train dataset')\nprint(f'There are {len_test} images in test dataset')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Figuring out the total number of images having empty masks."},{"metadata":{"trusted":true},"cell_type":"code","source":"len(train_df[train_df['EncodedPixels'].isnull()])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Label wise breakdown of empty masks."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.loc[train_df['EncodedPixels'].isnull(), 'Image_Label'].apply(lambda x: x.split('_')[1]).value_counts().plot(kind=\"bar\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Count of labels having mask data"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.loc[train_df['EncodedPixels'].isnull() == False, 'Image_Label'].apply(lambda x: x.split('_')[1]).value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Images having multiple masks"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.loc[train_df['EncodedPixels'].isnull() == False, 'Image_Label'].apply(lambda x: x.split('_')[0]).value_counts().value_counts().plot(kind=\"bar\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can see that there are significant number of images having 2 masks and also a few of them having 4 masks."},{"metadata":{},"cell_type":"markdown","source":"## Checking image size for train and test"},{"metadata":{},"cell_type":"markdown","source":"Check the size of each image in the dataset by iterating through all the images (in train and test)."},{"metadata":{"trusted":true},"cell_type":"code","source":"from collections import defaultdict\ntrain_size_dict = defaultdict(int)\ntrain_path = Path(\"../input/understanding_cloud_organization/train_images/\")\n\nfor img_name in train_path.iterdir():\n    img = Image.open(img_name)\n    train_size_dict[img.size] += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_size_dict","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Iterating through all images in Test"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_size_dict = defaultdict(int)\ntest_path = Path(\"../input/understanding_cloud_organization/test_images/\")\n\nfor img_name in test_path.iterdir():\n    img = Image.open(img_name)\n    test_size_dict[img.size] += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_size_dict","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## All the images in train and test set have a size 2100*1400"},{"metadata":{},"cell_type":"markdown","source":"# Vizualizing the masks"},{"metadata":{"trusted":true},"cell_type":"code","source":"palet = [(249, 192, 12), (0, 185, 241), (114, 0, 218), (249,50,12)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def name_and_mask(start_idx):\n    col = start_idx\n    img_names = [str(i).split(\"_\")[0] for i in train_df.iloc[col:col+4, 0].values]\n    if not (img_names[0] == img_names[1] == img_names[2] == img_names[3]):\n        raise ValueError\n\n    labels = train_df.iloc[col:col+4, 1]\n    mask = np.zeros((1400, 2100, 4), dtype=np.uint8)\n\n    for idx, label in enumerate(labels.values):\n        if label is not np.nan:\n            mask_label = np.zeros(2100*1400, dtype=np.uint8)\n            label = label.split(\" \")\n            positions = map(int, label[0::2])\n            length = map(int, label[1::2])\n            for pos, le in zip(positions, length):\n                mask_label[pos:(pos+le)] = 1\n            mask[:, :, idx] = mask_label.reshape(1400, 2100, order='F')\n    return img_names[0], mask","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_mask_image(col):\n    name, mask = name_and_mask(col)\n    img = cv2.imread(str(train_path / name))\n    fig, ax = plt.subplots(figsize=(15, 15))\n\n    for ch in range(4):\n        contours, _ = cv2.findContours(mask[:, :, ch], cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)\n        for i in range(0, len(contours)):\n            cv2.polylines(img, contours[i], True, palet[ch], 2)\n    ax.set_title(name)\n    ax.imshow(img)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idx_no_class = []\nidx_class_1 = []\nidx_class_2 = []\nidx_class_3 = []\nidx_class_4 = []\nidx_class_multi = []\nidx_class_triple = []\n\nfor col in range(0, len(train_df), 4):\n    img_names = [str(i).split(\"_\")[0] for i in train_df.iloc[col:col+4, 0].values]\n    if not (img_names[0] == img_names[1] == img_names[2] == img_names[3]):\n        raise ValueError\n        \n    labels = train_df.iloc[col:col+4, 1]\n    if labels.isna().all():\n        idx_no_defect.append(col)\n    elif (labels.isna() == [False, True, True, True]).all():\n        idx_class_1.append(col)\n    elif (labels.isna() == [True, False, True, True]).all():\n        idx_class_2.append(col)\n    elif (labels.isna() == [True, True, False, True]).all():\n        idx_class_3.append(col)\n    elif (labels.isna() == [True, True, True, False]).all():\n        idx_class_4.append(col)\n    elif labels.isna().sum() == 1:\n        idx_class_triple.append(col)\n    else:\n        idx_class_multi.append(col)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Images with class 1"},{"metadata":{"trusted":true},"cell_type":"code","source":"for idx in idx_class_1[:5]:\n    show_mask_image(idx)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Images with class 2"},{"metadata":{"trusted":true},"cell_type":"code","source":"for idx in idx_class_2[:5]:\n    show_mask_image(idx)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Images with class 3"},{"metadata":{"trusted":true},"cell_type":"code","source":"for idx in idx_class_3[:5]:\n    show_mask_image(idx)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Images with class 4"},{"metadata":{"trusted":true},"cell_type":"code","source":"for idx in idx_class_4[:5]:\n    show_mask_image(idx)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Images with multiple classes"},{"metadata":{"trusted":true},"cell_type":"code","source":"for idx in idx_class_multi[:5]:\n    show_mask_image(idx)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Explanation of the evaluation metric"},{"metadata":{},"cell_type":"markdown","source":"**Dice Coefficient (F1 Score)**\n\nDice coefficient is a statistic used to gauge the similarity of two samples.\n\nSimply put, the Dice Coefficient is 2 * the Area of Overlap divided by the total number of pixels in both images. (See explanation of area of union in section 2).\n\n![](https://miro.medium.com/max/644/1*yUd5ckecHjWZf6hGrdlwzA.png)"},{"metadata":{"trusted":true},"cell_type":"markdown","source":"I devote the credits for the code of this kernel to @GoldFish kernel at [https://www.kaggle.com/go1dfish/clear-mask-visualization-and-simple-eda](https://www.kaggle.com/go1dfish/clear-mask-visualization-and-simple-eda)"},{"metadata":{},"cell_type":"markdown","source":"**Please upvote if this is helpful**"}],"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":1}