{"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":"markdown","source":"# Import packages","metadata":{}},{"cell_type":"code","source":"# import libraries \nimport numpy as np \nimport pandas as pd\nimport os\nfrom pathlib import Path\nimport cv2\nimport copy\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.layers.experimental import preprocessing\n\nfrom IPython.display import clear_output\nimport matplotlib.pyplot as plt\n\nimport imageio\n\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\n\nfrom skimage.morphology import label\nimport random","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:21:29.656598Z","iopub.execute_input":"2021-11-11T23:21:29.656852Z","iopub.status.idle":"2021-11-11T23:21:36.400509Z","shell.execute_reply.started":"2021-11-11T23:21:29.656775Z","shell.execute_reply":"2021-11-11T23:21:36.399746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load input files","metadata":{}},{"cell_type":"code","source":"# input\nDIR = '../input/sartorius-cell-instance-segmentation'\nIMG_HEIGHT, IMG_WIDTH = (512, 512)\nHEIGHT, WIDTH = (520,704)\nIMG_CHANNELS = 1\nTEST_PATH = DIR + '/test/'\n\nsample_submission = pd.read_csv(DIR + '/sample_submission.csv')\n\n# output \ncsv_output = os.path.join('./', 'submission.csv') ","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:21:36.402214Z","iopub.execute_input":"2021-11-11T23:21:36.402465Z","iopub.status.idle":"2021-11-11T23:21:36.418281Z","shell.execute_reply.started":"2021-11-11T23:21:36.402431Z","shell.execute_reply":"2021-11-11T23:21:36.417598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#CODE FROM UnetFromScratch\n# 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    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\n\ndef rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    ref: https://www.kaggle.com/dragonzhang/positive-score-with-detectron-3-3-inference\n    '''\n    pixels = img.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\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();\n    \ndef get_mask(image_id, df):\n    '''\n    Uses rle_decode() to get ndarray from mask using image_id in dataframe (df).\n    ref: https://www.kaggle.com/barteksadlej123/sartors-tf-starter\n    '''\n    current = df[df[\"id\"] == image_id]\n    labels = current[\"annotation\"].tolist()\n    \n    mask = np.zeros((HEIGHT, WIDTH))\n    for label in labels:\n        mask += rle_decode(label, (HEIGHT, WIDTH))\n    mask = mask.clip(0, 1)\n    \n    return mask","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:21:36.420012Z","iopub.execute_input":"2021-11-11T23:21:36.420692Z","iopub.status.idle":"2021-11-11T23:21:36.439053Z","shell.execute_reply.started":"2021-11-11T23:21:36.420542Z","shell.execute_reply":"2021-11-11T23:21:36.438360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"# reference: https://www.kaggle.com/karan23258/cell-instance-segmentation-unetfromscratch\n\nmodel = load_model('../input/unet-new-model/model_011.h5')","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:21:36.442795Z","iopub.execute_input":"2021-11-11T23:21:36.443154Z","iopub.status.idle":"2021-11-11T23:21:39.750582Z","shell.execute_reply.started":"2021-11-11T23:21:36.443123Z","shell.execute_reply":"2021-11-11T23:21:39.749740Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predictions & PostProcessing","metadata":{}},{"cell_type":"code","source":"def get_sample(id_):\n    path = TEST_PATH + 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    \n    return img","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:21:39.753125Z","iopub.execute_input":"2021-11-11T23:21:39.753705Z","iopub.status.idle":"2021-11-11T23:21:39.760150Z","shell.execute_reply.started":"2021-11-11T23:21:39.753651Z","shell.execute_reply":"2021-11-11T23:21:39.759261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#most code from https://github.com/RohanTrix/Osteosarcoma-cell-Segmentation-using-Watershed/blob/master/Cell_segment.py\nimport cv2\nimport numpy as np\nfrom matplotlib import pyplot as plt\nfrom scipy import ndimage\nfrom skimage import measure, color, io\nfrom skimage.segmentation import clear_border\n\n\ndef watersheding(pred, id_):\n    # create and process the mask\n    mask = np.where(pred > 0.5, 125, 0)\n    image_p = copy.deepcopy(mask)\n    \n    img = image_p\n    img_save = cv2.imwrite('test.jpg', img)\n    img = cv2.imread('test.jpg')\n    cells=img[:,:,0]  #Blue channel. Image equivalent to grey image.\n\n    #cv2.imshow('REAL',img)\n\n    ret1, thresh = cv2.threshold(cells, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)\n\n\n    kernel = np.ones((3,3),np.uint8)\n    opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)\n    cv2.imwrite('opening.jpg',opening)\n\n    opening = clear_border(opening)\n\n    sure_bg = cv2.dilate(opening,kernel,iterations=10)\n\n    dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)\n\n    ret2, sure_fg = cv2.threshold(dist_transform,0.2*dist_transform.max(),255,0)\n\n    sure_fg = np.uint8(sure_fg)\n    unknown = cv2.subtract(sure_bg,sure_fg)\n\n    ret3, markers = cv2.connectedComponents(sure_fg)\n\n    #The entire background pixels is given value 0.\n    #This means watershed considers this region as unknown.\n    #So let us add 10 to all labels so that sure background is not 0, but 10\n    markers = markers+10\n\n    #Marked the region of unknown with zero\n    markers[unknown==255] = 0\n    '''plt.imshow(markers, cmap='jet')   #Look at the 3 distinct regions.\n    plt.show()'''\n    plt.imsave('Markers.jpg',markers)\n    #Now we are ready for watershed filling. \n    markers = cv2.watershed(img,markers)\n    \n    return markers","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:39:02.217218Z","iopub.execute_input":"2021-11-11T23:39:02.217759Z","iopub.status.idle":"2021-11-11T23:39:02.228282Z","shell.execute_reply.started":"2021-11-11T23:39:02.217718Z","shell.execute_reply":"2021-11-11T23:39:02.227374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_cell_instances(pred, id_):\n    \n    markers = watersheding(pred, id_)\n    # reshape to original shape\n    markers_2 = resize(markers, (HEIGHT, WIDTH), mode='constant', preserve_range=True)\n    #markers_2 = copy.deepcopy(np.pad(markers, ((0, 8), (0, 192)), constant_values=0))\n    # convert to pd.DataFrame\n    m_2 = pd.DataFrame(markers_2)\n    \n    for idx in np.unique(markers_2):\n        if idx > 10:\n            cell_mask = np.where(m_2 == idx, 255, 0)\n            rle = rle_encode(cell_mask)\n            predictions.append((id_, rle))  \n","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:34:10.940487Z","iopub.execute_input":"2021-11-11T23:34:10.941018Z","iopub.status.idle":"2021-11-11T23:34:10.948328Z","shell.execute_reply.started":"2021-11-11T23:34:10.940979Z","shell.execute_reply":"2021-11-11T23:34:10.945974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ids of samples to test\ntest_ids = sample_submission['id'].unique().tolist()\n\n# create the list of mask for each cell in the image\npredictions = []\n\nfor id_ in test_ids:\n    sample = np.asarray([get_sample(id_)])\n    sample = model.predict(sample, verbose=1)\n    get_cell_instances(sample[0,:,:,:], id_)\n    print('Done)')","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:39:09.696267Z","iopub.execute_input":"2021-11-11T23:39:09.696622Z","iopub.status.idle":"2021-11-11T23:39:25.042004Z","shell.execute_reply.started":"2021-11-11T23:39:09.696580Z","shell.execute_reply":"2021-11-11T23:39:25.041074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Generate submission","metadata":{}},{"cell_type":"code","source":"# get test ids\ntest_ids = [cell[0] for cell in predictions]\n# run length encoding\npredicted = [cell[1] for cell in predictions]","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:39:25.043982Z","iopub.execute_input":"2021-11-11T23:39:25.044209Z","iopub.status.idle":"2021-11-11T23:39:25.050081Z","shell.execute_reply.started":"2021-11-11T23:39:25.044183Z","shell.execute_reply":"2021-11-11T23:39:25.049151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# generate submission data frame \nsubmission = pd.DataFrame.from_dict({'id': test_ids, 'predicted': predicted} )\nsubmission = submission.sort_values( ['id'], ascending=True )\nsubmission.to_csv(csv_output, index=False)","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:39:25.051304Z","iopub.execute_input":"2021-11-11T23:39:25.051714Z","iopub.status.idle":"2021-11-11T23:39:25.100081Z","shell.execute_reply.started":"2021-11-11T23:39:25.051677Z","shell.execute_reply":"2021-11-11T23:39:25.099301Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#pd.read_csv(csv_output)","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:39:25.101974Z","iopub.execute_input":"2021-11-11T23:39:25.102220Z","iopub.status.idle":"2021-11-11T23:39:25.108192Z","shell.execute_reply.started":"2021-11-11T23:39:25.102185Z","shell.execute_reply":"2021-11-11T23:39:25.107396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle_decode(mask_rle, shape, color=1):\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    ref: https://www.kaggle.com/inversion/run-length-decoding-quick-start\n    '''\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.float32)\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = color\n    return img.reshape(shape)\n\ndef get_mask(image_id, df):\n    '''\n    Uses rle_decode() to get ndarray from mask using image_id in dataframe (df).\n    ref: https://www.kaggle.com/barteksadlej123/sartors-tf-starter\n    '''\n    current = df[df[\"id\"] == image_id]\n    labels = current[\"annotation\"].tolist()\n    \n    mask = np.zeros((HEIGHT, WIDTH))\n    for label in labels:\n        mask += rle_decode(label, (HEIGHT, WIDTH))\n    mask = mask.clip(0, 1)\n    \n    return mask","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:39:25.111501Z","iopub.execute_input":"2021-11-11T23:39:25.111723Z","iopub.status.idle":"2021-11-11T23:39:25.121029Z","shell.execute_reply.started":"2021-11-11T23:39:25.111698Z","shell.execute_reply":"2021-11-11T23:39:25.120166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"HEIGHT, WIDTH = (520,704)\n# ids of samples to test\nimage_ids = sample_submission['id'].unique().tolist()\n\nsanity = pd.DataFrame.from_dict({'id': test_ids, 'annotation': predicted} )\n\nfor image_id in image_ids:\n    img = cv2.imread(f\"../input/sartorius-cell-instance-segmentation/test/{image_id}.png\")\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n    mask = get_mask(image_id, sanity)\n\n    print(img.shape)\n    plt.figure(figsize=(16, 32))\n    plt.imshow(img[:,:,0])\n    plt.imshow(mask, alpha=0.3)\n","metadata":{"execution":{"iopub.status.busy":"2021-11-11T23:39:25.122455Z","iopub.execute_input":"2021-11-11T23:39:25.122782Z","iopub.status.idle":"2021-11-11T23:39:31.796143Z","shell.execute_reply.started":"2021-11-11T23:39:25.122745Z","shell.execute_reply":"2021-11-11T23:39:31.795371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}