{"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":"# 画像の切り抜きに関する検証\n\n判別に有効な部分を切り抜く部分のソースコードを検証する検証\n","metadata":{}},{"cell_type":"markdown","source":"## DICOM データの変換用モジュールを読み込む\n\nインターネットからインストールもできるが、投稿時を見越して、Kaggle Dataset からインストールする","metadata":{}},{"cell_type":"code","source":"!pip install /kaggle/input/dicomsdl-offline-installer/dicomsdl-0.109.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:35.130753Z","iopub.execute_input":"2023-01-23T01:40:35.131355Z","iopub.status.idle":"2023-01-23T01:40:44.339971Z","shell.execute_reply.started":"2023-01-23T01:40:35.131281Z","shell.execute_reply":"2023-01-23T01:40:44.337894Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習データのパスを取得\n\n画像を読み込むために、パスを取得する","metadata":{}},{"cell_type":"code","source":"import os\nimport pandas as pd\n\ndata_dir = '/kaggle/input/rsna-breast-cancer-detection'\n\ntrain_df = pd.read_csv(f\"{data_dir}/train.csv\")\n\ntrain_df['dcm_path'] = train_df.apply(\n    lambda i: os.path.join(\n        f\"{data_dir}\", 'train_images', str(i['patient_id']), str(i['image_id']) + '.dcm'\n    ), axis=1\n)","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:44.343079Z","iopub.execute_input":"2023-01-23T01:40:44.343595Z","iopub.status.idle":"2023-01-23T01:40:45.303125Z","shell.execute_reply.started":"2023-01-23T01:40:44.343549Z","shell.execute_reply":"2023-01-23T01:40:45.301938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## DICOM データを読み込んで画像形式に変換","metadata":{}},{"cell_type":"code","source":"import dicomsdl\nimport numpy as np\n\ndef read_xray(path, fix_monochrome = True):\n    dicom = dicomsdl.open(path)\n    data = dicom.pixelData(storedvalue=False)  # storedvalue = True for int16 return otherwise float32\n    data = data - np.min(data)\n    data = data / np.max(data)\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = 1.0 - data\n    return data","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-01-23T01:40:45.304564Z","iopub.execute_input":"2023-01-23T01:40:45.304909Z","iopub.status.idle":"2023-01-23T01:40:45.313281Z","shell.execute_reply.started":"2023-01-23T01:40:45.304882Z","shell.execute_reply":"2023-01-23T01:40:45.311463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dcm_path = train_df['dcm_path'][0]\ndcm_path","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:45.31707Z","iopub.execute_input":"2023-01-23T01:40:45.317585Z","iopub.status.idle":"2023-01-23T01:40:45.332576Z","shell.execute_reply.started":"2023-01-23T01:40:45.317546Z","shell.execute_reply":"2023-01-23T01:40:45.329826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nimage = read_xray(dcm_path)\n\nplt.imshow(np.array(image), cmap='gray')","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:45.336014Z","iopub.execute_input":"2023-01-23T01:40:45.336552Z","iopub.status.idle":"2023-01-23T01:40:47.589957Z","shell.execute_reply.started":"2023-01-23T01:40:45.336512Z","shell.execute_reply":"2023-01-23T01:40:47.588466Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 枠の切り抜き\n\n画像の枠を切り抜くために、上下左右の5ピクセル分除去する","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:47:25.372937Z","iopub.execute_input":"2023-01-23T01:47:25.373335Z","iopub.status.idle":"2023-01-23T01:47:25.379255Z","shell.execute_reply.started":"2023-01-23T01:47:25.373298Z","shell.execute_reply":"2023-01-23T01:47:25.37797Z"}}},{"cell_type":"code","source":"def crop_image(image):\n    # 画像によっては不要な枠があるので、取り除く\n    image = image[5:-5, 5:-5]\n    return image","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:47.591405Z","iopub.execute_input":"2023-01-23T01:40:47.591788Z","iopub.status.idle":"2023-01-23T01:40:47.597714Z","shell.execute_reply.started":"2023-01-23T01:40:47.591748Z","shell.execute_reply":"2023-01-23T01:40:47.596588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(image.shape)\nimage = crop_image(image)\nprint(image.shape)\nplt.imshow(np.array(image), cmap='gray')","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:47.599478Z","iopub.execute_input":"2023-01-23T01:40:47.599956Z","iopub.status.idle":"2023-01-23T01:40:49.146015Z","shell.execute_reply.started":"2023-01-23T01:40:47.599915Z","shell.execute_reply":"2023-01-23T01:40:49.144662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 空白部分の切り抜き\n\nCV2を利用して、空白部分を特定し、削除する","metadata":{}},{"cell_type":"code","source":"import cv2\n\ndef img2roi(image):\n    output= cv2.connectedComponentsWithStats((image > 0.05).astype(np.uint8)[:, :], 8, cv2.CV_32S)\n    stats = output[2] # left, top, width, height, area_size\n    \n    idx = stats[1:, 4].argmax() + 1\n    x1, y1, w, h = stats[idx][:4]\n    x2 = x1 + w\n    y2 = y1 + h\n    \n    image_fit = image[y1: y2, x1: x2]\n    \n    return image_fit","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:49.148264Z","iopub.execute_input":"2023-01-23T01:40:49.148816Z","iopub.status.idle":"2023-01-23T01:40:49.157974Z","shell.execute_reply.started":"2023-01-23T01:40:49.14877Z","shell.execute_reply":"2023-01-23T01:40:49.15675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(image.shape)\nimage = img2roi(image)\nprint(image.shape)\nplt.imshow(np.array(image), cmap='gray')","metadata":{"execution":{"iopub.status.busy":"2023-01-23T01:40:49.159926Z","iopub.execute_input":"2023-01-23T01:40:49.161248Z","iopub.status.idle":"2023-01-23T01:40:49.834513Z","shell.execute_reply.started":"2023-01-23T01:40:49.161203Z","shell.execute_reply":"2023-01-23T01:40:49.833125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# いくつかの画像で実施\n","metadata":{}},{"cell_type":"code","source":"image_size = 10\n\nfig, ax=plt.subplots(image_size, 3, figsize=(12,image_size*4))\nfor i, dcm_path in enumerate(train_df['dcm_path'][:image_size]):\n    image = read_xray(dcm_path)\n    ax[i,0].imshow(np.array(image), cmap='gray')\n\n    image = crop_image(image)\n    ax[i,1].imshow(np.array(image), cmap='gray')\n    \n    image = img2roi(image)\n    ax[i,2].imshow(np.array(image), cmap='gray')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2023-01-23T02:01:43.848641Z","iopub.execute_input":"2023-01-23T02:01:43.849088Z","iopub.status.idle":"2023-01-23T02:02:14.678459Z","shell.execute_reply.started":"2023-01-23T02:01:43.849054Z","shell.execute_reply":"2023-01-23T02:02:14.676908Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 参考\n\n* https://www.kaggle.com/code/vslaykovsky/infer-pytorch-aux-targets-weighted-loss-thres\n* https://www.kaggle.com/code/theoviel/dicom-resized-png-jpg/data\n* https://www.kaggle.com/code/awsaf49/rsna-bcd-efficientnet-tf-tpu-1vm-infer","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}