{"metadata":{"colab":{"provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":75057,"databundleVersionId":8226831,"sourceType":"competition"},{"sourceId":170758829,"sourceType":"kernelVersion"}],"dockerImageVersionId":30684,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"This is a project called \"Lethal Company monsters and loot segmentation\" for the Deep Learning for Computer Vision course.","metadata":{"id":"U_IX8bhZzPaY"}},{"cell_type":"code","source":"# pycocotools for RLE\n# either install it for every session:\n# !pip install --quiet pycocotools\n\n# or add https://www.kaggle.com/code/margusl/dl4cv-pycocotools notebook as an input and load it from there\nimport sys\nsys.path.append('/kaggle/input/dl4cv-pycocotools/mysitepackages')","metadata":{"execution":{"iopub.status.busy":"2024-04-13T13:48:05.995368Z","iopub.execute_input":"2024-04-13T13:48:05.996623Z","iopub.status.idle":"2024-04-13T13:48:06.035535Z","shell.execute_reply.started":"2024-04-13T13:48:05.996575Z","shell.execute_reply":"2024-04-13T13:48:06.034318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random\nimport pandas as pd\nimport os\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport torch\nfrom pathlib import Path\nfrom PIL import Image\n\n# for encoding predicted segments for submission\nfrom pycocotools import mask as coco_mask\nimport zlib\nimport base64","metadata":{"id":"ffJMpVzsfBMB","execution":{"iopub.status.busy":"2024-04-13T13:49:30.302678Z","iopub.execute_input":"2024-04-13T13:49:30.303788Z","iopub.status.idle":"2024-04-13T13:49:30.310773Z","shell.execute_reply.started":"2024-04-13T13:49:30.303726Z","shell.execute_reply":"2024-04-13T13:49:30.309824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ls -l /kaggle/input/dl4cv-team10-lethal-company-segmentation/","metadata":{"execution":{"iopub.status.busy":"2024-04-13T13:50:04.958366Z","iopub.execute_input":"2024-04-13T13:50:04.958873Z","iopub.status.idle":"2024-04-13T13:50:06.067011Z","shell.execute_reply.started":"2024-04-13T13:50:04.958834Z","shell.execute_reply":"2024-04-13T13:50:06.065618Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# set dataset path\nkaggle_in = Path(\"/kaggle/input/dl4cv-team10-lethal-company-segmentation/\")","metadata":{"execution":{"iopub.status.busy":"2024-04-13T13:50:07.577204Z","iopub.execute_input":"2024-04-13T13:50:07.578085Z","iopub.status.idle":"2024-04-13T13:50:07.584093Z","shell.execute_reply.started":"2024-04-13T13:50:07.578035Z","shell.execute_reply":"2024-04-13T13:50:07.582821Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Info about the dataset\nDataset consists of screenshots (PNG) and for every screenshot there are 2 segmentation masks: enemy and loot.  \n\nTraining set structure:\n* `train/screenshots/*.png` - screenshots from Lethal Company\n* `train/masks_enemies/*.png` - segmentation masks for enemies, file names correspond to those in `screenshots/`\n* `train/masks_loot/*.png` - segmentation masks for loot, file names correspond to those in `screenshots/`\n\nTest set includes only screenshots (`test/screenshots/*.png`) and your task is to predict enemy mask and loot mask for every single screenshot in the test set.\n\nFor IDs we use screenshot filenames (e.g `5102_0046020.png`)","metadata":{"id":"i19fRhPzAS-E"}},{"cell_type":"code","source":"file_paths = [str(file) for file in kaggle_in.rglob('*.png')]\ndisplay(file_paths[:5])\nimages = (\n    pd.Series(file_paths).str.split('/', expand=True).iloc[:,3:]\n    .set_axis([\"kaggle\", \"split\", \"type\", \"img\"], axis=\"columns\")\n    .drop(columns = [\"kaggle\"])\n    .set_index([\"split\", \"type\"])\n)\nimages","metadata":{"id":"BKhtrOOcASNa","outputId":"a97dbeb0-8829-4fbb-d724-1df3cbd14453","execution":{"iopub.status.busy":"2024-04-13T13:50:13.230719Z","iopub.execute_input":"2024-04-13T13:50:13.231377Z","iopub.status.idle":"2024-04-13T13:52:27.998283Z","shell.execute_reply.started":"2024-04-13T13:50:13.231344Z","shell.execute_reply":"2024-04-13T13:52:27.997035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# file counts:\nimages.groupby(level=[0, 1]).size().reset_index(name='file_count')","metadata":{"execution":{"iopub.status.busy":"2024-04-13T13:52:28.000673Z","iopub.execute_input":"2024-04-13T13:52:28.001063Z","iopub.status.idle":"2024-04-13T13:52:28.043681Z","shell.execute_reply.started":"2024-04-13T13:52:28.001033Z","shell.execute_reply":"2024-04-13T13:52:28.042459Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualizing some samples from the training set","metadata":{"id":"woC8-EgLA54D"}},{"cell_type":"code","source":"def im5(img_lst):\n  _, axes = plt.subplots(1, 5, figsize=(15,4))\n  for i, img in enumerate(img_lst):\n    axes[i].imshow(img)\n    axes[i].axis('off')\n  plt.tight_layout()\n  plt.show()","metadata":{"id":"-guC-8mZA3zt","execution":{"iopub.status.busy":"2024-04-13T13:52:28.045709Z","iopub.execute_input":"2024-04-13T13:52:28.046458Z","iopub.status.idle":"2024-04-13T13:52:28.056046Z","shell.execute_reply.started":"2024-04-13T13:52:28.046417Z","shell.execute_reply":"2024-04-13T13:52:28.054606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"file_samples = [\"3309_0189135.png\",\n                \"3309_0139710.png\",\n                \"8875_0106785.png\",\n                \"8875_0024945.png\",\n                \"2006_0262485.png\"]","metadata":{"id":"gbJG72VhA4kg","execution":{"iopub.status.busy":"2024-04-13T13:52:28.059394Z","iopub.execute_input":"2024-04-13T13:52:28.060292Z","iopub.status.idle":"2024-04-13T13:52:28.070286Z","shell.execute_reply.started":"2024-04-13T13:52:28.060253Z","shell.execute_reply":"2024-04-13T13:52:28.068963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"screenshots = [Image.open(kaggle_in / \"train/screenshots\" / img) for img in file_samples]\nim5(screenshots)","metadata":{"id":"tzLmycgZBDfj","outputId":"fdb94ed4-2c77-4f9e-f72f-4922cfe3dad0","execution":{"iopub.status.busy":"2024-04-13T13:52:28.072908Z","iopub.execute_input":"2024-04-13T13:52:28.073341Z","iopub.status.idle":"2024-04-13T13:52:29.019180Z","shell.execute_reply.started":"2024-04-13T13:52:28.073302Z","shell.execute_reply":"2024-04-13T13:52:29.018221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# enemy masks\nm_enemy = [np.array(Image.open(kaggle_in / \"train/masks_enemies\" / img).convert(\"1\"), dtype=np.uint8)  for img in file_samples]\nim5(m_enemy)","metadata":{"id":"56OoTSO6ErGR","outputId":"8997e85b-b47e-457e-d7e0-2fc5beb9de31","execution":{"iopub.status.busy":"2024-04-13T13:52:29.020684Z","iopub.execute_input":"2024-04-13T13:52:29.021322Z","iopub.status.idle":"2024-04-13T13:52:29.543177Z","shell.execute_reply.started":"2024-04-13T13:52:29.021292Z","shell.execute_reply":"2024-04-13T13:52:29.542013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# loot mask\nm_loot = [np.array(Image.open(kaggle_in / \"train/masks_loot\" / img).convert(\"1\"), dtype=np.uint8)  for img in file_samples]\nim5(m_loot)","metadata":{"id":"MxugiU5VBJO0","outputId":"c903a0c5-0dea-4a30-e58b-6a773198ee61","execution":{"iopub.status.busy":"2024-04-13T13:52:29.544987Z","iopub.execute_input":"2024-04-13T13:52:29.545327Z","iopub.status.idle":"2024-04-13T13:52:30.071884Z","shell.execute_reply.started":"2024-04-13T13:52:29.545299Z","shell.execute_reply":"2024-04-13T13:52:30.070688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# an empty mask\ndisplay(np.shape(m_enemy[2]))\ndisplay(np.unique(m_enemy[2], return_counts=True))\nprint(m_enemy[2])","metadata":{"id":"5cpKx_1NtFVs","outputId":"7c09df97-81f0-4716-e896-d44b7bda3832","execution":{"iopub.status.busy":"2024-04-13T14:05:18.090523Z","iopub.execute_input":"2024-04-13T14:05:18.091227Z","iopub.status.idle":"2024-04-13T14:05:18.112926Z","shell.execute_reply.started":"2024-04-13T14:05:18.091184Z","shell.execute_reply":"2024-04-13T14:05:18.111806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# mask with segments\ndisplay(np.shape(m_loot[0]))\ndisplay(np.unique(m_loot[0], return_counts=True))\nprint(m_loot[0])","metadata":{"id":"7kBdN7_8sPuJ","outputId":"780cb472-a8a4-49af-d20b-2afc86aa6022","execution":{"iopub.status.busy":"2024-04-13T14:05:20.984052Z","iopub.execute_input":"2024-04-13T14:05:20.984706Z","iopub.status.idle":"2024-04-13T14:05:21.003147Z","shell.execute_reply.started":"2024-04-13T14:05:20.984675Z","shell.execute_reply":"2024-04-13T14:05:21.002198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Scoring\nOur competition metric is public and is configured to use default parameters: [dl4cv-10-2-class-iou-sum-with-coef-metric](https://www.kaggle.com/code/margusl/dl4cv-10-2-class-iou-sum-with-coef-metric). You can play around with it if you choose to, perhaps with a training set.","metadata":{"id":"4vTkbd-Dnwff"}},{"cell_type":"markdown","source":"# Encoding / submission helpers\nPredictions are submitted as RLE (run-length encoded) strings for which we use `pycocotools`, sequences are compressed (`zlib`) and encoded as Base64. You can use following `encode_mask()` helper to handle encoding and you can also check scoring metric source for decoding logic.\n\n**NOTE:** shape of your predicted and encoded mask **MUST** match input image resolution (`np.shape(m_loot[0]) == (520, 860)`), with any other shapes decoding at scoring end will fail.\n","metadata":{"id":"kVIotvUip7MW"}},{"cell_type":"code","source":"def encode_mask(mask: np.ndarray):\n  \"\"\"Encode numpy arrays (unit8 or boolean) to compressed base64 encoded RLE strings\n\n  Depends on pycocotools\n  Ex:\n  `encode_mask(mask_tesnor.numpy())`\n  \"\"\"\n  rle = coco_mask.encode(np.asfortranarray(mask))[\"counts\"]\n  return base64.b64encode(zlib.compress(rle)).decode('utf-8')","metadata":{"id":"1a0rdm8XzSDc","execution":{"iopub.status.busy":"2024-04-13T14:05:23.801969Z","iopub.execute_input":"2024-04-13T14:05:23.802585Z","iopub.status.idle":"2024-04-13T14:05:23.807813Z","shell.execute_reply.started":"2024-04-13T14:05:23.802545Z","shell.execute_reply":"2024-04-13T14:05:23.806965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"For the reference, this is what you should end up when encoding all-set mask (all ones) and empty mask (all zeros) for an 860x520 image:","metadata":{"id":"lIFtcPI5w8BL"}},{"cell_type":"code","source":"assert np.shape(m_loot[0]) == (520, 860)\nall_set_rle   = encode_mask(np.ones_like(m_loot[0]))  # eJwzCEhPsQUABG8BiQ==\nall_empty_rle = encode_mask(np.zeros_like(m_loot[0])) # eJwLSE+xBQADfgFZ\n\nprint(f'all set:\\t\"{all_set_rle}\"')\nprint(f'none set:\\t\"{all_empty_rle}\"')","metadata":{"id":"63HNeKW7wABS","outputId":"e48ffc26-6535-4abc-e4e2-ce5f97cb9be1","execution":{"iopub.status.busy":"2024-04-13T14:05:26.099375Z","iopub.execute_input":"2024-04-13T14:05:26.100039Z","iopub.status.idle":"2024-04-13T14:05:26.109101Z","shell.execute_reply.started":"2024-04-13T14:05:26.100008Z","shell.execute_reply":"2024-04-13T14:05:26.107764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Here should start some code to train the model and predict.\nSome dummy code for generating the predictions.","metadata":{"id":"k1qKkAQrW9RY"}},{"cell_type":"code","source":"classes = [\"monsters\", \"loot\"]\n\nimg_width = 860\nimg_height = 520\n\nK = len(classes)","metadata":{"id":"ZTTuYjQUT343","execution":{"iopub.status.busy":"2024-04-13T14:05:28.842951Z","iopub.execute_input":"2024-04-13T14:05:28.843333Z","iopub.status.idle":"2024-04-13T14:05:28.849611Z","shell.execute_reply.started":"2024-04-13T14:05:28.843305Z","shell.execute_reply":"2024-04-13T14:05:28.848193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predictingRandomMask (img_width, img_height):\n    mask = np.zeros((img_height, img_width), dtype=np.uint8)\n    mask[0,:] = 1\n    return mask","metadata":{"id":"5n1Egg_OUuj0","execution":{"iopub.status.busy":"2024-04-13T14:05:31.856893Z","iopub.execute_input":"2024-04-13T14:05:31.857891Z","iopub.status.idle":"2024-04-13T14:05:31.863493Z","shell.execute_reply.started":"2024-04-13T14:05:31.857856Z","shell.execute_reply":"2024-04-13T14:05:31.862374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"file_names_image = [str(file) for file in (kaggle_in / \"test/screenshots\").rglob('*.png')]\n\nrandomMaskMonster = np.uint8(predictingRandomMask(img_width, img_height))\nrandomMaskLoot = np.uint8(predictingRandomMask(img_width, img_height))\nencoded_monster = encode_mask(randomMaskMonster)\nencoded_loot = encode_mask(randomMaskLoot)\n\nresults = []\nfor elem in file_names_image:\n    file_name = elem.split(\"/\")[-1]\n    results.append((file_name, encoded_monster, encoded_loot))\n\ndf = pd.DataFrame(results, columns=['ImageID', 'RleMonsters', 'RleLoot'])","metadata":{"id":"CBOihnC_T983","execution":{"iopub.status.busy":"2024-04-13T14:06:23.203939Z","iopub.execute_input":"2024-04-13T14:06:23.204896Z","iopub.status.idle":"2024-04-13T14:06:36.772426Z","shell.execute_reply.started":"2024-04-13T14:06:23.204861Z","shell.execute_reply":"2024-04-13T14:06:36.771497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"id":"3fHkQbacgLl_","outputId":"1684b519-eed4-4b83-9aff-c118a3cd2a69","execution":{"iopub.status.busy":"2024-04-13T14:06:36.774231Z","iopub.execute_input":"2024-04-13T14:06:36.774884Z","iopub.status.idle":"2024-04-13T14:06:36.789841Z","shell.execute_reply.started":"2024-04-13T14:06:36.774853Z","shell.execute_reply":"2024-04-13T14:06:36.788691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Write the predictions to a CSV file which we can submit to the competition.\nsubmission = pd.DataFrame(\n    {'img_id': df['ImageID'], 'enemy_rle': df['RleMonsters'], 'loot_rle': df['RleLoot']},\n    columns = ['img_id', 'enemy_rle', 'loot_rle'])\nsubmission.to_csv('submission.csv', index = False)\n","metadata":{"id":"a_QZ1OI3degN","execution":{"iopub.status.busy":"2024-04-13T14:06:41.175654Z","iopub.execute_input":"2024-04-13T14:06:41.176701Z","iopub.status.idle":"2024-04-13T14:06:41.267627Z","shell.execute_reply.started":"2024-04-13T14:06:41.176665Z","shell.execute_reply":"2024-04-13T14:06:41.266639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission","metadata":{"id":"eqZgDmQcm9C2","outputId":"cd526b46-9852-4a04-fc41-73bb1cf9856c","execution":{"iopub.status.busy":"2024-04-13T14:06:43.489041Z","iopub.execute_input":"2024-04-13T14:06:43.489425Z","iopub.status.idle":"2024-04-13T14:06:43.505467Z","shell.execute_reply.started":"2024-04-13T14:06:43.489397Z","shell.execute_reply":"2024-04-13T14:06:43.504356Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check csv file\n!ls -l submission.csv\n!echo\n!head submission.csv -n 10","metadata":{"id":"FeeOECcyAu72","outputId":"da8586ad-f240-42ee-f5ea-5fd5242bc02d","execution":{"iopub.status.busy":"2024-04-13T14:06:46.994613Z","iopub.execute_input":"2024-04-13T14:06:46.995049Z","iopub.status.idle":"2024-04-13T14:06:50.357703Z","shell.execute_reply.started":"2024-04-13T14:06:46.995015Z","shell.execute_reply":"2024-04-13T14:06:50.356315Z"},"trusted":true},"execution_count":null,"outputs":[]}]}