{"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":"markdown","source":"# Sartorius - Cell Instance Segmentation\n![](https://storage.googleapis.com/kaggle-competitions/kaggle/30201/logos/header.png?t=2021-09-03-15-27-46)","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport imageio\nimport matplotlib.pyplot as plt\nimport cv2\nfrom skimage.io import imread, imshow, imread_collection, concatenate_images\nfrom skimage.transform import resize\nfrom tqdm import tqdm\nfrom keras.models import Model, load_model\nfrom keras.layers import Input\nfrom keras.layers.core import Dropout, Lambda\nfrom keras.layers.convolutional import Conv2D, Conv2DTranspose\nfrom keras.layers.pooling import MaxPooling2D\nfrom keras.layers.merge import concatenate\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint\nfrom keras import backend as K\nimport tensorflow as tf\nfrom skimage.morphology import label\nimport random","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:01.420213Z","iopub.execute_input":"2021-10-18T22:08:01.420479Z","iopub.status.idle":"2021-10-18T22:08:01.427963Z","shell.execute_reply.started":"2021-10-18T22:08:01.420448Z","shell.execute_reply":"2021-10-18T22:08:01.427008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission = pd.read_csv('../input/sartorius-cell-instance-segmentation/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:01.429818Z","iopub.execute_input":"2021-10-18T22:08:01.430338Z","iopub.status.idle":"2021-10-18T22:08:01.446214Z","shell.execute_reply.started":"2021-10-18T22:08:01.430277Z","shell.execute_reply":"2021-10-18T22:08:01.445355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Reference: https://www.kaggle.com/ihelon/cell-segmentation-run-length-decoding\n\ndef rle_decode(mask_rle, shape, color=1):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height, width, channels) of array to return \n    color: color for the mask\n    Returns numpy array (mask)\n\n    '''\n    s = mask_rle.split()\n    \n    starts = list(map(lambda x: int(x) - 1, s[0::2]))\n    lengths = list(map(int, s[1::2]))\n    ends = [x + y for x, y in zip(starts, lengths)]\n    \n    img = np.zeros((shape[0] * shape[1], shape[2]), dtype=np.float32)\n            \n    for start, end in zip(starts, ends):\n        img[start : end] = color\n    \n    return img.reshape(shape)\n\ndef plot_masks(image_id, colors=True):\n    labels = train_data[train_data[\"id\"] == image_id][\"annotation\"].tolist()\n\n    if colors:\n        mask = np.zeros((520, 704, 3))\n        for label in labels:\n            mask += rle_decode(label, shape=(520, 704, 3), color=np.random.rand(3))\n    else:\n        mask = np.zeros((520, 704, 1))\n        for label in labels:\n            mask += rle_decode(label, shape=(520, 704, 1))\n    mask = mask.clip(0, 1)\n\n    image = cv2.imread(f\"../input/sartorius-cell-instance-segmentation/train/{image_id}.png\")\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n    plt.figure(figsize=(16, 32))\n    plt.subplot(3, 1, 1)\n    plt.imshow(image)\n    plt.title('Input image')\n    plt.axis(\"off\")\n    plt.subplot(3, 1, 2)\n    plt.imshow(image)\n    plt.imshow(mask, alpha=0.5)\n    plt.title('Input image with mask')\n    plt.axis(\"off\")\n    plt.subplot(3, 1, 3)\n    plt.imshow(mask)\n    plt.title('Only mask')\n    plt.axis(\"off\")\n    \n    plt.show();","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:01.447561Z","iopub.execute_input":"2021-10-18T22:08:01.447828Z","iopub.status.idle":"2021-10-18T22:08:01.461143Z","shell.execute_reply.started":"2021-10-18T22:08:01.447795Z","shell.execute_reply":"2021-10-18T22:08:01.460341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_HEIGHT = 256\nIMG_WIDTH = 256\nIMG_CHANNELS = 1\n\nTRAIN_PATH = '../input/sartorius-cell-instance-segmentation/train/'\ntest_ids = sample_submission['id'].unique().tolist()\n\n# Get and resize test images\nX_test = np.zeros((sample_submission['id'].nunique(), IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS), dtype=np.uint8)\nprint('Getting and resizing test images ... ')\n\nfor n, id_ in tqdm(enumerate(test_ids), total=len(test_ids)):\n    path = TRAIN_PATH.replace('train', 'test') + id_\n    img = imread(path + '.png')[:,:]\n    img = resize(img, (IMG_HEIGHT, IMG_WIDTH), mode='constant', preserve_range=True)\n    img = np.expand_dims(img, axis = 2)\n    X_test[n] = img\n\nprint('Done!')","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:01.463280Z","iopub.execute_input":"2021-10-18T22:08:01.463766Z","iopub.status.idle":"2021-10-18T22:08:01.567457Z","shell.execute_reply.started":"2021-10-18T22:08:01.463717Z","shell.execute_reply":"2021-10-18T22:08:01.566693Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def dice_coefficient(y_true, y_pred):\n    numerator = 2 * tf.reduce_sum(y_true * y_pred)\n    denominator = tf.reduce_sum(y_true + y_pred)\n    return numerator / (denominator + tf.keras.backend.epsilon())","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:01.568891Z","iopub.execute_input":"2021-10-18T22:08:01.569470Z","iopub.status.idle":"2021-10-18T22:08:01.577225Z","shell.execute_reply.started":"2021-10-18T22:08:01.569429Z","shell.execute_reply":"2021-10-18T22:08:01.576113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predict on train, val and test\nmodel = load_model('../input/cell-instance-segmentation-model/best_model.h5', custom_objects={'dice_coefficient': dice_coefficient})\npreds_test = model.predict(X_test, verbose=1)\n\n# Threshold predictions\npreds_test_t = (preds_test > 0.5).astype(np.uint8)\n\n# Create list of upsampled test masks\npreds_test_upsampled = []\nfor i in range(len(preds_test)):\n    preds_test_upsampled.append(resize(np.squeeze(preds_test[i]), \n                                       (IMG_HEIGHT, IMG_WIDTH), \n                                       mode='constant', preserve_range=True))","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:01.672137Z","iopub.execute_input":"2021-10-18T22:08:01.672507Z","iopub.status.idle":"2021-10-18T22:08:03.035423Z","shell.execute_reply.started":"2021-10-18T22:08:01.672469Z","shell.execute_reply":"2021-10-18T22:08:03.034598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Run-length encoding stolen from https://www.kaggle.com/rakhlin/fast-run-length-encoding-python\ndef rle_encoding(x):\n    dots = np.where(x.flatten() == 1)[0]\n    run_lengths = []\n    prev = -2\n    for b in dots:\n        if (b>prev+1): run_lengths.extend((b + 1, 0))\n        run_lengths[-1] += 1\n        prev = b\n    return run_lengths\n\ndef prob_to_rles(x, cutoff=0.5):\n    lab_img = (x > cutoff).astype(int)\n    for i in range(1, lab_img.max() + 1):\n        yield rle_encoding(lab_img == i)","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:03.037206Z","iopub.execute_input":"2021-10-18T22:08:03.037664Z","iopub.status.idle":"2021-10-18T22:08:03.045887Z","shell.execute_reply.started":"2021-10-18T22:08:03.037622Z","shell.execute_reply":"2021-10-18T22:08:03.045106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def post_process(probability, threshold=0.5, min_size=300):\n    mask = cv2.threshold(probability, threshold, 1, cv2.THRESH_BINARY)[1]\n    num_component, component = cv2.connectedComponents(mask.astype(np.uint8))\n    predictions = []\n    for c in range(1, num_component):\n        p = (component == c)\n        if p.sum() > min_size:\n            a_prediction = np.zeros((520, 704), np.float32)\n            a_prediction[p] = 1\n            predictions.append(a_prediction)\n    return predictions","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:03.047152Z","iopub.execute_input":"2021-10-18T22:08:03.047723Z","iopub.status.idle":"2021-10-18T22:08:03.056966Z","shell.execute_reply.started":"2021-10-18T22:08:03.047687Z","shell.execute_reply":"2021-10-18T22:08:03.056277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output_df = pd.DataFrame(data = None, columns = sample_submission.columns)\ncount = 0\n\nfor n, id_ in enumerate(test_ids):\n    probability_mask = cv2.resize(preds_test_upsampled[n], dsize=(704, 520), interpolation=cv2.INTER_LINEAR)\n    predictions = post_process(probability_mask)\n    rle = [list(prob_to_rles(predictions[i]))[0] for i in range(0, len(predictions))]\n    for i in range(0, len(rle)):\n        cell_annotations = ' '.join([str(x) for x in rle[i]])\n        output_df.loc[count] = id_,cell_annotations\n        count +=1\n        \noutput_df.to_csv('submission.csv', index = False)","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:03.058119Z","iopub.execute_input":"2021-10-18T22:08:03.058677Z","iopub.status.idle":"2021-10-18T22:08:03.639336Z","shell.execute_reply.started":"2021-10-18T22:08:03.058636Z","shell.execute_reply":"2021-10-18T22:08:03.638327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output_df","metadata":{"execution":{"iopub.status.busy":"2021-10-18T22:08:03.643171Z","iopub.execute_input":"2021-10-18T22:08:03.643386Z","iopub.status.idle":"2021-10-18T22:08:03.655762Z","shell.execute_reply.started":"2021-10-18T22:08:03.643360Z","shell.execute_reply":"2021-10-18T22:08:03.655107Z"},"trusted":true},"execution_count":null,"outputs":[]}]}