{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-08-16T09:25:11.121803Z","iopub.execute_input":"2022-08-16T09:25:11.122243Z","iopub.status.idle":"2022-08-16T09:28:38.333520Z","shell.execute_reply.started":"2022-08-16T09:25:11.122156Z","shell.execute_reply":"2022-08-16T09:28:38.332252Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"root_dir = \"/kaggle/input/airbus-ship-detection/\"\nprint(os.listdir(root_dir))","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:28:38.336156Z","iopub.execute_input":"2022-08-16T09:28:38.336525Z","iopub.status.idle":"2022-08-16T09:28:38.343047Z","shell.execute_reply.started":"2022-08-16T09:28:38.336493Z","shell.execute_reply":"2022-08-16T09:28:38.342255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dir = os.path.join(root_dir,\"train_v2\")\ntest_dir = os.path.join(root_dir,\"test_v2\")\nprint(f\"Files in train dir: {len(os.listdir(train_dir))}\\nFiles in test dir: {len(os.listdir(test_dir))}\")","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:28:38.344212Z","iopub.execute_input":"2022-08-16T09:28:38.344474Z","iopub.status.idle":"2022-08-16T09:28:38.500283Z","shell.execute_reply.started":"2022-08-16T09:28:38.344444Z","shell.execute_reply":"2022-08-16T09:28:38.498863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"not_jpg_train_files = [filename for filename in os.listdir(train_dir) if not filename.endswith('.jpg')]\nnot_jpg_test_files = [filename for filename in os.listdir(test_dir) if not filename.endswith('.jpg')]\nprint(f\"\"\"Checking if in train and test are only photos:\nNot jpg files in train: {len(not_jpg_train_files)}\nNot jpg files in test: {len(not_jpg_test_files)}\"\"\")","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:28:38.502399Z","iopub.execute_input":"2022-08-16T09:28:38.502685Z","iopub.status.idle":"2022-08-16T09:28:38.625737Z","shell.execute_reply.started":"2022-08-16T09:28:38.502662Z","shell.execute_reply":"2022-08-16T09:28:38.624158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_csv_path =  os.path.join(root_dir, \"train_ship_segmentations_v2.csv\")\ntrain_df = pd.read_csv(train_csv_path, index_col='ImageId')#load df with RLE encoding \nprint(f\"Shape with duplicates:{train_df.shape}\")\ntrain_df = train_df[~train_df.index.duplicated(keep='first')] # Get rid of duplicates\nprint(f\"Shape without duplicates:{train_df.shape} (the same amount we have in train dir)\")\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:28:38.627148Z","iopub.execute_input":"2022-08-16T09:28:38.627457Z","iopub.status.idle":"2022-08-16T09:28:39.772715Z","shell.execute_reply.started":"2022-08-16T09:28:38.627430Z","shell.execute_reply":"2022-08-16T09:28:39.771769Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As you see here images with ships have non NaN values","metadata":{}},{"cell_type":"code","source":"#Decoder for Run Length Encodings\ndef rle_decode(mask_rle, shape=(768, 768)):\n    #Reference https://www.kaggle.com/code/inversion/run-length-decoding-quick-start\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height,width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n    if isinstance(mask_rle, float) or (mask_rle==0):\n        return np.zeros(shape)\n    if isinstance(mask_rle, str):\n        s = mask_rle.split()\n        starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n        starts -= 1\n        ends = starts + lengths\n        img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n        for lo, hi in zip(starts, ends):\n            img[lo:hi] = 1\n        return img.reshape(shape).T\n    list_mask_rle = mask_rle\n    all_mask = np.zeros(shape)\n    for mask_rle in list_mask_rle:\n        s = mask_rle.split()\n        starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n        starts -= 1\n        ends = starts + lengths\n        img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n        for lo, hi in zip(starts, ends):\n            img[lo:hi] = 1\n        all_mask += img.reshape(shape).T\n    return all_mask\n        \n        \n    ","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:28:39.774097Z","iopub.execute_input":"2022-08-16T09:28:39.775365Z","iopub.status.idle":"2022-08-16T09:28:39.786188Z","shell.execute_reply.started":"2022-08-16T09:28:39.775328Z","shell.execute_reply":"2022-08-16T09:28:39.785183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Dataset have some corrupted images which we will discard during training","metadata":{}},{"cell_type":"code","source":"train_df['file_size_kb'] = train_df.index.map(lambda c_img_id: os.stat(os.path.join(train_dir, c_img_id)).st_size/1024)\nprint(f\"amount of corrupted images: {len(train_df[train_df['file_size_kb']<50])}\")","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:28:39.787077Z","iopub.execute_input":"2022-08-16T09:28:39.787752Z","iopub.status.idle":"2022-08-16T09:30:29.534639Z","shell.execute_reply.started":"2022-08-16T09:28:39.787726Z","shell.execute_reply":"2022-08-16T09:30:29.533230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Next I will show small samples with ships and its corresponding RLE target mask so for this I prep df with only ships\ntemp = train_df.dropna()\ntemp.shape[0]#actual number of photos with ships","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:29.535635Z","iopub.execute_input":"2022-08-16T09:30:29.535851Z","iopub.status.idle":"2022-08-16T09:30:29.562148Z","shell.execute_reply.started":"2022-08-16T09:30:29.535828Z","shell.execute_reply":"2022-08-16T09:30:29.561511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\n\n#Show sample of images with target mask \nrandom_row = np.random.choice(temp.index, size=5)\nrle = temp.loc[random_row,'EncodedPixels']\nfig, axarr = plt.subplots(1, 5, figsize=(20, 45))\nfor i, m in enumerate(rle):\n    path = os.path.join(train_dir, random_row[i])\n    img = cv2.imread(path)\n    mask = rle_decode(m)\n    axarr[i].imshow(img)\n    axarr[i].imshow(mask, alpha=0.5)\nplt.show()\n\n","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:29.563154Z","iopub.execute_input":"2022-08-16T09:30:29.563399Z","iopub.status.idle":"2022-08-16T09:30:31.200197Z","shell.execute_reply.started":"2022-08-16T09:30:29.563376Z","shell.execute_reply":"2022-08-16T09:30:31.199072Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import seaborn as sns\n\ntrgt01 = train_df.fillna(0)\ntrgt01['EncodedPixels'] = (trgt01['EncodedPixels'] !=0).astype(\"uint8\")\nvalue = trgt01['EncodedPixels'].value_counts().tolist()\n\nsns.barplot(x =  [\"Non Ships\", \"Ships\"], y = value)\nprint(f\"As we can see images with no ships are a majority class (ratio {value[0]/np.sum(value)})\")","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:31.204155Z","iopub.execute_input":"2022-08-16T09:30:31.204527Z","iopub.status.idle":"2022-08-16T09:30:31.915498Z","shell.execute_reply.started":"2022-08-16T09:30:31.204490Z","shell.execute_reply":"2022-08-16T09:30:31.914388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp[\"size_of_ship\"] = temp['EncodedPixels'].apply(lambda x: np.sum(rle_decode(x)))","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:31.916737Z","iopub.execute_input":"2022-08-16T09:30:31.916984Z","iopub.status.idle":"2022-08-16T09:30:54.739453Z","shell.execute_reply.started":"2022-08-16T09:30:31.916956Z","shell.execute_reply":"2022-08-16T09:30:54.738415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp[temp[\"size_of_ship\"] == temp[\"size_of_ship\"].max()] #biggest ships","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:54.741109Z","iopub.execute_input":"2022-08-16T09:30:54.741500Z","iopub.status.idle":"2022-08-16T09:30:54.757176Z","shell.execute_reply.started":"2022-08-16T09:30:54.741466Z","shell.execute_reply":"2022-08-16T09:30:54.755595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rle = temp[temp[\"size_of_ship\"] == temp[\"size_of_ship\"].max()]['EncodedPixels']\nall_mask = rle_decode(rle[0])\nplt.imshow(all_mask) #Show the biggest ship mask","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:54.759859Z","iopub.execute_input":"2022-08-16T09:30:54.760492Z","iopub.status.idle":"2022-08-16T09:30:54.942528Z","shell.execute_reply.started":"2022-08-16T09:30:54.760454Z","shell.execute_reply":"2022-08-16T09:30:54.941572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(cv2.imread(os.path.join(train_dir,'a129c36b3.jpg')))","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:54.944392Z","iopub.execute_input":"2022-08-16T09:30:54.944681Z","iopub.status.idle":"2022-08-16T09:30:55.195688Z","shell.execute_reply.started":"2022-08-16T09:30:54.944656Z","shell.execute_reply":"2022-08-16T09:30:55.194157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Actually also dataset have replicated images**","metadata":{}},{"cell_type":"code","source":"plt.imshow(cv2.imread(os.path.join(train_dir,'eba27cc8a.jpg')))","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:55.197500Z","iopub.execute_input":"2022-08-16T09:30:55.197753Z","iopub.status.idle":"2022-08-16T09:30:55.465938Z","shell.execute_reply.started":"2022-08-16T09:30:55.197728Z","shell.execute_reply":"2022-08-16T09:30:55.464613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Lets look on the distribution of ship sizes","metadata":{}},{"cell_type":"code","source":"sns.histplot(temp['size_of_ship'], bins= 15) ","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:55.467038Z","iopub.execute_input":"2022-08-16T09:30:55.468076Z","iopub.status.idle":"2022-08-16T09:30:55.676355Z","shell.execute_reply.started":"2022-08-16T09:30:55.468048Z","shell.execute_reply":"2022-08-16T09:30:55.675375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Histogram with long tails , we have many small sized ships in contrast to max size ship**","metadata":{}},{"cell_type":"markdown","source":"Dataset have class imbalance, so lets see actually how many pixels of positive class we have","metadata":{}},{"cell_type":"code","source":"postive_class_pixels = temp[\"size_of_ship\"].sum()\nall_pixels = temp.shape[0] * 768* 768\nprint(f\"\"\"pixels percentage of positive class:{postive_class_pixels/all_pixels * 100} | calculated only for images with ships\nSo when we have all ~190000 images it would be even smaller\"\"\")","metadata":{"execution":{"iopub.status.busy":"2022-08-16T09:30:55.678235Z","iopub.execute_input":"2022-08-16T09:30:55.678638Z","iopub.status.idle":"2022-08-16T09:30:55.686541Z","shell.execute_reply.started":"2022-08-16T09:30:55.678591Z","shell.execute_reply":"2022-08-16T09:30:55.685203Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Not so many :)","metadata":{}},{"cell_type":"markdown","source":"So as we can see from the EDA we have a dataset with class imbalance and actually very small masks of positive class, some portions of replicated and corrupted, bad labeled images(not all ships have coressponding pixel area).\nSo it would be better to experiment discarding some portions of images where we have only negative class(where is no ship) for segmentation, and create a simple binary classifier for detecting whether a ship on an image or not which will stand and filter non ship images, so segmentation model have to work with less photos of just background\n","metadata":{}}]}