{"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":"# Convert DICOM to PNG\n\n**Version 1:**\n\n- Keep aspect ratio\n- 16 bits PNG\n- 1024 largest dimension\n\n**Version 2:**\n\n- Save as dataset with data under /tmp","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport math, random\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm\nimport glob, os\nimport cv2\nimport pydicom\nimport json\nfrom datetime import datetime\nfrom joblib import Parallel, delayed","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:26:55.565719Z","iopub.execute_input":"2022-12-11T19:26:55.566321Z","iopub.status.idle":"2022-12-11T19:26:55.575185Z","shell.execute_reply.started":"2022-12-11T19:26:55.566248Z","shell.execute_reply":"2022-12-11T19:26:55.573715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -qU python-gdcm pydicom pylibjpeg","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:26:55.578436Z","iopub.execute_input":"2022-12-11T19:26:55.579305Z","iopub.status.idle":"2022-12-11T19:27:07.138882Z","shell.execute_reply.started":"2022-12-11T19:26:55.579247Z","shell.execute_reply":"2022-12-11T19:27:07.137319Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Pydicom:', pydicom.__version__)","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:07.140834Z","iopub.execute_input":"2022-12-11T19:27:07.141315Z","iopub.status.idle":"2022-12-11T19:27:07.148747Z","shell.execute_reply.started":"2022-12-11T19:27:07.141273Z","shell.execute_reply":"2022-12-11T19:27:07.147166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMAGE_SIZE_H, IMAGE_SIZE_W = 1024, 1024\nTRAIN_DICOM_IMAGES = \"/kaggle/input/rsna-breast-cancer-detection/train_images\"\n\nVERSION = \"v2\"\n\nDATASET_NAME = f'rsna-smbcd-%d-ar-%s' % (IMAGE_SIZE_H, VERSION)\nprint(DATASET_NAME)\n\nTRAIN_IMAGES = f'/tmp/{DATASET_NAME}/train/'","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:07.150427Z","iopub.execute_input":"2022-12-11T19:27:07.150822Z","iopub.status.idle":"2022-12-11T19:27:07.161525Z","shell.execute_reply.started":"2022-12-11T19:27:07.150772Z","shell.execute_reply":"2022-12-11T19:27:07.160194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create Kaggle Dataset if not exists\n!rm -r /tmp/{DATASET_NAME}","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:07.164904Z","iopub.execute_input":"2022-12-11T19:27:07.16535Z","iopub.status.idle":"2022-12-11T19:27:08.291342Z","shell.execute_reply.started":"2022-12-11T19:27:07.16531Z","shell.execute_reply":"2022-12-11T19:27:08.289941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs(TRAIN_IMAGES, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:08.293121Z","iopub.execute_input":"2022-12-11T19:27:08.293895Z","iopub.status.idle":"2022-12-11T19:27:08.300329Z","shell.execute_reply.started":"2022-12-11T19:27:08.293845Z","shell.execute_reply":"2022-12-11T19:27:08.298736Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open('/kaggle/input/kaggle-api-creds/kaggle.json') as f:\n    kaggle_creds = json.load(f)\n    \nos.environ['KAGGLE_USERNAME'] = kaggle_creds['username']\nos.environ['KAGGLE_KEY'] = kaggle_creds['key']\n\n!kaggle datasets init -p /tmp/{DATASET_NAME}\n\nwith open(f'/tmp/{DATASET_NAME}/dataset-metadata.json') as f:\n    dataset_meta = json.load(f)\ndataset_meta['id'] = f'mpware/{DATASET_NAME}'\ndataset_meta['title'] = DATASET_NAME\nwith open(f'/tmp/{DATASET_NAME}/dataset-metadata.json', \"w\") as outfile:\n    json.dump(dataset_meta, outfile)\nprint(dataset_meta)\n\n!cp /tmp/{DATASET_NAME}/dataset-metadata.json /tmp/{DATASET_NAME}/meta.json\n!ls /tmp/{DATASET_NAME}\n\n!kaggle datasets create -u -p /tmp/{DATASET_NAME}","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:08.302623Z","iopub.execute_input":"2022-12-11T19:27:08.303398Z","iopub.status.idle":"2022-12-11T19:27:15.529024Z","shell.execute_reply.started":"2022-12-11T19:27:08.303351Z","shell.execute_reply":"2022-12-11T19:27:15.527329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def image_resize_keep_ar(image, width = None, height = None, inter = cv2.INTER_LINEAR):\n    dim = None\n    (h, w) = image.shape[:2]\n    if width is None and height is None:\n        return image\n    if width is None:\n        r = height / float(h)\n        dim = (int(w * r), height)\n    else:\n        r = width / float(w)\n        dim = (width, int(h * r))\n    resized = cv2.resize(image, dim, interpolation = inter)\n    return resized\n\n\ndef read_dicom_as_image(dcm_file, resize=True, keep_ar=True):\n    dicom = pydicom.dcmread(dcm_file)\n    image = dicom.pixel_array  \n    image = (image - image.min()) / (image.max() - image.min() + 1e-6)  # Float64\n    if dicom.PhotometricInterpretation == 'MONOCHROME1':\n        image = 1 - image\n    if resize is True:\n        if keep_ar is True:\n            h, w = image.shape\n            if w > h:\n                 image = image_resize_keep_ar(image, width = IMAGE_SIZE_W)\n            else:\n                 image = image_resize_keep_ar(image, height = IMAGE_SIZE_H)\n        else:\n            image = cv2.resize(image, (IMAGE_SIZE_H, IMAGE_SIZE_W), interpolation=cv2.INTER_LINEAR)\n    return image\n\n\ndef save_dicom_as_array(dcm_file, resize=True, with_image=True):\n    dimg = read_dicom_as_image(dcm_file, resize=resize) # np.array Float64 - 0.0 / 1.0\n    patient_id = dcm_file.split('/')[-2]\n    image_id   = dcm_file.split('/')[-1][:-4]\n    filename = patient_id + \"_\" + image_id    \n    if with_image is True:\n        dimg = (dimg * 65535).astype(np.uint16)\n        cv2.imwrite(TRAIN_IMAGES + filename + \".png\", dimg)\n    else:\n        np.savez(TRAIN_IMAGES + filename + \".npz\", img=dimg.astype(np.float32))\n    return filename","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:15.531335Z","iopub.execute_input":"2022-12-11T19:27:15.531973Z","iopub.status.idle":"2022-12-11T19:27:15.550493Z","shell.execute_reply.started":"2022-12-11T19:27:15.531919Z","shell.execute_reply":"2022-12-11T19:27:15.54878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"files = glob.glob(TRAIN_DICOM_IMAGES + \"/**/*.dcm\")\nprint(len(files), files[:10])","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:15.552461Z","iopub.execute_input":"2022-12-11T19:27:15.552914Z","iopub.status.idle":"2022-12-11T19:27:23.768226Z","shell.execute_reply.started":"2022-12-11T19:27:15.552878Z","shell.execute_reply":"2022-12-11T19:27:23.765932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Display one image","metadata":{}},{"cell_type":"code","source":"dimg = read_dicom_as_image(files[0])\nfiles[0], dimg.shape, dimg.min(), dimg.max(), dimg.mean(), dimg.dtype","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:23.770145Z","iopub.execute_input":"2022-12-11T19:27:23.770545Z","iopub.status.idle":"2022-12-11T19:27:24.497335Z","shell.execute_reply.started":"2022-12-11T19:27:23.770512Z","shell.execute_reply":"2022-12-11T19:27:24.496002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filename = save_dicom_as_array(files[0])","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:24.498964Z","iopub.execute_input":"2022-12-11T19:27:24.499476Z","iopub.status.idle":"2022-12-11T19:27:25.253748Z","shell.execute_reply.started":"2022-12-11T19:27:24.499427Z","shell.execute_reply":"2022-12-11T19:27:25.252429Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pimg = cv2.imread(TRAIN_IMAGES + filename + \".png\", -cv2.IMREAD_ANYDEPTH)\nfilename, pimg.shape, pimg.min(), pimg.max(), pimg.mean(), pimg.dtype","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:25.256072Z","iopub.execute_input":"2022-12-11T19:27:25.256495Z","iopub.status.idle":"2022-12-11T19:27:25.279495Z","shell.execute_reply.started":"2022-12-11T19:27:25.25646Z","shell.execute_reply":"2022-12-11T19:27:25.278313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"diff = dimg - (pimg/65535.)\nfilename, diff.shape, diff.min(), diff.max(), diff.mean(), diff.dtype","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:25.280967Z","iopub.execute_input":"2022-12-11T19:27:25.281346Z","iopub.status.idle":"2022-12-11T19:27:25.29793Z","shell.execute_reply.started":"2022-12-11T19:27:25.281314Z","shell.execute_reply":"2022-12-11T19:27:25.296701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(1, 3, figsize=(30, 15))\nd = ax[0].imshow(dimg)\nd = ax[0].set_title(\"Original image float32\")\nd = ax[1].imshow(pimg)\nd = ax[1].set_title(\"PNG 16 bits\")\nd = ax[2].imshow(diff)\nd = ax[2].set_title(\"Diff between original and 16 bits reloaded\")\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:25.301575Z","iopub.execute_input":"2022-12-11T19:27:25.301922Z","iopub.status.idle":"2022-12-11T19:27:26.777984Z","shell.execute_reply.started":"2022-12-11T19:27:25.301892Z","shell.execute_reply":"2022-12-11T19:27:26.77634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save all images","metadata":{}},{"cell_type":"code","source":"_ = Parallel(n_jobs=4)(\n    delayed(save_dicom_as_array)(filename) for filename in tqdm(files)\n)","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:27:26.779467Z","iopub.execute_input":"2022-12-11T19:27:26.780877Z","iopub.status.idle":"2022-12-11T19:35:07.409385Z","shell.execute_reply.started":"2022-12-11T19:27:26.780833Z","shell.execute_reply":"2022-12-11T19:35:07.407482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"version_name = datetime.now().strftime(\"%Y%m%d-%H%M%S\")\nprint(version_name)","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:35:07.416506Z","iopub.execute_input":"2022-12-11T19:35:07.418581Z","iopub.status.idle":"2022-12-11T19:35:07.429101Z","shell.execute_reply.started":"2022-12-11T19:35:07.418508Z","shell.execute_reply":"2022-12-11T19:35:07.427788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls /tmp/{DATASET_NAME}","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:35:07.430828Z","iopub.execute_input":"2022-12-11T19:35:07.431917Z","iopub.status.idle":"2022-12-11T19:35:08.548105Z","shell.execute_reply.started":"2022-12-11T19:35:07.431873Z","shell.execute_reply":"2022-12-11T19:35:08.54676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!kaggle datasets version -m {version_name} -p /tmp/{DATASET_NAME} -r zip -q","metadata":{"execution":{"iopub.status.busy":"2022-12-11T19:35:08.549816Z","iopub.execute_input":"2022-12-11T19:35:08.550773Z","iopub.status.idle":"2022-12-11T19:35:54.621952Z","shell.execute_reply.started":"2022-12-11T19:35:08.550728Z","shell.execute_reply":"2022-12-11T19:35:54.620183Z"},"trusted":true},"execution_count":null,"outputs":[]}]}