{"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":"import numpy as np\nimport pandas as pd\nimport cv2\nfrom PIL import Image, ImageDraw\nimport os","metadata":{"execution":{"iopub.status.busy":"2021-07-18T11:44:07.724597Z","iopub.execute_input":"2021-07-18T11:44:07.725045Z","iopub.status.idle":"2021-07-18T11:44:07.991504Z","shell.execute_reply.started":"2021-07-18T11:44:07.724954Z","shell.execute_reply":"2021-07-18T11:44:07.990514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask_path = \"masks\"\nif not (os.path.exists(mask_path)):\n    os.makedirs(mask_path)\ntrain_annotations = pd.read_csv(\"../input/ranzcr-clip-catheter-line-classification/train_annotations.csv\")\nimages_path = \"../input/ranzcr-clip-catheter-line-classification/train\"\ndef get_point(chosen):\n    points = []\n    for i, point in enumerate(train_annotations.iloc[chosen]['data'].split('],')):\n        if i==len(train_annotations.iloc[chosen]['data'].split('],'))-1:\n            xy = tuple([int(x) for x in point[2:-2].split(', ')])\n            points.append(xy)\n        else:\n            xy = tuple([int(x) for x in point[2:].split(', ')])\n            points.append(xy)\n    return points\n\nfile_names = np.unique(train_annotations['StudyInstanceUID'].values)\n\nfor file_name in file_names:\n    file_path = images_path + \"/\" + file_name + \".jpg\"\n    image = cv2.imread(file_path)\n    mask = np.zeros((image.shape[0], image.shape[1]), dtype=np.uint8)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    points = []\n    for value in train_annotations.loc[train_annotations['StudyInstanceUID']==file_name].index.values:\n        points.append(get_point(value))\n    mask = Image.fromarray(mask.astype(np.uint8), \"L\")\n    draw = ImageDraw.Draw(mask)\n    for p in points:\n        draw.line(p, fill=255, width=15)\n    mask.save(mask_path + \"/\" + file_name + \".jpg\")","metadata":{"execution":{"iopub.status.busy":"2021-07-18T11:44:10.680227Z","iopub.execute_input":"2021-07-18T11:44:10.680602Z","iopub.status.idle":"2021-07-18T12:02:06.200161Z","shell.execute_reply.started":"2021-07-18T11:44:10.680554Z","shell.execute_reply":"2021-07-18T12:02:06.198743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport random\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nplt.style.use(\"ggplot\")\n%matplotlib inline\n\nfrom tqdm import tqdm_notebook, tnrange\nfrom itertools import chain\nfrom skimage.io import imread, imshow, concatenate_images\nfrom skimage.transform import resize\nfrom skimage.morphology import label\nfrom sklearn.model_selection import train_test_split\n\nimport tensorflow as tf\n\nfrom keras.models import Model, load_model\nfrom keras.layers import Input, BatchNormalization, Activation, Dense, Dropout\nfrom keras.layers.core import Lambda, RepeatVector, Reshape\nfrom keras.layers.convolutional import Conv2D, Conv2DTranspose\nfrom keras.layers.pooling import MaxPooling2D, GlobalMaxPool2D\nfrom keras.layers.merge import concatenate, add\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\nfrom keras.optimizers import Adam\nfrom keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img","metadata":{"execution":{"iopub.status.busy":"2021-07-18T12:05:54.313873Z","iopub.execute_input":"2021-07-18T12:05:54.314292Z","iopub.status.idle":"2021-07-18T12:06:02.742225Z","shell.execute_reply.started":"2021-07-18T12:05:54.314253Z","shell.execute_reply":"2021-07-18T12:06:02.741183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set some parameters\nim_width = 256\nim_height = 256\nborder = 5","metadata":{"execution":{"iopub.status.busy":"2021-07-18T12:06:02.743635Z","iopub.execute_input":"2021-07-18T12:06:02.743881Z","iopub.status.idle":"2021-07-18T12:06:02.748177Z","shell.execute_reply.started":"2021-07-18T12:06:02.743856Z","shell.execute_reply":"2021-07-18T12:06:02.747368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ids = next(os.walk(\"./masks\"))[2] # list of names all images in the given path\nprint(\"No. of images = \", len(ids))","metadata":{"execution":{"iopub.status.busy":"2021-07-18T12:06:52.909402Z","iopub.execute_input":"2021-07-18T12:06:52.90976Z","iopub.status.idle":"2021-07-18T12:06:52.932329Z","shell.execute_reply.started":"2021-07-18T12:06:52.909725Z","shell.execute_reply":"2021-07-18T12:06:52.931237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X = np.zeros((len(ids), im_height, im_width, 1), dtype=np.float32)\ny = np.zeros((len(ids), im_height, im_width, 1), dtype=np.float32)","metadata":{"execution":{"iopub.status.busy":"2021-07-18T12:06:55.513508Z","iopub.execute_input":"2021-07-18T12:06:55.51399Z","iopub.status.idle":"2021-07-18T12:06:55.518355Z","shell.execute_reply.started":"2021-07-18T12:06:55.513952Z","shell.execute_reply":"2021-07-18T12:06:55.517471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Load the images and masks into arrays","metadata":{}},{"cell_type":"code","source":"# tqdm is used to display the progress bar\nfor n, id_ in tqdm_notebook(enumerate(ids), total=len(ids)):\n    # Load images\n    img = load_img(\"../input/ranzcr-clip-catheter-line-classification/train/\"+id_, grayscale=True)\n    if img is not None:\n        x_img = img_to_array(img)\n        x_img = resize(x_img, (256, 256, 1), mode = 'constant', preserve_range = True)\n        # Load masks\n        mask = img_to_array(load_img(\"./masks/\"+id_, grayscale=True))\n        mask = resize(mask, (256, 256, 1), mode = 'constant', preserve_range = True)\n        # Save images\n        X[n] = x_img/255.0\n        y[n] = mask/255.0","metadata":{"execution":{"iopub.status.busy":"2021-07-18T12:11:24.416163Z","iopub.execute_input":"2021-07-18T12:11:24.416539Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Split train and valid\nX_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=42)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Below code can be used to visualize the images and corresponding masks","metadata":{}},{"cell_type":"code","source":"# Visualize any randome image along with the mask\nix = random.randint(0, len(X_train))\nhas_mask = y_train[ix].max() > 0 # salt indicator\n\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize = (20, 15))\n\nax1.imshow(X_train[ix, ..., 0], cmap = 'seismic', interpolation = 'bilinear')\nif has_mask: # if salt\n    # draw a boundary(contour) in the original image separating salt and non-salt areas\n    ax1.contour(y_train[ix].squeeze(), colors = 'k', linewidths = 5, levels = [0.5])\nax1.set_title('Seismic')\n\nax2.imshow(y_train[ix].squeeze(), cmap = 'gray', interpolation = 'bilinear')\nax2.set_title('Brain Tumor Segmentation')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def conv2d_block(input_tensor, n_filters, kernel_size = 3, batchnorm = True):\n    \"\"\"Function to add 2 convolutional layers with the parameters passed to it\"\"\"\n    # first layer\n    x = Conv2D(filters = n_filters, kernel_size = (kernel_size, kernel_size),\\\n              kernel_initializer = 'he_normal', padding = 'same')(input_tensor)\n    if batchnorm:\n        x = BatchNormalization()(x)\n    x = Activation('relu')(x)\n    \n    # second layer\n    x = Conv2D(filters = n_filters, kernel_size = (kernel_size, kernel_size),\\\n              kernel_initializer = 'he_normal', padding = 'same')(input_tensor)\n    if batchnorm:\n        x = BatchNormalization()(x)\n    x = Activation('relu')(x)\n    \n    return x","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_unet(input_img, n_filters = 16, dropout = 0.1, batchnorm = True):\n    \"\"\"Function to define the UNET Model\"\"\"\n    # Contracting Path\n    c1 = conv2d_block(input_img, n_filters * 1, kernel_size = 3, batchnorm = batchnorm)\n    p1 = MaxPooling2D((2, 2))(c1)\n    p1 = Dropout(dropout)(p1)\n    \n    c2 = conv2d_block(p1, n_filters * 2, kernel_size = 3, batchnorm = batchnorm)\n    p2 = MaxPooling2D((2, 2))(c2)\n    p2 = Dropout(dropout)(p2)\n    \n    c3 = conv2d_block(p2, n_filters * 4, kernel_size = 3, batchnorm = batchnorm)\n    p3 = MaxPooling2D((2, 2))(c3)\n    p3 = Dropout(dropout)(p3)\n    \n    c4 = conv2d_block(p3, n_filters * 8, kernel_size = 3, batchnorm = batchnorm)\n    p4 = MaxPooling2D((2, 2))(c4)\n    p4 = Dropout(dropout)(p4)\n    \n    c5 = conv2d_block(p4, n_filters = n_filters * 16, kernel_size = 3, batchnorm = batchnorm)\n    \n    # Expansive Path\n    u6 = Conv2DTranspose(n_filters * 8, (3, 3), strides = (2, 2), padding = 'same')(c5)\n    u6 = concatenate([u6, c4])\n    u6 = Dropout(dropout)(u6)\n    c6 = conv2d_block(u6, n_filters * 8, kernel_size = 3, batchnorm = batchnorm)\n    \n    u7 = Conv2DTranspose(n_filters * 4, (3, 3), strides = (2, 2), padding = 'same')(c6)\n    u7 = concatenate([u7, c3])\n    u7 = Dropout(dropout)(u7)\n    c7 = conv2d_block(u7, n_filters * 4, kernel_size = 3, batchnorm = batchnorm)\n    \n    u8 = Conv2DTranspose(n_filters * 2, (3, 3), strides = (2, 2), padding = 'same')(c7)\n    u8 = concatenate([u8, c2])\n    u8 = Dropout(dropout)(u8)\n    c8 = conv2d_block(u8, n_filters * 2, kernel_size = 3, batchnorm = batchnorm)\n    \n    u9 = Conv2DTranspose(n_filters * 1, (3, 3), strides = (2, 2), padding = 'same')(c8)\n    u9 = concatenate([u9, c1])\n    u9 = Dropout(dropout)(u9)\n    c9 = conv2d_block(u9, n_filters * 1, kernel_size = 3, batchnorm = batchnorm)\n    \n    outputs = Conv2D(1, (1, 1), activation='sigmoid')(c9)\n    model = Model(inputs=[input_img], outputs=[outputs])\n    return model","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"input_img = Input((im_height, im_width, 1), name='img')\nmodel = get_unet(input_img, n_filters=16, dropout=0.05, batchnorm=True)\nmodel.compile(optimizer=Adam(), loss=\"binary_crossentropy\", metrics=[\"accuracy\"])","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks = [\n    EarlyStopping(patience=10, verbose=1),\n    ReduceLROnPlateau(factor=0.1, patience=5, min_lr=0.00001, verbose=1),\n    ModelCheckpoint('model-tgs-salt.h5', verbose=1, save_best_only=True, save_weights_only=True)\n]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"results = model.fit(X_train, y_train, batch_size=32, epochs=50, callbacks=callbacks,\\\n                    validation_data=(X_valid, y_valid))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\nplt.title(\"Learning curve\")\nplt.plot(results.history[\"loss\"], label=\"loss\")\nplt.plot(results.history[\"val_loss\"], label=\"val_loss\")\nplt.plot( np.argmin(results.history[\"val_loss\"]), np.min(results.history[\"val_loss\"]), marker=\"x\", color=\"r\", label=\"best model\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"log_loss\")\nplt.legend();","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Inference","metadata":{}},{"cell_type":"code","source":"# load the best model\nmodel.load_weights('model-tgs-salt.h5')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Evaluate on validation set (this must be equals to the best log_loss)\nmodel.evaluate(X_valid, y_valid, verbose=1)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predict on train, val and test\npreds_train = model.predict(X_train, verbose=1)\npreds_val = model.predict(X_valid, verbose=1)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Threshold predictions\npreds_train_t = (preds_train > 0.5).astype(np.uint8)\npreds_val_t = (preds_val > 0.5).astype(np.uint8)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_sample(X, y, preds, binary_preds, ix=None):\n    \"\"\"Function to plot the results\"\"\"\n    if ix is None:\n        ix = random.randint(0, len(X))\n\n    has_mask = y[ix].max() > 0\n\n    fig, ax = plt.subplots(1, 4, figsize=(20, 10))\n    ax[0].imshow(X[ix, ..., 0], cmap='seismic')\n    if has_mask:\n        ax[0].contour(y[ix].squeeze(), colors='k', levels=[0.5])\n    ax[0].set_title('Seismic')\n\n    ax[1].imshow(y[ix].squeeze())\n    ax[1].set_title('Salt')\n\n    ax[2].imshow(preds[ix].squeeze(), vmin=0, vmax=1)\n    if has_mask:\n        ax[2].contour(y[ix].squeeze(), colors='k', levels=[0.5])\n    ax[2].set_title('Salt Predicted')\n    \n    ax[3].imshow(binary_preds[ix].squeeze(), vmin=0, vmax=1)\n    if has_mask:\n        ax[3].contour(y[ix].squeeze(), colors='k', levels=[0.5])\n    ax[3].set_title('Salt Predicted binary');","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Predictions on training set","metadata":{}},{"cell_type":"code","source":"# Check if training data looks all right\nplot_sample(X_train, y_train, preds_train, preds_train_t, ix=14)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_train, y_train, preds_train, preds_train_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Predictions on test set","metadata":{}},{"cell_type":"code","source":"# Check if valid data looks all right\nplot_sample(X_valid, y_valid, preds_val, preds_val_t, ix=19)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sample(X_valid, y_valid, preds_val, preds_val_t)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}