{"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":"!wget http://bit.ly/3ZLyF82 -O CSS.css -q\n\nfrom IPython.core.display import HTML\n\nwith open(\"./CSS.css\", \"r\") as file:\n    custom_css = file.read()\n\nHTML(custom_css)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-05-28T11:40:26.270592Z","iopub.execute_input":"2023-05-28T11:40:26.271475Z","iopub.status.idle":"2023-05-28T11:40:27.751701Z","shell.execute_reply.started":"2023-05-28T11:40:26.27144Z","shell.execute_reply":"2023-05-28T11:40:27.750518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls ../input/google-research-identify-contrails-reduce-global-warming/ -GFlash --color","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:40:27.753891Z","iopub.execute_input":"2023-05-28T11:40:27.754385Z","iopub.status.idle":"2023-05-28T11:40:28.852089Z","shell.execute_reply.started":"2023-05-28T11:40:27.754344Z","shell.execute_reply":"2023-05-28T11:40:28.850997Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install nb_black # for formatting the code\n%load_ext lab_black","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-05-28T11:40:28.853622Z","iopub.execute_input":"2023-05-28T11:40:28.854896Z","iopub.status.idle":"2023-05-28T11:40:48.894408Z","shell.execute_reply.started":"2023-05-28T11:40:28.854845Z","shell.execute_reply":"2023-05-28T11:40:48.893249Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# %load_ext nb_black","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-05-28T11:40:48.896915Z","iopub.execute_input":"2023-05-28T11:40:48.898074Z","iopub.status.idle":"2023-05-28T11:40:48.903613Z","shell.execute_reply.started":"2023-05-28T11:40:48.898029Z","shell.execute_reply":"2023-05-28T11:40:48.902198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install itables # for interactive tables","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-05-28T11:40:48.905049Z","iopub.execute_input":"2023-05-28T11:40:48.905428Z","iopub.status.idle":"2023-05-28T11:41:02.267713Z","shell.execute_reply.started":"2023-05-28T11:40:48.905397Z","shell.execute_reply":"2023-05-28T11:41:02.266425Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"padding:20px;color:white;margin:0;font-size:30px;font-family:Georgia;text-align:center;display:fill;border-radius:5px;background-color:#4285F4;overflow:hidden\">Libraries</div>","metadata":{}},{"cell_type":"code","source":"import numpy as np  # linear algebra\n\nimport pandas as pd  # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom itables import init_notebook_mode\nfrom pathlib import Path\nfrom tqdm import tqdm\n\ninit_notebook_mode(all_interactive=True, connected=True)\n\nimport matplotlib.pyplot as plt\nimport plotly.express as px\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\nimport seaborn as sns\n\n%matplotlib inline\n\nimport os\nimport json\n\n\nfrom colorama import Style, Fore\n\ngreen = Style.BRIGHT + Fore.GREEN\nblue = Style.BRIGHT + Fore.BLACK\nred = Style.BRIGHT + Fore.RED","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-05-28T11:41:02.269401Z","iopub.execute_input":"2023-05-28T11:41:02.26975Z","iopub.status.idle":"2023-05-28T11:41:04.576868Z","shell.execute_reply.started":"2023-05-28T11:41:02.269716Z","shell.execute_reply":"2023-05-28T11:41:04.575717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"padding:20px;color:white;margin:0;font-size:30px;font-family:Georgia;text-align:center;display:fill;border-radius:5px;background-color:#4285F4;overflow:hidden\">Introduction</div>\n\n<img src=\"https://storage.googleapis.com/kaggle-media/competitions/Google-Contrails/waterdroplets.png\">\n\n<span style=\"font-size:18px; font-family:Georgia;\"><b>Objectives</b>: In creating this notebook, my objectives are:</span>\n    \n<ul style=“list-style-type:circle;”><span style='font-size:18px; font-family:Georgia;'>\n\n<li>To learn about the data by exploration and visualization</li>\n\n<li>To perform some processing techniques for further development</li>\n\n</span></ul>\n\n<hr>\n\n<div style=\"font-size:18px; font-family:Georgia;\"><b>Overview</b>\n<ul>\n  \n<li>The dataset for this competition was obtained from the  <a href=\"https://www.goes-r.gov/spacesegment/abi.html\">GOES-16 Advanced Baseline Imager (ABI)</a>, which is publicly available on Google Cloud Storage. Our task is to use geostationary satellite images to identify aviation contrails.</li>\n    \n<li>The original full-disk images were reprojected using bilinear resampling to generate a local scene image. Because contrails are easier to identify with temporal context, a sequence of images at 10-minute intervals are provided. Each example <em>(record_id)</em> contains exactly one labeled frame.</li>\n\n<li>Learn more about the dataset from the preprint: <a href=\"https://arxiv.org/abs/2304.02122\">OpenContrails: Benchmarking Contrail Detection on GOES-16 ABI</a>.</li>\n    \n<li>Labeling instructions can be found at in this <a href=\"https://storage.googleapis.com/goes_contrails_dataset/20230419/Contrail_Detection_Dataset_Instruction.pdf\">supplementary material</a>.</li>\n</div>\n   \n","metadata":{}},{"cell_type":"markdown","source":"<div class=\"alert alert-info\" role=\"alert\" style=\"padding:20px;color:black;margin:0;font-size:17px;font-family:Georgia;text-align:left;display:fill;border-radius:5px;overflow:hidden\">\n    <b>Rules for contrail labelling</b>\n        <ul style=“list-style-type:circle;”>\n            <li>Contrails must contain at least 10 pixels.\n             <li>At some time in their life, Contrails must be at least 3x longer than they are wide (generally longer is better).</li>\n            <li>This requirement does not need to be met if every image the contrail is in, but it should be met in at least 1.\n<li>Contrails must either appear suddenly or enter from the sides of the image</li>\n<li>Contrails should be visible in at least two image (and more images is better)</li>\n          \n</div>","metadata":{}},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">\n    <b>Understanding the evaluation metric</b><br>\n    This competition is evaluated on the global <a href=\"https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient\">Sørensen–Dice coefficient</a>. The Dice coefficient can be used to compare the pixel-wise agreement between a predicted segmentation and its corresponding ground truth. The formula is given by:\n    $$2 * \\frac{|X \\bigcap Y|}{|X| + |Y|}$$\n    where, \n    <ul>\n        <li> |X| and |Y| are the cardinalities of the two sets (i.e. the number of elements in each set)</li>\n        <li>|X ∩ Y| represents the size or cardinality of the intersection of sets X and Y.</li>\n    </ul>\n</div>","metadata":{}},{"cell_type":"markdown","source":"# <div style=\"padding:20px;color:white;margin:0;font-size:30px;font-family:Georgia;text-align:center;display:fill;border-radius:5px;background-color:#4285F4;overflow:hidden\">EDA📊</div>","metadata":{}},{"cell_type":"code","source":"BASE_PATH = \"/kaggle/input/google-research-identify-contrails-reduce-global-warming\"\nTRAIN_PATH = os.path.join(BASE_PATH, \"train\")\nTEST_PATH = os.path.join(BASE_PATH, \"test\")\nVALID_PATH = os.path.join(BASE_PATH, \"validation\")\nTRAIN_META_PATH = os.path.join(BASE_PATH, \"train_metadata.json\")\nVALID_META_PATH = os.path.join(BASE_PATH, \"validation_metadata.json\")","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:04.579611Z","iopub.execute_input":"2023-05-28T11:41:04.580907Z","iopub.status.idle":"2023-05-28T11:41:04.592807Z","shell.execute_reply.started":"2023-05-28T11:41:04.580861Z","shell.execute_reply":"2023-05-28T11:41:04.591223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\"> Let's inderstand what files are poresent in training directory.\ntrain/ - the training set; each folder represents a record_id and contains the following data:\n<ul>\n    <li><strong>band_{08-16}.npy</strong>: array with size of H x W x T, where T = n_times_before + n_times_after + 1, representing the number of images in the sequence. There are n_times_before and n_times_after images before and after the labeled frame respectively. In our dataset all examples have n_times_before=4 and n_times_after=3. Each band represents an infrared channel at different wavelengths and is converted to brightness temperatures based on the calibration parameters. The number in the filename corresponds to the GOES-16 ABI band number. Details of the ABI bands can be found here.</li>\n\n<li><strong>human_individual_masks.npy</strong>: array with size of H x W x 1 x R. Each example is labeled by R individual human labelers. R is not the same for all samples. The labeled masks have value either 0 or 1 and correspond to the (n_times_before+1)-th image in band_{08-16}.npy. They are available only in the training set.</li>\n\n<li><strong>human_pixel_masks.npy</strong>: array with size of H x W x 1 containing the binary ground truth. A pixel is regarded as contrail pixel in evaluation if it is labeled as contrail by more than half of the labelers.</li>\n</ul>\n</div>","metadata":{}},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">\nFirst of all let's count the positive and negative classes i.e. how many images have contrail in it and how many don't.\n    </div>","metadata":{}},{"cell_type":"code","source":"# Since the loop takes some time to run(aprox: 1.5 min) so I have commented the code\n# if you want to try it out yourselves then you can uncomment it\n\n# pos_example = 0\n\nTRAIN_FILES = os.listdir(TRAIN_PATH)\n# for example in tqdm(TRAIN_FILES, colour=\"green\"):\n#     img = np.load(f\"{TRAIN_PATH}/{example}/human_pixel_masks.npy\")\n#     if len(np.unique(img)) > 1:\n#         pos_example += 1\n\n# print(\n#     f\"There are {pos_example} positive examples\\nThere are {len(TRAIN_FILES) - pos_example} negative examples.\"\n# )","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:04.594579Z","iopub.execute_input":"2023-05-28T11:41:04.594963Z","iopub.status.idle":"2023-05-28T11:41:04.861426Z","shell.execute_reply.started":"2023-05-28T11:41:04.594929Z","shell.execute_reply":"2023-05-28T11:41:04.860485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">Let's visualize it using a countplot.</div>","metadata":{}},{"cell_type":"code","source":"pos_example = 9259\nneg_example = len(TRAIN_FILES) - pos_example\n\ncategories = [\"Positive (contrails)\", \"Negative (no contrails)\"]\ncounts = [pos_example, neg_example]\n\nplt.bar(categories, counts)\nplt.xlabel(\"Category\")\nplt.ylabel(\"Count\")\nplt.title(\"Distribution of Examples\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:04.862571Z","iopub.execute_input":"2023-05-28T11:41:04.862864Z","iopub.status.idle":"2023-05-28T11:41:05.118088Z","shell.execute_reply.started":"2023-05-28T11:41:04.862838Z","shell.execute_reply":"2023-05-28T11:41:05.117108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">Now we have an idea on what is the distribution of the positive and negative files, let's explore one of the file. I will select file having <b>id : 1000216489776414077</b> and belonging to <b>8<sup>th</sup> spectral band</b>.<div>","metadata":{}},{"cell_type":"code","source":"tem_8 = np.load(\n    \"/kaggle/input/google-research-identify-contrails-reduce-global-warming/train/1000216489776414077/band_08.npy\"\n)\n\nfig, ax = plt.subplots(nrows=1, ncols=2, sharey=True)\n\n# plt.plot(tem_8[0])\nax[0].imshow(tem_8[..., 0])\nax[1].imshow(tem_8[..., 1])\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:05.122263Z","iopub.execute_input":"2023-05-28T11:41:05.122732Z","iopub.status.idle":"2023-05-28T11:41:05.582044Z","shell.execute_reply.started":"2023-05-28T11:41:05.1227Z","shell.execute_reply":"2023-05-28T11:41:05.581089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">\nBefore we begin analyzing the data, it is important to understand where the data came from. The source of the data is essential to know when building a model. By understanding the source of the data and the method of data collection, we can extract more information from the dataset.\n</div>\n<br>\n<div style=\"font-size:18px; font-family:Georgia;\">\nThe original satellite images were obtained from the <a href=\"https://www.goes-r.gov/spacesegment/abi.html\"><u>GOES-16 Advanced Baseline Imager (ABI)</u></a>, which is publicly available on <a href=\"https://console.cloud.google.com/storage/browser/gcp-public-data-goes-16\"><u>Google Cloud Storage</u></a>. The original full-disk images were reprojected using bilinear resampling to generate a local scene image.\n\n<hr>\n<strong>Advanced Baseline Imager(ABI) & Spectral bands</strong><br>\nThe Advanced Baseline Imager (ABI) is an advanced weather satellite instrument used for Earth observation. It is one of the primary instruments onboard the Geostationary Operational Environmental Satellite (GOES) series, specifically designed for weather monitoring and forecasting. The ABI provides high-resolution, multi-channel imaging capabilities that significantly enhance weather analysis and forecasting capabilities.\n<hr>\n<strong>Spectral bands</strong> (<span style=\"font-size:15px\"><a href=\"https://www.earthdata.nasa.gov/sensors/abi#:~:text=ABI%20views%20Earth%20with%2016,channels%2C%20and%2010%20infrared%20channels.\">Source</a></span>)<br>\nABI views Earth with 16 different spectral bands (compared to five on the previous generation of GOES), including two visible channels, four near-infrared channels, and 10 infrared channels. These different channels (wavelengths) are used by models and tools to indicate various elements on Earth’s surface or in the atmosphere, such as trees, water, clouds, moisture, or smoke.<br>\n</div>","metadata":{}},{"cell_type":"code","source":"# Idea borrowed from Pranav Nadimpalli @pranavnadimpali\nbands = range(8, 17)\ncolors = [\n    \"red\",\n    \"blue\",\n    \"green\",\n    \"orange\",\n    \"purple\",\n    \"cyan\",\n    \"magenta\",\n    \"yellow\",\n    \"black\",\n]\n\nfor i, band in enumerate(bands):\n    temp = np.load(f\"{TRAIN_PATH}/1000216489776414077/band_{band:02}.npy\")\n    plt.plot(temp[0], color=colors[i], label=f\"Band {band:02}\")\n\n# plt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:05.583555Z","iopub.execute_input":"2023-05-28T11:41:05.584516Z","iopub.status.idle":"2023-05-28T11:41:06.55436Z","shell.execute_reply.started":"2023-05-28T11:41:05.584477Z","shell.execute_reply":"2023-05-28T11:41:06.553477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">\n<b>What are these spectral bands🤔🌈?</b><br>\n<p>\nIn the given dataset we are provided images which are captured at 8 different spectral bands namely from <i>band 8</i> to <i>band 16</i>. Each band represents a series of images captured at different wavelengths of light. For instance, band 08 consists of a series of images highlighting a specific wavelength, while band 16 contains images capturing a different wavelength. It is important to note that each band contains images of the same thing just at different wavelengths so each band will look slightly different and contain more information than others because contrails look different at different wavelengths.\n\nThe ABI captures images in separate bands at regular 10-minute intervals. Within each band, there are a total of 8 images taken over a span of 80 minutes, with a 10-minute gap between each image. For instance, when we analyze band 8, we are essentially observing a sequence of images, each captured 10 minutes apart from one another. This series of images offers valuable insights into the progression and transformations of contrails, enabling us to study their expansion and shape variations over time.\n\n<hr>\n\nNow that we have got a bird's eye view of the spectral bands let's understanf what the two files : <i>human_pixel_masks</i> and <i>human_individual_masks</i> are trying to tell us.\n\n- human_pixel_masks : these file contain the ground truth labels. We can consider a label correct only if more than half of the labellers have aggried upon it. Doing so increases the rwliability of the results produced. Since the images are captured at three intervals namely n_times_before which is 4 and n_timed_after which is 3, this implies that the ground truth mask corresponds to the 5<sup>th</sup> example.\n\n- human_individual_masks: The human_individual_masks represent labels generated by multiple labellers. These labels are then compared and combined to create a final ground truth, which can be found in the human_pixel_masks file. \n    \n</p>\n</div>","metadata":{}},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">\nLet's dig deep into individual images and find their metadata.\n</div>","metadata":{}},{"cell_type":"code","source":"band = 8\nsample_img = np.load(f\"{TRAIN_PATH}/1000216489776414077/band_{band:02}.npy\")\nprint(f\"{green}The image has a shape : {sample_img.shape}\")","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:06.555537Z","iopub.execute_input":"2023-05-28T11:41:06.55632Z","iopub.status.idle":"2023-05-28T11:41:06.567124Z","shell.execute_reply.started":"2023-05-28T11:41:06.556282Z","shell.execute_reply":"2023-05-28T11:41:06.565853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">\n<b>Plot the images and visualize the change in the countrails over time.</b>\n<p>\nThe plot will go from left to right which will tell us the images for different bands.<br>\nThe images from top to bottom will tell us the change over time steps.(10 min apart)   \n</p>\n</div>","metadata":{}},{"cell_type":"code","source":"def plot_images(img_id: str, img_dir: str):\n    \"\"\"\n    Args:\n    img_id = The ID of the image (e.g., '1000216489776414077')\n    img_dir = The directory (e.g., 'train', 'test', or 'valid')\n    \"\"\"\n\n    fig, axs = plt.subplots(len(bands), 8, figsize=(16, 16))\n\n    for i, band in enumerate(bands):\n        img = np.load(f\"{BASE_PATH}/{img_dir}/{img_id}/band_{band:02}.npy\")\n        for j in range(8):\n            axs[i, j].imshow(img[..., j])\n            axs[i, j].set_title(f\"Band {band}\\nTime Step {j-4}\")\n            axs[i, j].set_xticks([])\n            axs[i, j].set_yticks([])\n\n    plt.tight_layout()\n    plt.show()\n\n\nplot_images(\"1001792196232384964\", \"train\")","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:06.568751Z","iopub.execute_input":"2023-05-28T11:41:06.569103Z","iopub.status.idle":"2023-05-28T11:41:11.902606Z","shell.execute_reply.started":"2023-05-28T11:41:06.569072Z","shell.execute_reply":"2023-05-28T11:41:11.9012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:18px; font-family:Georgia;\">\n<b></b>\nNow since we have got an overview of how are the images in several band we will move on to exploring the ground truth masks.\n</div>","metadata":{}},{"cell_type":"code","source":"band_8_human_individual = np.load(\n    f\"{TRAIN_PATH}/1000603527582775543/human_individual_masks.npy\"\n)\nband_8_human_individual.shape","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:11.904109Z","iopub.execute_input":"2023-05-28T11:41:11.904489Z","iopub.status.idle":"2023-05-28T11:41:11.932987Z","shell.execute_reply.started":"2023-05-28T11:41:11.904456Z","shell.execute_reply":"2023-05-28T11:41:11.931939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(band_8_human_individual[..., 0])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-28T11:41:11.934746Z","iopub.execute_input":"2023-05-28T11:41:11.935492Z","iopub.status.idle":"2023-05-28T11:41:12.177592Z","shell.execute_reply.started":"2023-05-28T11:41:11.935454Z","shell.execute_reply":"2023-05-28T11:41:12.176471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}