{"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":"<center>\n    <img align=\"center\" src=\"https://www.linkpicture.com/q/unical-logo-640x640_1.png\"> \n    <img align=\"center\" src=\"https://www.linkpicture.com/q/logo-rsna.png\"> \n<center>","metadata":{}},{"cell_type":"markdown","source":"## RSNA Screening Mammography Breast Cancer Detection\n### Find breast cancers in screening mammograms\n\nContext:\n* The RSNA International Conference on Artificial Intelligence in Radiology (RSNA-AI) is a new conference that will be held in conjunction with the 2019 RSNA Annual Meeting in Chicago, Illinois, USA.\n* The goal of the conference is to bring together radiologists, radiology trainees, and radiology researchers to discuss the latest advances in artificial intelligence (AI) and machine learning (ML) in radiology.\n* The RSNA and the American College of Radiology (ACR) provide the RSNA-AI Challenge to promote the development of AI and ML algorithms for the detection of breast cancer in mammography.\n* The goal of the challenge is to develop an algorithm that can automatically detect breast cancer in screening mammograms.\n* The work of improving the automation of detection in screening mammography may enable radiologists to be more accurate and efficient, improving the quality and safety of patient care. It could also help reduce costs and unnecessary medical procedures.\n  \nLink to the competition: https://www.kaggle.com/competitions/rsna-breast-cancer-detection/overview <br>\nLink to the dataset: https://www.kaggle.com/c/rsna-breast-cancer-detection/data","metadata":{}},{"cell_type":"markdown","source":"### Notebooks\n* [RSNA BCD | DICOM ➜ ROI-PNG](https://www.kaggle.com/code/matteoperfidio/rsna-bcd-dicom-roi-png): This notebook converts the DICOM images to PNG images with the ROI (Region of Interest).\n* [RSNA BCD | EfficientNetB3 [Train]](https://www.kaggle.com/code/matteoperfidio/rsna-bcd-efficientnetb3-train): This notebook uses the EfficientNetB3 model to train the provided dataset.\n* [RSNA BCD | EfficientNetB3 [Test]](https://www.kaggle.com/code/matteoperfidio/rsna-bcd-efficientnetb3-test): This notebook uses the EfficientNetB3 model to test the provided dataset and submit the results to the competition.\n  \n**Note**: *The test notebook is required because the model is trained on the TPU but the submission must be done via the GPU.*","metadata":{}},{"cell_type":"markdown","source":"### Overview\n* In this notebook we will see how to convert the DICOM images to PNG images and how to create the ROIs (Regions of Interest) for the images.\n\n* A Region of Interest (ROI) is a part of an image that is of interest and requires special attention. The concept of a ROI is commonly used in many application areas.  For example, in medical imaging, the boundaries of a tumor may be defined on an image or in a volume, for the purpose of measuring its size. In geographical information systems (GIS), a ROI can be taken literally as a polygonal selection from a 2D map. In computer vision and optical character recognition, the ROI defines the borders of an object under consideration. In image processing, the ROI is a rectangular subset of an image that is used to perform a specific operation. \n\n* So, in this notebook we will create the ROIs for the images in order to improves the recognition of the breast cancer. In fact, observing the images we can see that the breast cancer occupies a small part of the image, so we can create a ROI in order to focus the attention of the model on the part of the image that contains the breast cancer.","metadata":{}},{"cell_type":"markdown","source":"### Outline\n* [1. Install libraries](#1)\n* [2. Import libraries](#2)\n* [3. Configuration](#3)\n* [4. Load data](#4)\n* [5. Assing input and output paths](#5)\n* [6. Utility functions](#6)\n* [7. Create ROIs](#7)\n* [8. Results](#8)\n* [9. Additional resources](#9)","metadata":{}},{"cell_type":"markdown","source":"### 1. Install libraries <a id=\"1\"></a>","metadata":{}},{"cell_type":"code","source":"from IPython.display import clear_output","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:24.26525Z","iopub.execute_input":"2022-12-30T23:37:24.265824Z","iopub.status.idle":"2022-12-30T23:37:24.318732Z","shell.execute_reply.started":"2022-12-30T23:37:24.265711Z","shell.execute_reply":"2022-12-30T23:37:24.317785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip -q install dicomsdl\nclear_output()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:24.320519Z","iopub.execute_input":"2022-12-30T23:37:24.321537Z","iopub.status.idle":"2022-12-30T23:37:38.704997Z","shell.execute_reply.started":"2022-12-30T23:37:24.321498Z","shell.execute_reply":"2022-12-30T23:37:38.703614Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* [dicomsdl](https://github.com/tsangel/dicomsdl) is a Python library for converting DICOM images to PNG images.","metadata":{}},{"cell_type":"markdown","source":"### 2. Import libraries <a id=\"2\"></a>","metadata":{}},{"cell_type":"code","source":"import os, random, cv2, dicomsdl\nimport numpy as np\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom joblib import Parallel, delayed\nfrom matplotlib import pyplot as plt\nfrom mpl_toolkits.axes_grid1 import ImageGrid","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:38.706789Z","iopub.execute_input":"2022-12-30T23:37:38.707518Z","iopub.status.idle":"2022-12-30T23:37:39.183112Z","shell.execute_reply.started":"2022-12-30T23:37:38.707474Z","shell.execute_reply":"2022-12-30T23:37:39.182155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 3. Configuration <a id=\"3\"></a>","metadata":{}},{"cell_type":"code","source":"img_size = [1024, 512]\nresize_dim = [(1024,512), (512,256)]\n\nclass Config:\n    def __init__(self):\n\n        self.path = '/kaggle/input/rsna-breast-cancer-detection/'\n        self.train_path = self.path + 'train_images/'\n        self.test_path = self.path + 'test_images/'\n        self.train_csv = self.path + 'train.csv'\n        self.test_csv = self.path + 'test.csv'\n        \n        self.output_path = '/kaggle/working/'\n        self.train_output_path = self.output_path + 'train_images/'\n        self.test_output_path = self.output_path + 'test_images/'\n\n        self.img_size = img_size[0]\n        self.resize_dim = resize_dim[0]\n\nconfig = Config()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.186123Z","iopub.execute_input":"2022-12-30T23:37:39.186505Z","iopub.status.idle":"2022-12-30T23:37:39.196437Z","shell.execute_reply.started":"2022-12-30T23:37:39.186469Z","shell.execute_reply":"2022-12-30T23:37:39.195426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 4. Load data <a id=\"4\"></a>","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(config.train_csv)\ntest_df = pd.read_csv(config.test_csv)","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.198046Z","iopub.execute_input":"2022-12-30T23:37:39.19843Z","iopub.status.idle":"2022-12-30T23:37:39.34281Z","shell.execute_reply.started":"2022-12-30T23:37:39.198394Z","shell.execute_reply":"2022-12-30T23:37:39.341752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.345527Z","iopub.execute_input":"2022-12-30T23:37:39.346272Z","iopub.status.idle":"2022-12-30T23:37:39.373453Z","shell.execute_reply.started":"2022-12-30T23:37:39.34623Z","shell.execute_reply":"2022-12-30T23:37:39.372316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.375474Z","iopub.execute_input":"2022-12-30T23:37:39.375884Z","iopub.status.idle":"2022-12-30T23:37:39.389953Z","shell.execute_reply.started":"2022-12-30T23:37:39.375847Z","shell.execute_reply":"2022-12-30T23:37:39.387748Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 5. Assign the input and output paths <a id=\"5\"></a>","metadata":{}},{"cell_type":"code","source":"train_df['dicom_path'] = config.train_path + train_df['patient_id'].astype(str) + '/' + train_df['image_id'].astype(str) + '.dcm'\ntrain_df['image_path'] = config.train_output_path + train_df['patient_id'].astype(str) + '/' + train_df['image_id'].astype(str) + '.png'\n\ntest_df['dicom_path'] = config.test_path + test_df['patient_id'].astype(str) + '/' + test_df['image_id'].astype(str) + '.dcm'\ntest_df['image_path'] = config.test_output_path + test_df['patient_id'].astype(str) + '/' + test_df['image_id'].astype(str) + '.png'","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.391563Z","iopub.execute_input":"2022-12-30T23:37:39.391838Z","iopub.status.idle":"2022-12-30T23:37:39.586111Z","shell.execute_reply.started":"2022-12-30T23:37:39.391812Z","shell.execute_reply":"2022-12-30T23:37:39.585148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.587495Z","iopub.execute_input":"2022-12-30T23:37:39.58794Z","iopub.status.idle":"2022-12-30T23:37:39.610423Z","shell.execute_reply.started":"2022-12-30T23:37:39.587904Z","shell.execute_reply":"2022-12-30T23:37:39.6095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.615301Z","iopub.execute_input":"2022-12-30T23:37:39.615605Z","iopub.status.idle":"2022-12-30T23:37:39.633643Z","shell.execute_reply.started":"2022-12-30T23:37:39.615579Z","shell.execute_reply":"2022-12-30T23:37:39.632514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 6. Utility functions <a id=\"6\"></a>","metadata":{}},{"cell_type":"markdown","source":"This function is used to convert the DICOM images to PNG images. In particular, it takes as input the path of the DICOM image and returns the image in PNG format using the library dicomsdl.","metadata":{}},{"cell_type":"code","source":"def dicom_to_png(dicom_path):\n    dicom = dicomsdl.open(dicom_path)\n    image = dicom.pixelData(storedvalue=False)\n    image = image - np.min(image)\n    image = image / np.max(image)\n\n    if dicom.PhotometricInterpretation == 'MONOCHROME1':\n        image = 1.0 - image\n    \n    image = cv2.resize(image, (config.img_size, config.img_size), interpolation=cv2.INTER_LINEAR)\n    image = (image * 255).astype(np.uint8)\n    return image","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.636512Z","iopub.execute_input":"2022-12-30T23:37:39.63686Z","iopub.status.idle":"2022-12-30T23:37:39.645417Z","shell.execute_reply.started":"2022-12-30T23:37:39.636826Z","shell.execute_reply":"2022-12-30T23:37:39.644074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The following function is used to create the ROIs for the images. In particular, it takes as input the path of the DICOM image and returns the image with the ROI.","metadata":{}},{"cell_type":"code","source":"def png_to_roi(image, image_path):\n    bin_image = cv2.threshold(image, 20, 255, cv2.THRESH_BINARY)[1]\n    contours, _ = cv2.findContours(bin_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)\n    contour = max(contours, key=cv2.contourArea)\n    ys = contour.squeeze()[:, 0]\n    xs = contour.squeeze()[:, 1]\n    roi = image[np.min(xs):np.max(xs), np.min(ys):np.max(ys)]\n    return cv2.resize(roi, config.resize_dim[::-1], interpolation=cv2.INTER_LINEAR)","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.64699Z","iopub.execute_input":"2022-12-30T23:37:39.64773Z","iopub.status.idle":"2022-12-30T23:37:39.657292Z","shell.execute_reply.started":"2022-12-30T23:37:39.647667Z","shell.execute_reply":"2022-12-30T23:37:39.656275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 7. Create ROIs <a id=\"7\"></a>","metadata":{}},{"cell_type":"code","source":"def process(dicom_path, image_path):\n    image = dicom_to_png(dicom_path)\n    os.makedirs(os.path.dirname(image_path), exist_ok=True)\n    image = png_to_roi(image, image_path)\n    cv2.imwrite(image_path, image)","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.658296Z","iopub.execute_input":"2022-12-30T23:37:39.658605Z","iopub.status.idle":"2022-12-30T23:37:39.668988Z","shell.execute_reply.started":"2022-12-30T23:37:39.658574Z","shell.execute_reply":"2022-12-30T23:37:39.667965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Parallel(n_jobs=4, backend='threading')(delayed(process)(dicom_path, image_path) \n                   for dicom_path, image_path in tqdm(zip(train_df['dicom_path'], \n                                                          train_df['image_path'])))\nclear_output()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:37:39.670647Z","iopub.execute_input":"2022-12-30T23:37:39.67116Z","iopub.status.idle":"2022-12-30T23:38:30.465941Z","shell.execute_reply.started":"2022-12-30T23:37:39.671113Z","shell.execute_reply":"2022-12-30T23:38:30.46014Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Parallel(n_jobs=4, backend='threading')(delayed(process)(dicom_path, image_path) \n                   for dicom_path, image_path in tqdm(zip(test_df['dicom_path'], \n                                                          test_df['image_path'])))\nclear_output()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:38:30.472975Z","iopub.status.idle":"2022-12-30T23:38:30.486306Z","shell.execute_reply.started":"2022-12-30T23:38:30.485623Z","shell.execute_reply":"2022-12-30T23:38:30.485687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 8. Results <a id=\"8\"></a>","metadata":{}},{"cell_type":"code","source":"def plot_images(images, titles, rows=2, cols=5, figsize=(20, 15)):\n    fig = plt.figure(figsize=figsize)\n    grid = ImageGrid(fig, 111, nrows_ncols=(rows, cols), axes_pad=0.25)\n    for ax, im, title in zip(grid, images, titles):\n        ax.imshow(im)\n        ax.set_title(title)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:38:30.494124Z","iopub.status.idle":"2022-12-30T23:38:30.49848Z","shell.execute_reply.started":"2022-12-30T23:38:30.497812Z","shell.execute_reply":"2022-12-30T23:38:30.497876Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_df = train_df.sample(10).reset_index(drop=True)\n\nimages = []\ntitles = []\n\nfor i in range(10):\n    image = cv2.imread(sample_df['image_path'][i])\n    images.append(image)\n    titles.append(sample_df['cancer'][i])\n\nplot_images(images, titles)","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:38:30.507516Z","iopub.status.idle":"2022-12-30T23:38:30.508905Z","shell.execute_reply.started":"2022-12-30T23:38:30.508525Z","shell.execute_reply":"2022-12-30T23:38:30.508554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 9. Additional resources <a id=\"9\"></a>","metadata":{}},{"cell_type":"code","source":"!cp /kaggle/input/rsna-breast-cancer-detection/train.csv /kaggle/working/\n!cp /kaggle/input/rsna-breast-cancer-detection/test.csv /kaggle/working/\n!cp /kaggle/input/rsna-breast-cancer-detection/sample_submission.csv /kaggle/working/","metadata":{"execution":{"iopub.status.busy":"2022-12-30T23:38:30.518492Z","iopub.status.idle":"2022-12-30T23:38:30.519499Z","shell.execute_reply.started":"2022-12-30T23:38:30.519107Z","shell.execute_reply":"2022-12-30T23:38:30.519136Z"},"trusted":true},"execution_count":null,"outputs":[]}]}