{"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":"<div align='center'><font size=\"5\" color='#353B47'>Chest-X-ray</font></div>\n<div align='center'><font size=\"4\" color=\"#353B47\">Starter exploration and data explanations</font></div>\n<br>\n<hr>","metadata":{}},{"cell_type":"markdown","source":"The objective of this notebook is to give some insights regarding common thoracic lung diseases and its localisation.","metadata":{}},{"cell_type":"markdown","source":"# <div id=\"summary\">Summary</div>\n\n**<font size=\"2\"><a href=\"#chap1\">1. Load libraries</a></font>**\n**<br><font size=\"2\"><a href=\"#chap2\">2. Quick Analysis</a></font>**\n**<br><font size=\"2\"><a href=\"#chap3\">3. Extracting meta information from .dicom files</a></font>**\n**<br><font size=\"2\"><a href=\"#chap4\">4. Preprocessing meta information</a></font>**\n**<br><font size=\"2\"><a href=\"#chap5\">5. Fusion of boxings</a></font>**\n**<br><font size=\"2\"><a href=\"#chap6\">6. Presentation of each radiographic observations</a></font>**","metadata":{}},{"cell_type":"markdown","source":"# <div id=\"chap1\">1. Load libraries","metadata":{}},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')\n\nfrom matplotlib.patches import Rectangle\nimport numpy as np\nimport pandas as pd\nimport os\nimport re\nimport random\nimport matplotlib.pyplot as plt\nimport plotly\nimport plotly.graph_objects as go\nimport plotly.express as px\nfrom pydicom import dcmread\nfrom tqdm import tqdm\nimport multiprocessing as mp","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Path to dataframe and image folders\nPATH = \"../input/vinbigdata-chest-xray-abnormalities-detection\"\n\n# Import trainset\ntrain_dataframe = pd.read_csv(os.path.join(PATH, 'train.csv'))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div id=\"chap2\">2. Quick Analysis","metadata":{}},{"cell_type":"markdown","source":"## Careful, not unique image_id !","metadata":{}},{"cell_type":"code","source":"train_dataframe.image_id.value_counts()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_dataframe.image_id.unique())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This means that several radiologists gave different boxing coordinates for a same image. ","metadata":{}},{"cell_type":"markdown","source":"## Distribution of critical radiographic observations","metadata":{}},{"cell_type":"markdown","source":"There are 15 different radiographic observations which correspond to: \n\n0 - Aortic enlargement\n<br>1 - Atelectasis\n<br>2 - Calcification\n<br>3 - Cardiomegaly\n<br>4 - Consolidation\n<br>5 - ILD\n<br>6 - Infiltration\n<br>7 - Lung Opacity\n<br>8 - Nodule/Mass\n<br>9 - Other lesion\n<br>10 - Pleural effusion\n<br>11 - Pleural thickening\n<br>12 - Pneumothorax\n<br>13 - Pulmonary fibrosis\n<br>14 - No finding","metadata":{}},{"cell_type":"markdown","source":"Number of radiographic observations among all train images","metadata":{}},{"cell_type":"code","source":"def plot_distribution_classes(x_values, y_values, title):\n    \n    colors = ['rgb(26, 118, 255)',] * 15\n    colors[0] = 'lightslategray'\n\n    fig = go.Figure(data=[go.Bar(\n        x=x_values, \n        y=y_values,\n        text=y_values,\n        marker_color=colors\n    )])\n\n    fig.update_layout(height=600, width=900, title_text=title)\n    fig.update_xaxes(type=\"category\")\n\n    fig.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"indexes = train_dataframe.class_id.unique()\ncounts = train_dataframe.class_id.value_counts()\n\nsorted_dict = dict(zip(indexes, counts))\nsorted_dict = {k: v for k, v in sorted(sorted_dict.items(), key=lambda item: item[1], reverse = True)}\n\nx = list(sorted_dict.keys())\ny = list(sorted_dict.values())\n\nplot_distribution_classes(x, y, \n                          title=\"Distribution of radiographic observations\")","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The gray bar means 31818 observations concluded without any finding from radiologists","metadata":{}},{"cell_type":"code","source":"train_dataframe.info()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataframe.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Distribution of radiologist observations","metadata":{}},{"cell_type":"markdown","source":"Number of train images treated per radiologist","metadata":{}},{"cell_type":"code","source":"def plot_distribution_radiologist_obs(x_values, y_values, title):\n    \n    colors = ['lightslategray',] * 17\n    colors[0] = 'crimson'\n    colors[1] = 'crimson'\n    colors[2] = 'crimson'\n    \n    fig = go.Figure(data=[go.Bar(\n        x=x_values, \n        y=y_values,\n        text=y_values,\n        marker_color=colors\n    )])\n\n    fig.update_layout(height=600, width=900, title_text=title)\n    fig.update_xaxes(type=\"category\")\n\n    fig.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Show distribution of count of radio\nindexes = train_dataframe[['rad_id', 'image_id']].groupby(['rad_id']).agg(['count']).index\ncounts = train_dataframe[['rad_id', 'image_id']].groupby(['rad_id']).agg(['count']).values.ravel()\n\nsorted_dict = dict(zip(indexes, counts))\nsorted_dict = {k: v for k, v in sorted(sorted_dict.items(), key=lambda item: item[1], reverse = True)}\n\nx = list(sorted_dict.keys())\ny = list(sorted_dict.values())\n\nplot_distribution_radiologist_obs(x, y,\n                                  title = \"Distribution of radiologist observations\")","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------\n\n**<font size=\"2\"><a href=\"#summary\">Back to summary</a></font>**","metadata":{}},{"cell_type":"markdown","source":"# <div id=\"chap3\">3. Extracting meta information from .dicom files","metadata":{}},{"cell_type":"code","source":"ds = dcmread(os.path.join(PATH, 'train', '000434271f63a053c4128a0ba6352c7f.dicom'))\nds","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def infer_one_observation(file_path):\n    \n    ds = dcmread(file_path)\n    image_id = os.path.basename(file_path)\n        \n    observation_dict = {}\n    observation_dict['image_id'] = image_id.split(sep=\".\")[0]\n    \n    file_meta_keys = list(ds.file_meta._dict.keys())\n    remaining_meta_keys = list(ds._dict.keys())\n    \n    for key in file_meta_keys:\n        observation_dict[str(key)] = str(ds.file_meta[key].value)\n        \n    # Not taking into account pixel value\n    for key in remaining_meta_keys:\n        if key != (0x7fe0, 0x0010):\n            observation_dict[str(key)] = str(ds[key].value)\n        \n    return observation_dict","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mapper_dict = {'image_id':'image_id',\n               '(0002, 0000)':\"File Meta Information Group Length\",\n               '(0002, 0001)':\"File Meta Information Version\",\n               '(0002, 0002)':\"Media Storage SOP Class UID\",\n               '(0002, 0003)':\"Media Storage SOP Instance UID\",\n               '(0002, 0010)':\"Transfer Syntax UID\",\n               '(0002, 0012)':\"Implementation Class UID\",\n               '(0002, 0013)':\"Implementation Version Name\",\n               '(0002, 0016)':\"Source Application Entity Title\",\n               '(0010, 0040)':\"Patient's Sex\",\n               '(0010, 1010)':\"Patient's Age\",\n               '(0010, 1020)':\"Patient's Size\",\n               '(0010, 1030)':\"Patient's Weight\",\n               '(0028, 0002)':\"Samples per Pixel\",\n               '(0028, 0004)':\"Photometric Interpretation\",\n               '(0028, 0008)':\"Number of Frames\",\n               '(0028, 0010)':\"Rows\",\n               '(0028, 0011)':\"Columns\",\n               '(0028, 0030)':\"Pixel Spacing\",\n               '(0028, 0034)':\"Pixel Aspect Ratio\",\n               '(0028, 0100)':\"Bits Allocated\",\n               '(0028, 0101)':\"Bits Stored\",\n               '(0028, 0102)':\"High Bit\",\n               '(0028, 0103)':\"Pixel Representation\",\n               '(0028, 0106)':\"Smallest Image Pixel Value\",\n               '(0028, 0107)':\"Largest Image Pixel Value\",\n               '(0028, 1050)':\"Window Center\",\n               '(0028, 1051)':\"Window Width\",\n               '(0028, 1052)':\"Rescale Intercept\",\n               '(0028, 1053)':\"Rescale Slope\",\n               '(0028, 2110)':\"Lossy Image Compression\",\n               '(0028, 2112)':\"Lossy Image Compression Ratio\",\n               '(0028, 2114)':\"Lossy Image Compression Method\"\n              }","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def extract_meta_information(folder):\n    \n    folder_filenames = os.listdir(os.path.join(PATH, folder))\n    one_obs = infer_one_observation(os.path.join(PATH, folder, folder_filenames[0]))\n    metadata = pd.DataFrame(columns = one_obs.keys())\n\n    for filename in tqdm(folder_filenames[:20]):\n        one_obs = infer_one_observation(os.path.join(PATH, folder, filename))\n        metadata = metadata.append(one_obs, ignore_index=True)\n        \n    metadata.columns = metadata.columns.map(mapper_dict)\n    metadata.to_csv(f\"{folder}_dicom_metadata.csv\", index=False)\n    \n    return metadata","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Please note that this function only select first 20 elements of folder. For time execution purpose. If you want to rerun the whole extraction, please change this line:\n\n    for filename in tqdm(folder_filenames[:20]):\n\nto\n\n    for filename in tqdm(folder_filenames):\n","metadata":{}},{"cell_type":"code","source":"train_metadata = extract_meta_information(\"train\")\ntest_metadata = extract_meta_information(\"test\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There is a quicker way to extract metada, this way require using multiprocessing. I have 4 cores CPU. I'll create 4 Batches and perform the extraction in parallel on each core. As a result, I'll get 4 dataframes that I will simply have to concatenate.","metadata":{}},{"cell_type":"code","source":"train_filenames = os.listdir(os.path.join(PATH, \"train\"))\nBATCH_SIZES = list(map(lambda x:int(x/100), [0, 4000, 8000, 12000, 15000]))\n\none_obs_train = infer_one_observation(os.path.join(PATH, 'train', train_filenames[0]))\n\ndef extract_train_meta(BATCH):\n    \n    print(\"----- Train metadata extraction starting -----\")\n    \n    index_loop = 0\n    metadata = pd.DataFrame(columns = one_obs_train.keys())\n    \n    for filename in train_filenames[BATCH_SIZES[BATCH]:BATCH_SIZES[BATCH+1]]:\n        one_obs = infer_one_observation(os.path.join(PATH, 'train', filename))\n        metadata = metadata.append(one_obs_train, ignore_index=True)\n\n        if index_loop%10==0:\n            print(f\"{index_loop} train DICOM metadata successfully extracted\")\n        index_loop+=1\n    \n    metadata.columns = metadata.columns.map(mapper_dict)\n    metadata.to_csv(f\"batch_{BATCH}_dicom_train_metadata.csv\", index=False)\n    \n    print(\"----- Train metadata extraction fully completed -----\")\n    \n    return metadata","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_filenames = os.listdir(os.path.join(PATH, \"test\"))\nBATCH_SIZES = list(map(lambda x:int(x/10), [0, 750, 1500, 2250, 3000]))\n\none_obs_test = infer_one_observation(os.path.join(PATH, 'test', test_filenames[0]))\n\ndef extract_test_meta(BATCH):\n    print(\"----- Test metadata extraction starting -----\")\n    index_loop = 0\n    metadata = pd.DataFrame(columns = one_obs_test.keys())\n    \n    for filename in test_filenames[BATCH_SIZES[BATCH]:BATCH_SIZES[BATCH+1]]:\n        one_obs = infer_one_observation(os.path.join(PATH, 'test', filename))\n        metadata = metadata.append(one_obs_test, ignore_index=True)\n\n        if index_loop%10==0:\n            print(f\"{index_loop} test DICOM metadata successfully extracted\")\n        index_loop+=1\n    \n    metadata.columns = metadata.columns.map(mapper_dict)\n    metadata.to_csv(f\"batch_{BATCH}_dicom_test_metadata.csv\", index=False)\n    \n    print(\"----- Test metadata extraction fully completed -----\")\n    \n    return metadata","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pool = mp.Pool(mp.cpu_count())\npool.map(extract_train_meta, [i for i in range(4)])\npool.map(extract_test_meta, [i for i in range(4)])\npool.close()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Same as before, this function only select small batch sizes for time execution purpose. If you want to rerun the whole extraction, please change these lines:\n\n    BATCH_SIZES = list(map(lambda x:int(x/100), [0, 4000, 8000, 12000, 15000]))\n    \nand\n    \n    if index_loop%10==0:\n\nto\n\n    BATCH_SIZES = [0, 4000, 8000, 12000, 15000]\n\nand\n\n    if index_loop%1000==0:\n    \nfor train. And for the test, change these following lines:\n\n    BATCH_SIZES = list(map(lambda x:int(x/10), [0, 750, 1500, 2250, 3000]))\n\nand\n\n    if index_loop%10==0:\n\nto\n\n    BATCH_SIZES = [0, 750, 1500, 2250, 3000]\n\nand\n\n    if index_loop%100==0:","metadata":{}},{"cell_type":"markdown","source":"--------\n\n**<font size=\"2\"><a href=\"#summary\">Back to summary</a></font>**","metadata":{}},{"cell_type":"markdown","source":"# <div id=\"chap4\">4. Preprocessing meta information","metadata":{}},{"cell_type":"markdown","source":"Let's consider we extracted all metadata, you can find the data here: https://www.kaggle.com/bryanb/vinbigdata-chestxray-metadata\n\nI chose to keep only few information: sex, age, height and weight","metadata":{}},{"cell_type":"code","source":"# Load full metadata set\ntrain_metadata = pd.read_csv(\"../input/vinbigdata-chestxray-metadata/train_dicom_metadata.csv\")\ntest_metadata = pd.read_csv(\"../input/vinbigdata-chestxray-metadata/test_dicom_metadata.csv\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Keep some columns only\ntrain_metadata_filtered = train_metadata[[\"Patient's Sex\", \"Patient's Age\", \"Patient's Size\", \"Patient's Weight\"]]\ntest_metadata_filtered = test_metadata[[\"Patient's Sex\", \"Patient's Age\", \"Patient's Size\", \"Patient's Weight\"]]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_metadata_filtered[\"Patient's Size\"].value_counts())\nprint(train_metadata_filtered[\"Patient's Weight\"].value_counts())\n\nprint(test_metadata_filtered[\"Patient's Size\"].value_counts())\nprint(test_metadata_filtered[\"Patient's Weight\"].value_counts())\n\ntrain_metadata_filtered = train_metadata_filtered.drop([\"Patient's Size\", \"Patient's Weight\"], axis=1)\ntest_metadata_filtered = test_metadata_filtered.drop([\"Patient's Size\", \"Patient's Weight\"], axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_first_el(row):\n    resu = 'NA'\n    if len(str(row))>5:\n        resu = re.search(r\"(?<=\\[)(.*?)(?=\\,)\", row).group()\n    return resu","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_metadata_filtered[\"Patient's Sex\"] = train_metadata_filtered[\"Patient's Sex\"].fillna(\"NA\")\ntrain_metadata_filtered.loc[train_metadata_filtered[\"Patient's Sex\"]==\"O\"] = np.nan\n\ntrain_metadata_filtered[\"Patient's Age\"] = train_metadata_filtered[\"Patient's Age\"].fillna(\"0\")\ntrain_metadata_filtered[\"Patient's Age\"] = train_metadata_filtered[\"Patient's Age\"].apply(lambda x:re.search(r\"\\d*\", str(x)).group())\ntrain_metadata_filtered.loc[train_metadata_filtered[\"Patient's Age\"]== '']= np.nan\ntrain_metadata_filtered[\"Patient's Age\"] = train_metadata_filtered[\"Patient's Age\"].astype(float)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_metadata_filtered[\"Patient's Sex\"] = test_metadata_filtered[\"Patient's Sex\"].fillna(\"NA\")\ntest_metadata_filtered.loc[test_metadata_filtered[\"Patient's Sex\"]==\"O\"] = np.nan\n\ntest_metadata_filtered[\"Patient's Age\"] = test_metadata_filtered[\"Patient's Age\"].fillna(\"0\")\ntest_metadata_filtered[\"Patient's Age\"] = test_metadata_filtered[\"Patient's Age\"].apply(lambda x:re.search(r\"\\d*\", str(x)).group())\ntest_metadata_filtered.loc[test_metadata_filtered[\"Patient's Age\"]== '']= np.nan\ntest_metadata_filtered[\"Patient's Age\"] = test_metadata_filtered[\"Patient's Age\"].astype(float)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_metadata_filtered.to_csv(\"train_dicom_metadata_filtered.csv\", index=False)\ntest_metadata_filtered.to_csv(\"test_dicom_metadata_filtered.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_metadata_age = train_metadata_filtered.loc[(train_metadata_filtered[\"Patient's Age\"] > 0) & \n                                                 (train_metadata_filtered[\"Patient's Age\"] < 100), :]\n\nfig = px.histogram(train_metadata_age, x=\"Patient's Age\",\n                   marginal=\"box\",\n                   hover_data=train_metadata_age.columns)\n\nfig.update_layout(\n    title=\"Age distribution (train)\")\n\nfig.show()\n\ndel(train_metadata_age)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_metadata_counts = list(train_metadata_filtered.loc[train_metadata_filtered[\"Patient's Sex\"] != \"NA\", \"Patient's Sex\"].value_counts())\ntrain_metadata_labels = list(train_metadata_filtered.loc[train_metadata_filtered[\"Patient's Sex\"] != \"NA\", \"Patient's Sex\"].value_counts().index)\n\nfig = go.Figure(data=[go.Pie(labels=train_metadata_labels, \n                             values=train_metadata_counts, \n                             hole=.3,\n                             title_text=\"Sex distribution (train)\")])\nfig.show()\n\ndel(train_metadata_counts, train_metadata_labels)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = train_metadata_filtered.loc[(train_metadata_filtered[\"Patient's Sex\"] != \"NA\") &\n                                   (train_metadata_filtered[\"Patient's Age\"] > 0) &\n                                   (train_metadata_filtered[\"Patient's Age\"] < 100), :]\n\nfig = px.histogram(data, \n                   x=\"Patient's Age\", \n                   color=\"Patient's Sex\", \n                   marginal=\"box\",\n                   hover_data=data.columns,\n                   histnorm = \"probability\")\n\nfig.update_layout(\n    title=\"Age distribution by sex (train)\")\n\nfig.show()\n\ndel(data)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------\n\n**<font size=\"2\"><a href=\"#summary\">Back to summary</a></font>**","metadata":{}},{"cell_type":"markdown","source":"# <div id=\"chap5\">5. Fusion of boxings","metadata":{}},{"cell_type":"code","source":"train_dataframe.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def fusing_boxes(dataframe, class_id):\n    # filter on class_id\n    filtered_dataframe = dataframe.loc[dataframe.class_id == class_id,\n                                       ['image_id','x_min','y_min','x_max','y_max']]\n    # aggregate on image_id to average radiologists's estimations\n    return filtered_dataframe.groupby(['image_id']).mean()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot deduplicated class counts\n\nindexes = train_dataframe.class_id.unique()\ncounts = [fusing_boxes(train_dataframe, class_id).shape[0] for class_id in range(14)]\n\nsorted_dict = dict(zip(indexes, counts))\nsorted_dict = {k: v for k, v in sorted(sorted_dict.items(), key=lambda item: item[1], reverse = True)}\n\nx = list(sorted_dict.keys())\ny = list(sorted_dict.values())\n\nplot_distribution_classes(x, y, \n                          title=\"Deduplicated distribution of radiographic observations\")","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------\n\n**<font size=\"2\"><a href=\"#summary\">Back to summary</a></font>**","metadata":{}},{"cell_type":"markdown","source":"# <div id=\"chap6\">6. Presentation of each radiographic observations","metadata":{}},{"cell_type":"code","source":"def get_rectangle_parameter(dataframe, index):\n    \n    \"Adapt coordinates of bounding box for patch.Rectangle function\"\n    \n    x_min = dataframe.loc[index, 'x_min']\n    y_min = dataframe.loc[index, 'y_min']\n    x_max = dataframe.loc[index, 'x_max']\n    y_max = dataframe.loc[index, 'y_max']\n    \n    anchor_point = (x_min, y_min)\n    height = y_max - y_min\n    width = x_max - x_min\n    \n    return anchor_point, height, width","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def select_9_from_each(dataframe):\n    \n    \"For each class, returns 9 indexes and image paths\"\n    \n    # Initialize dictionaries\n    class_id_index_examples, class_id_image_examples = {}, {}\n    image_ids_train_dataframe = list(train_dataframe.image_id)\n    \n    # Loop over different classes\n    for class_id in range(14):\n        fusing_boxes_dataframe = fusing_boxes(dataframe, class_id).sample(n=9)\n        # image_id\n        fusing_box_indexes = fusing_boxes_dataframe.index\n        # Infer indexes\n        class_id_index_examples[str(class_id)] = [image_ids_train_dataframe.index(fusing_box_indexes[cid]) for cid in range(9)]\n        # Infer image paths\n        class_id_image_examples[str(class_id)] = fusing_box_indexes\n        \n    return class_id_index_examples, class_id_image_examples\n\nclass_id_index_examples, class_id_image_examples = select_9_from_each(train_dataframe)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_images(class_id, graph_indexes = np.arange(9)):\n    \n    # Get files\n    files_index = class_id_index_examples[str(class_id)]\n    files_list = class_id_image_examples[str(class_id)]\n    \n    # define subplot\n    fig, axs = plt.subplots(3,3, figsize=(12,12))\n    for graph_index in graph_indexes:\n        \n        full_filename = files_list[graph_index]+'.dicom'\n        ds = dcmread(os.path.join(PATH, \n                                  'train',\n                                  full_filename))\n        \n\n#         axs[graph_index%3, (graph_index)//3].set_title('Label: %s \\n'%class_id,\n#                   fontsize=18)\n        axs[graph_index%3, (graph_index)//3].imshow(ds.pixel_array, cmap=plt.get_cmap('gray'))\n                  \n        if str(class_id) != '14':\n            \n            # Add rectangle\n            anchor_point, height, width = get_rectangle_parameter(train_dataframe, \n                                                                  files_index[graph_index])\n            rect = Rectangle(anchor_point, \n                                     height, \n                                     width, \n                                     edgecolor='r', \n                                     facecolor=\"none\")\n            axs[graph_index%3, (graph_index)//3].add_patch(rect)\n                     \n    # the bottom of the subplots of the figure\n    plt.subplots_adjust(bottom = 0.001)\n    plt.subplots_adjust(top = 0.99)\n    \n    # show the figure\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I am not a doctor and cannot talk about each of these class fluently, hence I copy-pasted some accurate definitions from trusted sources. The main goal of this section is to share clear explanations regarding each class with plotted images to illustrate.","metadata":{}},{"cell_type":"markdown","source":"## Aortic enlargement","metadata":{}},{"cell_type":"markdown","source":"An aortic aneurysm is an enlargement (dilatation) of the aorta to greater than 1.5 times normal size. They usually cause no symptoms except when ruptured. Occasionally, there may be abdominal, back, or leg pain.\n\nThey are most commonly located in the abdominal aorta, but can also be located in the thoracic aorta. Aortic aneurysms cause weakness in the wall of the aorta and increase the risk of aortic rupture. When rupture occurs, massive internal bleeding results and, unless treated immediately, shock and death can occur.","metadata":{}},{"cell_type":"code","source":"display_images('0')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Atelectasis","metadata":{}},{"cell_type":"markdown","source":"Atelectasis (at-uh-LEK-tuh-sis) is a complete or partial collapse of the entire lung or area (lobe) of the lung. It occurs when the tiny air sacs (alveoli) within the lung become deflated or possibly filled with alveolar fluid.\n\nAtelectasis is one of the most common breathing (respiratory) complications after surgery. It's also a possible complication of other respiratory problems, including cystic fibrosis, lung tumors, chest injuries, fluid in the lung and respiratory weakness. You may develop atelectasis if you breathe in a foreign object.\n\nAtelectasis can make breathing difficult, particularly if you already have lung disease. Treatment depends on the cause and severity of the collapse.","metadata":{}},{"cell_type":"code","source":"display_images('1')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Calcification","metadata":{}},{"cell_type":"markdown","source":"Calcification is the accumulation of calcium salts in a body tissue. It normally occurs in the formation of bone, but calcium can be deposited abnormally in soft tissue, causing it to harden. Calcifications may be classified on whether there is mineral balance or not, and the location of the calcification.","metadata":{}},{"cell_type":"code","source":"display_images('2')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Cardiomegaly","metadata":{}},{"cell_type":"markdown","source":"Cardiomegaly is an enlarged heart. It is not a disease, but a sign of another condition. Less severe forms of cardiomegaly are referred to as mild cardiomegaly. As mild cardiomegaly does not always cause symptoms, many people with a slightly enlarged heart are unaware of the problem.","metadata":{}},{"cell_type":"code","source":"display_images('3')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Consolidation","metadata":{}},{"cell_type":"markdown","source":"A pulmonary consolidation is a region of normally compressible lung tissue that has filled with liquid instead of air. The condition is marked by induration (swelling or hardening of normally soft tissue) of a normally aerated lung. It is considered a radiologic sign.","metadata":{}},{"cell_type":"code","source":"display_images('4')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## ILD","metadata":{}},{"cell_type":"markdown","source":"Interstitial lung disease (ILD) is a group of many lung conditions. All interstitial lung diseases affect the interstitium, a part of your lungs. The interstitium is a lace-like network of tissue that goes throughout both lungs. It supports your lungs' tiny air sacs, called alveoli.","metadata":{}},{"cell_type":"code","source":"display_images('5')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Infiltration","metadata":{}},{"cell_type":"markdown","source":"As part of a disease process, infiltration is sometimes used to define the invasion of cancer cells into the underlying matrix or the blood vessels. Similarly, the term may describe the deposition of amyloid protein. During leukocyte extravasation, white blood cells move in response to cytokines from within the blood, into the diseased or infected tissues, usually in the same direction as a chemical gradient,[1] in a process called chemotaxis. The presence of lymphocytes in tissue in greater than normal numbers is likewise called infiltration.\n\nAs part of medical intervention, local anaesthetics may be injected at more than one point so as to infiltrate an area prior to a surgical procedure. However, the term may also apply to unintended iatrogenic leakage of fluids from phlebotomy or intravenous drug delivery procedures, a process also known as extravasation or \"tissuing\".","metadata":{}},{"cell_type":"code","source":"display_images('6')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Lung Opacity","metadata":{}},{"cell_type":"markdown","source":"Pulmonary opacification represents the result of a decrease in the ratio of gas to soft tissue (blood, lung parenchyma and stroma) in the lung. When reviewing an area of increased attenuation (opacification) on a chest radiograph or CT it is vital to determine where the opacification is. The patterns can broadly be divided into airspace opacification, lines and dots.","metadata":{}},{"cell_type":"code","source":"display_images('7')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Nodule/Mass","metadata":{}},{"cell_type":"markdown","source":"A lung nodule or pulmonary nodule is a relatively small focal density in the lung. A solitary pulmonary nodule (SPN) or coin lesion, is a mass in the lung smaller than 3 centimeters in diameter. There may also be multiple nodules.\n\nOne or more lung nodules can be an incidental finding found in up to 0.2% of chest X-rays and around 1% of CT scans.\n\nThe nodule most commonly represents a benign tumor such as a granuloma or hamartoma, but in around 20% of cases it represents a malignant cancer, especially in older adults and smokers. Conversely, 10 to 20% of patients with lung cancer are diagnosed in this way. If the patient has a history of smoking or the nodule is growing, the possibility of cancer may need to be excluded through further radiological studies and interventions, possibly including surgical resection. The prognosis depends on the underlying condition.","metadata":{}},{"cell_type":"code","source":"display_images('8')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Other lesion","metadata":{}},{"cell_type":"code","source":"display_images('9')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Pleural effusion","metadata":{}},{"cell_type":"markdown","source":"Pleural effusion, sometimes referred to as “water on the lungs,” is the build-up of excess fluid between the layers of the pleura outside the lungs. The pleura are thin membranes that line the lungs and the inside of the chest cavity and act to lubricate and facilitate breathing. Normally, a small amount of fluid is present in the pleura.","metadata":{}},{"cell_type":"code","source":"display_images('10')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Pleural thickening","metadata":{}},{"cell_type":"markdown","source":"What Is Pleural Thickening? Pleural thickening develops when scar tissue thickens the delicate membrane lining the lungs (the pleura). Pleural thickening can develop following asbestos exposure or other conditions, such as infection. It may be a symptom of a more severe diagnosis such as malignant pleural mesothelioma.","metadata":{}},{"cell_type":"code","source":"display_images('11')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Pneumothorax","metadata":{}},{"cell_type":"markdown","source":"A pneumothorax (noo-moe-THOR-aks) is a collapsed lung. A pneumothorax occurs when air leaks into the space between your lung and chest wall. This air pushes on the outside of your lung and makes it collapse. Pneumothorax can be a complete lung collapse or a collapse of only a portion of the lung.","metadata":{}},{"cell_type":"code","source":"display_images('12')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Pulmonary fibrosis","metadata":{}},{"cell_type":"markdown","source":"Pulmonary fibrosis is a lung disease that occurs when lung tissue becomes damaged and scarred. This thickened, stiff tissue makes it more difficult for your lungs to work properly. As pulmonary fibrosis worsens, you become progressively more short of breath.\n\nThe scarring associated with pulmonary fibrosis can be caused by a multitude of factors. But in most cases, doctors can't pinpoint what's causing the problem. When a cause can't be found, the condition is termed idiopathic pulmonary fibrosis.\n\nThe lung damage caused by pulmonary fibrosis can't be repaired, but medications and therapies can sometimes help ease symptoms and improve quality of life. For some people, a lung transplant might be appropriate.","metadata":{}},{"cell_type":"code","source":"display_images('13')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------\n\n**<font size=\"2\"><a href=\"#summary\">Back to summary</a></font>**","metadata":{}},{"cell_type":"markdown","source":"# References\n\n#### DICOM files\n* <a href=\"https://pydicom.github.io/pydicom/stable/auto_examples/input_output/plot_read_dicom.html\">Deal with .dicom files</a>\n* <a href=\"https://dicom.innolitics.com/ciods/rt-plan/patient-study/00101020\">Matching DICOM metadata</a>\n\n#### Abnormality classes\n* <a href=\"https://en.wikipedia.org/wiki/Aortic_aneurysm\">Aortic aneurysm - Wikipedia</a>\n*  <a href=\"https://www.mayoclinic.org/diseases-conditions/atelectasis/symptoms-causes/syc-20369684#:~:text=Atelectasis%20(at%2Duh%2DLEK,(respiratory)%20complications%20after%20surgery\">Atelectasis - Mayoclinic</a>\n*  <a href=\"https://en.wikipedia.org/wiki/Calcification#:~:text=Calcification%20is%20the%20accumulation%20of,the%20location%20of%20the%20calcification\">Calcification - Wikipedia</a>\n*  <a href=\"https://www.medicalnewstoday.com/articles/320591#:~:text=Cardiomegaly%20is%20an%20enlarged%20heart,are%20unaware%20of%20the%20problem\">Cardiomegaly - Medicalnewstoday</a>\n*  <a href=\"https://en.wikipedia.org/wiki/Pulmonary_consolidation#:~:text=A%20pulmonary%20consolidation%20is%20a,is%20considered%20a%20radiologic%20sign\">Pulmonary consolidation - Wikipedia</a>\n*  <a href=\"https://www.webmd.com/lung/interstitial-lung-disease#:~:text=Interstitial%20lung%20disease%20(ILD)%20is,tiny%20air%20sacs%2C%20called%20alveoli\">ILD - Webmd</a>\n*  <a href=\"https://en.wikipedia.org/wiki/Infiltration_(medical)\">Infiltration - Wikipedia</a>\n*  <a href=\"https://radiopaedia.org/articles/pulmonary-opacification#:~:text=Pulmonary%20opacification%20represents%20the%20result,determine%20where%20the%20opacification%20is\">Lung Opacity - Radiopaedia</a>\n*  <a href=\"https://en.wikipedia.org/wiki/Lung_nodule\">Nodule - Wikipedia</a>\n*  <a href=\"https://my.clevelandclinic.org/health/diseases/17373-pleural-effusion-causes-signs--treatment#:~:text=Pleural%20effusion%2C%20sometimes%20referred%20to,to%20lubricate%20and%20facilitate%20breathing\">Pleural effusion - Clevelandclinic</a>\n*  <a href=\"https://www.mesothelioma.com/asbestos-cancer/pleural-thickening/#:~:text=Is%20Pleural%20Thickening%3F-,What%20Is%20Pleural%20Thickening%3F,such%20as%20malignant%20pleural%20mesothelioma\">Pleural thickening - Mesothelioma</a>\n*  <a href=\"https://www.mayoclinic.org/diseases-conditions/pneumothorax/symptoms-causes/syc-20350367#:~:text=A%20pneumothorax%20(noo%2Dmoe%2D,a%20portion%20of%20the%20lung\">Pneumothorax - Mayoclinic</a>\n*  <a href=\"https://www.mayoclinic.org/diseases-conditions/pulmonary-fibrosis/symptoms-causes/syc-20353690#:~:text=Pulmonary%20fibrosis%20is%20a%20lung,progressively%20more%20short%20of%20breath\">Pulmonary Fibrosis - Mayoclinic</a>","metadata":{}},{"cell_type":"markdown","source":"<hr>\n<div align='justify'><font color=\"#353B47\" size=\"4\">Thank you for taking the time to read this notebook. I hope that I was able to answer your questions or your curiosity and that it was quite understandable. <u>any constructive comments are welcome</u>. They help me progress and motivate me to share better quality content. I am above all a passionate person who tries to advance my knowledge but also that of others. If you liked it, feel free to <u>upvote and share my work.</u> </font></div>\n<br>\n<div align='center'><font color=\"#353B47\" size=\"3\">Thank you and may passion guide you.</font></div>","metadata":{}}]}