{"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":"Hello fellow Kagglers,\n\nThis notebook demonstrates the inference using the Mask-RCNN EfficientNetV2 implementation from [this](https://www.kaggle.com/markwijkhuizen/sartorius-mask-rcnn-efficientnetv2-train-2h) notebook.\n\nThe inference consists of predicting all instances for a test image, removing overlap and run-length encoding each instance.\n\n**V2**\n\n- Added per cell_type minimum confidence level\n- Added per cell_type minimum size based on 1-percentile cell_type size\n- Mask-RCNN model architecture improvements\n\n**V3**\n- Instance confidence level based on semantic mask trained in [this](https://www.kaggle.com/markwijkhuizen/sartorius-training-upsampling-tf-public) notebook. The predicted semantic mask predicts which pixel belong to any cell, it does not segment instances nor does it predict the cell type. It does however predicts whether a pixel belongs to an instance. The predicted instance mask is multiplied with the semantic mask and divided by the instance size to get a mean pixel confidence score. This score is thresholded to filter out instances which the semantic mask predictor does not recognise as cells.","metadata":{}},{"cell_type":"code","source":"# Library to silence Tensorflow Logs\n!pip install -q /kaggle/input/maskrcnn-tf-2-efficientnetv2-caching/silence_tensorflow-1.1.1\n\nimport silence_tensorflow.auto","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:08:44.141550Z","iopub.execute_input":"2021-12-05T11:08:44.141913Z","iopub.status.idle":"2021-12-05T11:09:17.856716Z","shell.execute_reply.started":"2021-12-05T11:08:44.141798Z","shell.execute_reply":"2021-12-05T11:09:17.855920Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Install LZ4 library from wheel file\n!pip install -q /kaggle/input/maskrcnn-tf-2-efficientnetv2-caching/lz4-3.1.3-cp37-cp37m-manylinux1_x86_64.whl","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:17.858432Z","iopub.execute_input":"2021-12-05T11:09:17.858717Z","iopub.status.idle":"2021-12-05T11:09:44.437148Z","shell.execute_reply.started":"2021-12-05T11:09:17.858688Z","shell.execute_reply":"2021-12-05T11:09:44.436323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Add the EfficientNetV2 and Mask-RCNN folder to path, which allows importing them\nimport sys\nsys.path.append('/kaggle/input/maskrcnn-tf-2-efficientnetv2-caching/Instance_Segmentation/efficientnetv2')\nsys.path.append('/kaggle/input/maskrcnn-tf-2-efficientnetv2-caching/Instance_Segmentation/Mask_RCNN')","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:44.438830Z","iopub.execute_input":"2021-12-05T11:09:44.439120Z","iopub.status.idle":"2021-12-05T11:09:44.443319Z","shell.execute_reply.started":"2021-12-05T11:09:44.439085Z","shell.execute_reply":"2021-12-05T11:09:44.442586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport mrcnn.utils as utils\nimport mrcnn.model as modellib\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\n\nimport os\nimport sys\nimport json\nimport time\nimport skimage\nimport imageio\nimport glob\nimport effnetv2_model\n\nfrom PIL import Image, ImageDraw\nfrom tqdm.notebook import tqdm\nfrom sklearn.model_selection import KFold\nfrom PIL import Image, ImageEnhance\nfrom mrcnn.config import Config\nfrom mrcnn import visualize\n\n# ignore warnings to make outputs clearer\nimport warnings\nwarnings.filterwarnings('ignore')\n\nprint(f'Python Version: {sys.version}')\nprint(f'Tensorflow Version: {tf.__version__}')\nprint(f'Tensorflow Keras Version: {tf.keras.__version__}')","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:44.444630Z","iopub.execute_input":"2021-12-05T11:09:44.445109Z","iopub.status.idle":"2021-12-05T11:09:45.929377Z","shell.execute_reply.started":"2021-12-05T11:09:44.445076Z","shell.execute_reply":"2021-12-05T11:09:45.928591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Num GPUs Available: \", len(tf.config.experimental.list_physical_devices('GPU')))","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:45.931510Z","iopub.execute_input":"2021-12-05T11:09:45.931702Z","iopub.status.idle":"2021-12-05T11:09:46.077378Z","shell.execute_reply.started":"2021-12-05T11:09:45.931679Z","shell.execute_reply":"2021-12-05T11:09:46.076650Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image Dimension\nHEIGHT = 520\nWIDTH = 704\nSHAPE = (HEIGHT, WIDTH)\n\n# Image target dimension, divisible by 64\nHEIGHT_TARGET = 576\nWIDTH_TARGET = 704\nSHAPE_TARGET = (HEIGHT_TARGET, WIDTH_TARGET)\nBATCH_SIZE = 1\n\nDEBUG = True\nDEBUG_SIZE = 50\n\n# Make Mark-RCNN a pixel confidence mask instead of a binary mask\nPIXEL_CONFIDENCE_MASKS = True","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:46.078905Z","iopub.execute_input":"2021-12-05T11:09:46.079529Z","iopub.status.idle":"2021-12-05T11:09:46.086184Z","shell.execute_reply.started":"2021-12-05T11:09:46.079489Z","shell.execute_reply":"2021-12-05T11:09:46.085427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv('../input/sartorius-cell-instance-segmentation/train.csv')\n\n# Unique Cell Names\nCELL_NAMES = np.sort(train['cell_type'].unique())\nprint(f'CELL_NAMES: {CELL_NAMES}')","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:46.087650Z","iopub.execute_input":"2021-12-05T11:09:46.087927Z","iopub.status.idle":"2021-12-05T11:09:46.558043Z","shell.execute_reply.started":"2021-12-05T11:09:46.087894Z","shell.execute_reply":"2021-12-05T11:09:46.557259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference Config\n\n- **THRESHOLD_DICT**: per cell_type instance threshold, instances need a minimum confidence to be included\n- **MIN_SIZE_DICT**: per cell_type minimum instance pixel size, instances need a minimum pixel size to be included\n- **MIN_CONFIDENCE_PRED_DICT**: per cell_type minimum semantic mask confidence, instance should have a minimum intensity in the predicted semantic mask\n- **MASK_THRESHOLDS_DICT**: per cell type minimum pixel confidence, pixels in a predicted mask need a minimum confidence to be included","metadata":{}},{"cell_type":"code","source":"# Threshold Dictionar\nTHRESHOLD_DICT = {\n    'astro': 0.70,  # Large Bodies\n    'cort': 0.95,   # Sparse Dots\n    'shsy5y': 0.70, # Many Connected Dots\n}\n\nLABEL2THRESHOLD = dict([(CELL_NAMES.tolist().index(name) + 1, THRESHOLD_DICT[name]) for name in CELL_NAMES])\nprint(f'LABEL2THRESHOLD: {LABEL2THRESHOLD}')\n\n# Minimum Instance Size Dictionary\nMIN_SIZE_DICT = {\n    'astro': 110,  # Large Bodies\n    'cort': 60,   # Sparse Dots\n    'shsy5y': 50, # Many Connected Dots\n}\nLABEL2MIN_SIZE = dict([(CELL_NAMES.tolist().index(name) + 1, MIN_SIZE_DICT[name]) for name in CELL_NAMES])\nprint(f'LABEL2MIN_SIZE: {LABEL2MIN_SIZE}')\n\n# Minimum Mask Confidence\nMIN_SEM_MASK_CONF_DICT = {\n    'astro': 0.30,  # Large Bodies\n    'cort': 0.30,   # Sparse Dots\n    'shsy5y': 0.30, # Many Connected Dots\n}\nLABEL2MIN_SEM_MASK_CONF = dict([(CELL_NAMES.tolist().index(name) + 1, MIN_SEM_MASK_CONF_DICT[name]) for name in CELL_NAMES])\nprint(f'LABEL2MIN_SEM_MASK_CONF: {LABEL2MIN_SEM_MASK_CONF}')\n\n# Minimum Mask Confidence\nMASK_THRESHOLDS_DICT = {\n    'astro': 0.30,  # Large Bodies\n    'cort': 0.25,   # Sparse Dots\n    'shsy5y': 0.40, # Many Connected Dots\n}\nLABEL2MASK_THRESHOLD = dict([(CELL_NAMES.tolist().index(name) + 1, MASK_THRESHOLDS_DICT[name]) for name in CELL_NAMES])\nprint(f'LABEL2MASK_THRESHOLD: {LABEL2MASK_THRESHOLD}')","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:46.559167Z","iopub.execute_input":"2021-12-05T11:09:46.560006Z","iopub.status.idle":"2021-12-05T11:09:46.572198Z","shell.execute_reply.started":"2021-12-05T11:09:46.559968Z","shell.execute_reply":"2021-12-05T11:09:46.571519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Mask-RCNN Inference Config","metadata":{}},{"cell_type":"code","source":"class InferenceConfig(Config):\n    NAME = \"cell\"\n\n    # Set batch size to 1.\n    GPU_COUNT = 1\n    IMAGES_PER_GPU = BATCH_SIZE\n    \n    # Number of Classes\n    NUM_CLASSES = 1 + len(CELL_NAMES)\n\n    # Image Dimensions\n    IMAGE_MIN_DIM = HEIGHT_TARGET\n    IMAGE_MAX_DIM = WIDTH_TARGET\n    IMAGE_SHAPE = [HEIGHT_TARGET, WIDTH_TARGET, 3]\n    IMAGE_RESIZE_MODE = 'none'\n\n    STEPS_PER_EPOCH = DEBUG_SIZE if DEBUG else int(N_SAMPLES / BATCH_SIZE)\n    \n    BACKBONE = 'efficientnetv2-b0'\n\n    # Training Structure\n    FPN_CLASSIF_FC_LAYERS_SIZE = 1024\n    RPN_ANCHOR_SCALES = (32, 64, 128, 256, 512)\n    \n    # Training Structure\n    RPN_ANCHOR_SCALES = (32, 64, 128, 256, 512)\n    # Regions of Interest\n    PRE_NMS_LIMIT = 6000\n    # Non Max Supression\n    POST_NMS_ROIS_TRAINING = 2000\n    POST_NMS_ROIS_INFERENCE = 2000\n    # Instances\n    MAX_GT_INSTANCES = 790\n    TRAIN_ROIS_PER_IMAGE = 200\n    DETECTION_MAX_INSTANCES = 400\n    \n    # Thresholds\n    RPN_NMS_THRESHOLD = 0.70        # IoU Threshold for RPN proposals and GT\n    DETECTION_MIN_CONFIDENCE = 0.50 # Non-Background Confidence Threshold\n    DETECTION_NMS_THRESHOLD = 0.30  # IoU Threshold for ROI and GT\n    ROI_POSITIVE_RATIO = 0.33\n    \n    # Mini Mask\n    USE_MINI_MASK = False\n    MINI_MASK_SHAPE = (112, 112)\n    MASK_SHAPE = (56, 56)\n    \n    TRAIN_BN = False\n    \n    # Learning Rate\n    LEARNING_RATE = 0.004\n    N_WARMUP_STEPS = 2\n    \n    PIXEL_CONFIDENCE_MASKS = PIXEL_CONFIDENCE_MASKS\n\ninference_config = InferenceConfig()\ninference_config.display()","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:46.573912Z","iopub.execute_input":"2021-12-05T11:09:46.574107Z","iopub.status.idle":"2021-12-05T11:09:46.598402Z","shell.execute_reply.started":"2021-12-05T11:09:46.574084Z","shell.execute_reply":"2021-12-05T11:09:46.597743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Mask-RCNN Model","metadata":{}},{"cell_type":"code","source":"# Recreate the model in inference mode\nmodel_dir = '/kaggle/input/sartorius-maskrcnn-efficientnetv2-dataset/model_checkpoints'\nmodel = modellib.MaskRCNN(mode='inference', config=inference_config, model_dir=model_dir)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:46.600140Z","iopub.execute_input":"2021-12-05T11:09:46.600408Z","iopub.status.idle":"2021-12-05T11:09:58.764191Z","shell.execute_reply.started":"2021-12-05T11:09:46.600375Z","shell.execute_reply":"2021-12-05T11:09:58.763427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set EfficientNetV2-B0 Head Untrainable\nif 'efficientnetv2-b' in  inference_config.BACKBONE:\n    model.keras_model.layers[1].layers[-1].trainable = False\n\n# Find Last Model\nmodel_path = model.find_last()\n\n# Load Model Weights\nprint(f'Loading weights from: {model_path}')\nmodel.load_weights(model_path, by_name=True)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:09:58.765356Z","iopub.execute_input":"2021-12-05T11:09:58.765617Z","iopub.status.idle":"2021-12-05T11:10:06.455969Z","shell.execute_reply.started":"2021-12-05T11:09:58.765585Z","shell.execute_reply":"2021-12-05T11:10:06.455214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Semantic Segmentation Model","metadata":{}},{"cell_type":"code","source":"# Inspiration: https://www.tensorflow.org/tutorials/generative/pix2pix#build_an_input_pipeline_with_tfdata\ndef upsample(x, concat, filters, size, name, dropout=0.0):\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    x = tf.keras.layers.Conv2DTranspose(\n            filters, # Number of Convolutional Filters\n            size, # Kernel Size\n            strides=2, # Kernel Steps\n            padding='SAME', # Keep Dimensions\n            kernel_initializer=initializer, # Weight Initializer\n            use_bias=False, # Do not use Bias only Weights\n            name=f'Conv2DTranspose_{name}' # Name of Layer\n        )(x)\n    \n    x = tf.keras.layers.BatchNormalization(name=f'BatchNormalization_{name}')(x)\n\n    if dropout > 0.0:\n        x = tf.keras.layers.Dropout(dropout, name=f'Dropout_{name}')(x)\n\n    x = tf.keras.layers.ReLU(name=f'ReLy_{name}')(x)\n    x = tf.keras.layers.Concatenate(name=f'Concatenate_{name}')([x, concat])\n\n    return x","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:06.458001Z","iopub.execute_input":"2021-12-05T11:10:06.458430Z","iopub.status.idle":"2021-12-05T11:10:06.466103Z","shell.execute_reply.started":"2021-12-05T11:10:06.458392Z","shell.execute_reply":"2021-12-05T11:10:06.465268Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_semantic_segmentation_model():\n    # enable XLA optmizations\n    tf.config.optimizer.set_jit(True)\n    \n    # EfficientNetV2 Backbone\n    cnn = effnetv2_model.get_model(f'efficientnetv2-s', include_top=False, weights=None)\n\n    # Inputs, note the names are equal to the dictionary keys in the dataset\n    grayscale_image = tf.keras.layers.Input([HEIGHT_TARGET, WIDTH_TARGET, 1], name='image', dtype=tf.float32)\n\n    # CNN call, we need only the output layer\n    rgb_image = tf.keras.layers.Conv2D(3, kernel_size=1, strides=1)(grayscale_image)\n    embedding, up5, up4, up3, up2, up1 = cnn(rgb_image, with_endpoints=True)\n    print(f'embedding shape: {embedding.shape} up1 shape: {up1.shape}, up2 shape: {up2.shape}')\n    print(f'up3 shape: {up3.shape}, up4 shape: {up4.shape}, up5 shape: {up5.shape}')\n\n\n    x = upsample(up1, up2, up2.shape[-1] * 2, 3, 'upsample1_17x22', dropout=0.00)\n    x = upsample(x, up3, up3.shape[-1] * 2, 3, 'upsample2_34x44', dropout=0.00)\n    x = upsample(x, up4, up4.shape[-1] * 2, 3, 'upsample3_68x88', dropout=0.00)\n    x = upsample(x, up5, up5.shape[-1] * 2, 3, 'upsample4_136x176', dropout=0.00)\n\n    output = tf.keras.layers.Conv2DTranspose(\n            filters=1,\n            kernel_size=3,\n            strides=2,\n            padding='same',\n            activation='sigmoid'\n        )(x)\n\n    model = tf.keras.models.Model(inputs=grayscale_image, outputs=output)\n    model.load_weights('/kaggle/input/sartorius-training-upsampling-tf-public-dataset/model.h5')\n    model.trainable = False\n\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:06.468741Z","iopub.execute_input":"2021-12-05T11:10:06.469012Z","iopub.status.idle":"2021-12-05T11:10:06.479321Z","shell.execute_reply.started":"2021-12-05T11:10:06.468981Z","shell.execute_reply":"2021-12-05T11:10:06.478423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"semantic_segmentation_model = get_semantic_segmentation_model()","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:06.483116Z","iopub.execute_input":"2021-12-05T11:10:06.483711Z","iopub.status.idle":"2021-12-05T11:10:24.070299Z","shell.execute_reply.started":"2021-12-05T11:10:06.483683Z","shell.execute_reply":"2021-12-05T11:10:24.069500Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"semantic_segmentation_model.summary()","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:24.072719Z","iopub.execute_input":"2021-12-05T11:10:24.073149Z","iopub.status.idle":"2021-12-05T11:10:24.126672Z","shell.execute_reply.started":"2021-12-05T11:10:24.073114Z","shell.execute_reply":"2021-12-05T11:10:24.126029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Utility Functions","metadata":{}},{"cell_type":"code","source":"# Submission raises error when there is overlap between instances\n# This function removes the overlaps\n# Inspiration: https://www.kaggle.com/susnato/sartorius-segmentation-mask-rcnn-tf-inference\ndef fix_overlap(msk0):\n    \"\"\"\n    Args:\n        mask: multi-channel mask, each channel is an instance of cell, shape:(520,704,None)\n    Returns:\n        multi-channel mask with non-overlapping values, shape:(520,704,None)\n    \"\"\"\n    if PIXEL_CONFIDENCE_MASKS:\n        msk = np.where(msk0 >= 0.5, 1, 0).astype(np.bool)\n    else:\n        msk = np.array(msk0)\n        \n    msk = np.pad(msk, [[0,0],[0,0],[1,0]])\n    ins_len = msk.shape[-1]\n    msk = np.argmax(msk,axis=-1)\n    msk = tf.keras.utils.to_categorical(msk, num_classes=ins_len)\n    msk = msk[...,1:]\n    msk = msk * msk0\n    return msk\n\ndef has_overlap(msk):\n    msk = msk.astype(np.bool).astype(np.uint8) # binary mask\n    return np.any(np.sum(msk, axis=-1)>1) # only one channgel will contain value","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:24.127727Z","iopub.execute_input":"2021-12-05T11:10:24.127994Z","iopub.status.idle":"2021-12-05T11:10:24.138318Z","shell.execute_reply.started":"2021-12-05T11:10:24.127955Z","shell.execute_reply":"2021-12-05T11:10:24.137527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Run Length Encode an instance\ndef rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    img = unpad_image(img)\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)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:24.140659Z","iopub.execute_input":"2021-12-05T11:10:24.141473Z","iopub.status.idle":"2021-12-05T11:10:24.149111Z","shell.execute_reply.started":"2021-12-05T11:10:24.141437Z","shell.execute_reply":"2021-12-05T11:10:24.148436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Padding Utility Functions","metadata":{}},{"cell_type":"code","source":"# Removes the padding from an image\ndef unpad_image(image):\n    offset_h = (HEIGHT_TARGET - HEIGHT) // 2\n    offset_w = (WIDTH_TARGET - WIDTH) // 2\n    \n    return image[offset_h:offset_h+HEIGHT, offset_w:offset_w+WIDTH]","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:24.150630Z","iopub.execute_input":"2021-12-05T11:10:24.150898Z","iopub.status.idle":"2021-12-05T11:10:24.158102Z","shell.execute_reply.started":"2021-12-05T11:10:24.150845Z","shell.execute_reply":"2021-12-05T11:10:24.157397Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Pads an image\ndef pad_image(image, constant_values):\n    pad_h = (HEIGHT_TARGET - HEIGHT) // 2\n    pad_w = (WIDTH_TARGET - WIDTH) // 2\n    \n    return np.pad(image, ((pad_h, pad_h), (pad_w, pad_w)), constant_values=constant_values)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:24.159519Z","iopub.execute_input":"2021-12-05T11:10:24.160057Z","iopub.status.idle":"2021-12-05T11:10:24.166706Z","shell.execute_reply.started":"2021-12-05T11:10:24.160023Z","shell.execute_reply":"2021-12-05T11:10:24.166054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prepare Test Images","metadata":{}},{"cell_type":"code","source":"!rm -rf test ; mkdir test","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:24.168796Z","iopub.execute_input":"2021-12-05T11:10:24.169496Z","iopub.status.idle":"2021-12-05T11:10:24.863659Z","shell.execute_reply.started":"2021-12-05T11:10:24.169469Z","shell.execute_reply":"2021-12-05T11:10:24.862371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create padded images with contrast enhancement\nfor file_path in tqdm(glob.glob('/kaggle/input/sartorius-cell-instance-segmentation/test/*.png')):\n    # ReadImage\n    image = imageio.imread(file_path)\n    # Pad Image\n    image = pad_image(image, 128)\n    \n    # Create \"RGB\" image by stacking the image 3 times\n    image_mask_data_fusion = np.stack((image, image, image), axis=2)\n    \n    # Write image to working directory\n    image_id = file_path.split('/')[-1].split('.')[0]\n    imageio.imwrite(f'test/{image_id}.png', image_mask_data_fusion)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:24.865473Z","iopub.execute_input":"2021-12-05T11:10:24.865762Z","iopub.status.idle":"2021-12-05T11:10:27.293334Z","shell.execute_reply.started":"2021-12-05T11:10:24.865724Z","shell.execute_reply":"2021-12-05T11:10:27.292622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prediction Loop","metadata":{}},{"cell_type":"code","source":"# Submission Dictionary\nsubmission_dict = {\n    'id': [],\n    'predicted': [],\n}\n\nfor idx ,file_path in enumerate(tqdm(sorted(glob.glob('test/*.png')))):\n    # Image ID\n    image_id = file_path.split('/')[-1].split('.')[0]\n    # Load Image\n    img = skimage.io.imread(file_path)\n    # Get Mask-RCNN Predictions\n    results = model.detect([img], verbose= idx < 3)\n    r = results[0]\n    \n    # Predicted Semantic Mask\n    img_norm = (((img[:,:,0].astype(np.float32) - 128) / 128) / 0.589)\n    img_batch = np.expand_dims(img_norm, [0, 3])\n    semantic_mask_pred = semantic_segmentation_model.predict_on_batch(img_batch).squeeze()\n    \n    plt.figure(figsize=(16, 16))\n    plt.title(f'Predicted Semantic Mask {image_id}', size=24)\n    plt.imshow(semantic_mask_pred)\n    plt.axis(False)\n    plt.show()\n    \n    # Plot Prediction for the 3 Test Images\n    if idx < 3:\n        print(f'image_id: {image_id}')\n        visualize.display_instances(\n            img,\n            r['rois'],\n            r['masks'],\n            r['class_ids'],\n            ['BG'] + CELL_NAMES.tolist(),\n            r['scores'],\n            figsize=(16,16)\n        )\n    \n    # Optional Pixel Confidence to Binary Mask Conversion\n    if PIXEL_CONFIDENCE_MASKS:\n        mask_thresholds = [LABEL2MASK_THRESHOLD.get(class_id) for class_id in r['class_ids']]\n        r['masks'] = r['masks'] > mask_thresholds\n        \n    # Move Axis of Predicted Mask [W, H, N_INSTANCES] -> [N_INSTANCES, W, H]\n    masks_fixed = np.moveaxis(fix_overlap(r['masks']), -1, 0)\n    # Loop Through Instances\n    for idx, (m, score, label) in enumerate(zip(masks_fixed, r['scores'], r['class_ids'])):\n        # Cast to boolean mask with per cell_type mask threshold\n        if PIXEL_CONFIDENCE_MASKS:\n            m = m >= LABEL2MASK_THRESHOLD[label]\n\n        # Instance Size, sum will count True values\n        m_size = m.sum()\n        \n        # Predict Confidence using the predicted mask\n        semantic_mask__pred_confidence = (semantic_mask_pred * m).sum() / m_size\n        \n        # Requirements for instance to be included\n        # Minimum Instance Confidence and Minimum Instance Size and Semantic Mask Confidence\n        guard = score > LABEL2THRESHOLD[label] and m_size > LABEL2MIN_SIZE[label] and semantic_mask__pred_confidence > LABEL2MIN_SEM_MASK_CONF[label]\n        \n        # Always Include first instance to have at least 1 instance per test image, prevents submission error\n        if idx == 0 or guard:\n            # Image Id\n            submission_dict['id'].append(image_id)\n            # Instance Mask\n            submission_dict['predicted'].append(rle_encode(m))","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:27.294716Z","iopub.execute_input":"2021-12-05T11:10:27.295132Z","iopub.status.idle":"2021-12-05T11:10:59.560760Z","shell.execute_reply.started":"2021-12-05T11:10:27.295096Z","shell.execute_reply":"2021-12-05T11:10:59.559901Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"# Create a Pandas DataFrame from prediction dictionary\nsubmission = pd.DataFrame.from_dict(submission_dict)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:59.562304Z","iopub.execute_input":"2021-12-05T11:10:59.562655Z","iopub.status.idle":"2021-12-05T11:10:59.570330Z","shell.execute_reply.started":"2021-12-05T11:10:59.562618Z","shell.execute_reply":"2021-12-05T11:10:59.569474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display(submission.head())","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:59.571884Z","iopub.execute_input":"2021-12-05T11:10:59.572136Z","iopub.status.idle":"2021-12-05T11:10:59.590738Z","shell.execute_reply.started":"2021-12-05T11:10:59.572104Z","shell.execute_reply":"2021-12-05T11:10:59.590070Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display(submission.info())","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:59.592531Z","iopub.execute_input":"2021-12-05T11:10:59.593075Z","iopub.status.idle":"2021-12-05T11:10:59.608425Z","shell.execute_reply.started":"2021-12-05T11:10:59.593042Z","shell.execute_reply":"2021-12-05T11:10:59.607583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save submission as CSV\nsubmission.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T11:10:59.609925Z","iopub.execute_input":"2021-12-05T11:10:59.610499Z","iopub.status.idle":"2021-12-05T11:10:59.622100Z","shell.execute_reply.started":"2021-12-05T11:10:59.610463Z","shell.execute_reply":"2021-12-05T11:10:59.621460Z"},"trusted":true},"execution_count":null,"outputs":[]}]}