{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":10338,"databundleVersionId":862042,"sourceType":"competition"},{"sourceId":6086,"sourceType":"modelInstanceVersion","modelInstanceId":4624,"modelId":2800},{"sourceId":6088,"sourceType":"modelInstanceVersion","modelInstanceId":4626,"modelId":2800},{"sourceId":6111,"sourceType":"modelInstanceVersion","modelInstanceId":4620,"modelId":2799},{"sourceId":6132,"sourceType":"modelInstanceVersion","modelInstanceId":4583,"modelId":2795}],"dockerImageVersionId":31011,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 0 Preparation","metadata":{}},{"cell_type":"markdown","source":"## import library","metadata":{}},{"cell_type":"markdown","source":"It is used to directly display the graphs generated by Matplotlib in the Notebook without the need to use plt.show().\nThe magic command of % cannot be accompanied by annotations","metadata":{}},{"cell_type":"code","source":"%matplotlib inline \nimport glob, pylab, pandas as pd\nimport pydicom, numpy as np\nimport csv, os, random\n\nimport matplotlib.pyplot as plt\n\nimport matplotlib.patches as patches\nfrom matplotlib.patches import Rectangle\n\nfrom skimage import io, measure\nfrom skimage.transform import resize\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers, Model\n\nimport keras_cv.models","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-11T03:43:03.915924Z","iopub.execute_input":"2025-05-11T03:43:03.916484Z","iopub.status.idle":"2025-05-11T03:43:25.07059Z","shell.execute_reply.started":"2025-05-11T03:43:03.916462Z","shell.execute_reply":"2025-05-11T03:43:25.069791Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Preparations such as path definition","metadata":{}},{"cell_type":"code","source":"!ls ../input/rsna-pneumonia-detection-challenge/\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:45.512466Z","iopub.execute_input":"2025-05-07T06:54:45.513137Z","iopub.status.idle":"2025-05-07T06:54:45.659504Z","shell.execute_reply.started":"2025-05-07T06:54:45.513107Z","shell.execute_reply":"2025-05-07T06:54:45.65872Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"det_class_path = '../input/rsna-pneumonia-detection-challenge/stage_2_detailed_class_info.csv'\nbbox_path = '../input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv'\ndicom_dir = '../input/rsna-pneumonia-detection-challenge/stage_2_train_images/'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-11T03:43:59.536325Z","iopub.execute_input":"2025-05-11T03:43:59.537064Z","iopub.status.idle":"2025-05-11T03:43:59.541076Z","shell.execute_reply.started":"2025-05-11T03:43:59.537035Z","shell.execute_reply":"2025-05-11T03:43:59.540301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3\npneumonia_locations = {}\nwith open(os.path.join(bbox_path), mode='r') as infile:\n    reader = csv.reader(infile)\n    next(reader, None)\n    for rows in reader:\n        filename = rows[0]\n        location = rows[1:5]\n        pneumonia = rows[5]\n        if pneumonia == '1':\n            location = [int(float(i)) for i in location]\n            if filename in pneumonia_locations:\n                pneumonia_locations[filename].append(location)\n            else:\n                pneumonia_locations[filename] = [location]\n\n\n# 3 Load file names\nfilenames = os.listdir(dicom_dir)\nrandom.shuffle(filenames)\n\n# Split into training and validation filenames\nn_valid_samples = 2560\ntrain_filenames = filenames[n_valid_samples:]\nvalid_filenames = filenames[:n_valid_samples]\nprint('Number of training samples:', len(train_filenames))\nprint('Number of validation samples:', len(valid_filenames))\nn_train_samples = len(filenames) - n_valid_samples","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:45.666387Z","iopub.execute_input":"2025-05-07T06:54:45.666686Z","iopub.status.idle":"2025-05-07T06:54:46.54153Z","shell.execute_reply.started":"2025-05-07T06:54:45.666662Z","shell.execute_reply":"2025-05-07T06:54:46.54086Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# sample_df\ndet_class_path = '../input/rsna-pneumonia-detection-challenge/stage_2_detailed_class_info.csv'\nbbox_path = '../input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv'\ndicom_dir = '../input/rsna-pneumonia-detection-challenge/stage_2_train_images/'\nbbox_df = pd.read_csv(bbox_path)\ndet_class_df = pd.read_csv(det_class_path)\n\ncomb_bbox_df = pd.concat([bbox_df, det_class_df.drop('patientId', axis=1)], axis=1)  # Merge after dropping 'patientId' from det_class_df\nprint(comb_bbox_df.shape[0], 'combined cases') \ncomb_bbox_df.sample(3)  \nbox_df = comb_bbox_df.groupby('patientId').size().reset_index(name='boxes')  # Calculate the number of boxes for each patient in a new column 'boxes'\ncomb_box_df = pd.merge(comb_bbox_df, box_df, on='patientId')  # Merge original data with box count based on 'patientId'\nbox_df.groupby('boxes').size().reset_index(name='patients')  # Count by classification\ncomb_bbox_df.groupby(['class', 'Target']).size().reset_index(name='Patient Count')  # Group count by target and class\n\n# Store path list\nimage_df = pd.DataFrame({'path': glob.glob(os.path.join(dicom_dir, '*.dcm'))})  # Using glob to find files\nimage_df['patientId'] = image_df['path'].map(lambda x: os.path.splitext(os.path.basename(x))[0])\nprint(image_df.shape[0], 'images found')\nimg_pat_ids = set(image_df['patientId'].values.tolist())  # Extract patient IDs and store as a set\nbox_pat_ids = set(comb_box_df['patientId'].values.tolist())\n\nimage_bbox_df = pd.merge(comb_box_df, image_df, on='patientId', how='left').sort_values('patientId')  # Add paths\n\nDCM_TAG_LIST = ['PatientAge', 'BodyPartExamined', 'ViewPosition', 'PatientSex']\ndef get_tags(in_path):\n    c_dicom = pydicom.dcmread(in_path, stop_before_pixels=False)\n    tag_dict = {c_tag: getattr(c_dicom, c_tag, '') for c_tag in DCM_TAG_LIST}\n    tag_dict['path'] = in_path\n    return pd.Series(tag_dict)\n\nimage_meta_df = image_df.head(1000).apply(lambda x: get_tags(x['path']), axis=1)\nimage_meta_df['PatientAge'] = image_meta_df['PatientAge'].map(int)\nsample_df = image_bbox_df.copy()\nsample_df = sample_df[sample_df['path'].isin(image_meta_df['path'])]\nprint(sample_df.isnull().sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:46.542271Z","iopub.execute_input":"2025-05-07T06:54:46.542516Z","iopub.status.idle":"2025-05-07T06:54:55.646713Z","shell.execute_reply.started":"2025-05-07T06:54:46.542499Z","shell.execute_reply":"2025-05-07T06:54:55.645789Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1. table","metadata":{}},{"cell_type":"markdown","source":"## 1.1 class.csv","metadata":{}},{"cell_type":"code","source":"det_class_df = pd.read_csv(det_class_path)\nprint(det_class_df.iloc[0])\nprint(det_class_df.shape[0], 'class infos loaded') # outputs the number of lines loaded\nprint(det_class_df['patientId'].value_counts().shape[0], 'patient cases') # Outputs the number of unique patient cases\n\ndet_class_df.groupby('class').size().plot.bar() # Group by category and draw a bar chart\ndet_class_df.sample(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-11T03:44:04.525859Z","iopub.execute_input":"2025-05-11T03:44:04.526161Z","iopub.status.idle":"2025-05-11T03:44:04.841414Z","shell.execute_reply.started":"2025-05-11T03:44:04.526139Z","shell.execute_reply":"2025-05-11T03:44:04.840811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\n\n# Load Data\ndet_class_df = pd.read_csv(det_class_path)\n\n# Output a DataFrame for category counts\nclass_counts_df = det_class_df['class'].value_counts().reset_index()\nclass_counts_df.columns = ['class', 'count']\nprint(class_counts_df) # Outputs statistical information in the form of DataFrame\n\n# Draw a bar chart\nclass_counts = det_class_df['class'].value_counts()\nax = class_counts.plot(kind='bar', width=0.5)\n\n# Set the direction and spacing of the horizontal coordinate labels\nplt.xticks(rotation=0) # Rotate the tags to 0 degrees to keep them horizontal\nplt.subplots_adjust(bottom=0.3) # Adjust the bottom spacing to provide more space\n\n# Set tags and titles\nplt.xlabel('Class')\nplt.ylabel('Count')\nplt.title('Distribution of Classes')\nplt.show()\n\nThree samples were randomly sampled\nprint(det_class_df.sample(3))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-11T03:47:57.878602Z","iopub.execute_input":"2025-05-11T03:47:57.87912Z","iopub.status.idle":"2025-05-11T03:47:58.032597Z","shell.execute_reply.started":"2025-05-11T03:47:57.879098Z","shell.execute_reply":"2025-05-11T03:47:58.031995Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# View detailed label descriptions\nsummary = {}  # Initialize an empty dictionary to store counts for each class\nfor n, row in det_class_df.iterrows():  # Iterate over each row in the DataFrame\n    if row['class'] not in summary:  # If the class is not in the dictionary\n        summary[row['class']] = 0  # Initialize the count for that class to 0\n    summary[row['class']] += 1  # Increment the count for that class\n\nprint(summary)  # Output the count for each class","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:55.941561Z","iopub.execute_input":"2025-05-07T06:54:55.941842Z","iopub.status.idle":"2025-05-07T06:54:56.998645Z","shell.execute_reply.started":"2025-05-07T06:54:55.941817Z","shell.execute_reply":"2025-05-07T06:54:56.997889Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 1.2 label.csv","metadata":{}},{"cell_type":"code","source":"bbox_df = pd.read_csv(bbox_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:56.999441Z","iopub.execute_input":"2025-05-07T06:54:56.999731Z","iopub.status.idle":"2025-05-07T06:54:57.033624Z","shell.execute_reply.started":"2025-05-07T06:54:56.999701Z","shell.execute_reply":"2025-05-07T06:54:57.03308Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"First, take a look at who and what the information in the table is; It talks about the information of the block diagram\nbbox_df = pd.read_csv(bbox_path)\nprint(bbox_df.iloc[0])\nprint(bbox_df.shape[0], 'boxes loaded')\nprint(bbox_df['patientId'].value_counts().shape[0], 'patient cases')\n\nbbox_df.sample(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:57.036306Z","iopub.execute_input":"2025-05-07T06:54:57.036489Z","iopub.status.idle":"2025-05-07T06:54:57.094712Z","shell.execute_reply.started":"2025-05-07T06:54:57.036476Z","shell.execute_reply":"2025-05-07T06:54:57.094021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3\npneumonia_locations = {}\nwith open(os.path.join(bbox_path), mode='r') as infile:\n    reader = csv.reader(infile)\n    next(reader, None)\n    for rows in reader:\n        filename = rows[0]\n        location = rows[1:5]\n        pneumonia = rows[5]\n        if pneumonia == '1':\n            location = [int(float(i)) for i in location]\n            if filename in pneumonia_locations:\n                pneumonia_locations[filename].append(location)\n            else:\n                pneumonia_locations[filename] = [location]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:57.095441Z","iopub.execute_input":"2025-05-07T06:54:57.095703Z","iopub.status.idle":"2025-05-07T06:54:57.1521Z","shell.execute_reply.started":"2025-05-07T06:54:57.095679Z","shell.execute_reply":"2025-05-07T06:54:57.151356Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 1.3 merge tables","metadata":{}},{"cell_type":"markdown","source":"The first merge: Merge bbox_df and det_class_df to obtain the category and target information of each box.\n\nThe second merge: comb_box_df contains the information of each box and the number of boxes for each patient, which can analyze the patient's condition more accurately.\n\nThe third statistics: Count the number of patients corresponding to each box category.","metadata":{}},{"cell_type":"code","source":"Connect the two datasets and then obtain the category and target information of each region\n# comb_bbox_df = pd.merge(bbox_df, det_class_df, how='inner', on='patientId') # After merging using inner joins, it may result in an excessive number of generated boxes. Especially when there are duplicate patientids in two dataframes.\ncomb_bbox_df = pd.concat([bbox_df,det_class_df.drop('patientId', axis=1)],  axis=1) # Delete the 'patientId' column in det_class_df and then merge it\nprint(comb_bbox_df.shape[0], 'combined cases')\ncomb_bbox_df.sample(3)\n\nbox_df = comb_bbox_df.groupby('patientId').size().reset_index(name='boxes') # Create a new column 'boxes' to calculate the number of boxes for each patient\ncomb_box_df = pd.merge(comb_bbox_df, box_df, on='patientId') # Merge the original data and the number of boxes together based on 'patientId'\n\nBox_df.group by('boxes').size().reset_index(name='patients') # Categorization count\ncomb_bbox_df.groupby(['class', 'Target']).size().reset_index(name='Patient Count') # Count by target and category grouping","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:57.152894Z","iopub.execute_input":"2025-05-07T06:54:57.15314Z","iopub.status.idle":"2025-05-07T06:54:57.205702Z","shell.execute_reply.started":"2025-05-07T06:54:57.153124Z","shell.execute_reply":"2025-05-07T06:54:57.205177Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. dcm image","metadata":{}},{"cell_type":"markdown","source":"#### 2.0.1 single simage analysis","metadata":{}},{"cell_type":"code","source":"pip show pydicom","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:57.206543Z","iopub.execute_input":"2025-05-07T06:54:57.206804Z","iopub.status.idle":"2025-05-07T06:54:59.721826Z","shell.execute_reply.started":"2025-05-07T06:54:57.206787Z","shell.execute_reply":"2025-05-07T06:54:59.720881Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patientId = bbox_df['patientId'][0]\ndcm_file = f'{dicom_dir}{patientId}.dcm' # Format the path using f-String\n\ndcm_data = pydicom.dcmread(dcm_file) # pydicom 3.0 and below versions use read_file\nprint(dcm_data)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:59.723116Z","iopub.execute_input":"2025-05-07T06:54:59.723419Z","iopub.status.idle":"2025-05-07T06:54:59.739738Z","shell.execute_reply.started":"2025-05-07T06:54:59.723386Z","shell.execute_reply":"2025-05-07T06:54:59.739099Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Loading Images: It is necessary to determine the data type of the image, the data type of the pixel values, and the shape of the array\nim = dcm_data.pixel_array\nprint(type(im))\nprint(im.dtype)\nprint(im.shape)\n\npylab.imshow(im, cmap=pylab.cm.gist_gray)\npylab.axis('off')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:59.740428Z","iopub.execute_input":"2025-05-07T06:54:59.740596Z","iopub.status.idle":"2025-05-07T06:54:59.949559Z","shell.execute_reply.started":"2025-05-07T06:54:59.740582Z","shell.execute_reply":"2025-05-07T06:54:59.948834Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### 多图分析","metadata":{}},{"cell_type":"code","source":"# The list of stored paths is only the paths\nimage_df = pd.DataFrame({'path': glob.glob(os.path.join(dicom_dir, '*.dcm'))}) # The old version is glob, and the new version is glob.glob()\nimage_df['patientId'] = image_df['path'].map(lambda x: os.path.splitext(os.path.basename(x))[0])\nprint(image_df.shape[0], 'images found')\n\nimg_pat_ids = set(image_df['patientId'].values.tolist()) # Extract the patient ID and store it as a collection\nbox_pat_ids = set(comb_box_df['patientId'].values.tolist())\n\n# Check whether the patient ids are consistent\nassert img_pat_ids.union(box_pat_ids) == img_pat_ids, \"Patient IDs should be the same\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:54:59.950431Z","iopub.execute_input":"2025-05-07T06:54:59.950757Z","iopub.status.idle":"2025-05-07T06:55:00.051295Z","shell.execute_reply.started":"2025-05-07T06:54:59.950728Z","shell.execute_reply":"2025-05-07T06:55:00.050695Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Integrate the information and images of the box chart\nimage_bbox_df = pd.merge(comb_box_df, image_df, on='patientId', how='left').sort_values('patientId') # Only the path was added\nprint(image_bbox_df.shape[0], 'image bounding boxes')\nimage_bbox_df.head(5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:55:00.052015Z","iopub.execute_input":"2025-05-07T06:55:00.052291Z","iopub.status.idle":"2025-05-07T06:55:00.102169Z","shell.execute_reply.started":"2025-05-07T06:55:00.052267Z","shell.execute_reply":"2025-05-07T06:55:00.101616Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Integrating old and new features\nDCM_TAG_LIST = ['PatientAge', 'BodyPartExamined', 'ViewPosition', 'PatientSex']\n\ndef get_tags(in_path):\n    c_dicom = pydicom.dcmread(in_path, stop_before_pixels=False)  # Use read_file for pydicom version 3.0 and below\n    tag_dict = {c_tag: getattr(c_dicom, c_tag, '') for c_tag in DCM_TAG_LIST}\n    tag_dict['path'] = in_path\n    return pd.Series(tag_dict)\n    \nimage_meta_df = image_df.apply(lambda x: get_tags(x['path']), axis=1)  # Extract metadata for each image\n\n# Show the summary\nimage_meta_df['PatientAge'] = image_meta_df['PatientAge'].map(int)  # Convert to integer type\nimage_meta_df['PatientAge'].hist()  # Plot histogram\n# image_meta_df.drop('path', axis=1).describe(exclude=np.number)  # Drop 'path' column and describe other columns\n# image_meta_df.drop('path', axis=1, inplace=True)  # Using keyword argument\nsample_df = image_bbox_df.\\\n    groupby(['Target', 'class', 'boxes']).\\\n    apply(lambda x: x[x['patientId'] == x.sample(1)['patientId'].values[0]]).\\\n    reset_index(drop=True)\nsample_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:55:00.102859Z","iopub.execute_input":"2025-05-07T06:55:00.103118Z","iopub.status.idle":"2025-05-07T06:59:21.346163Z","shell.execute_reply.started":"2025-05-07T06:55:00.103092Z","shell.execute_reply":"2025-05-07T06:59:21.345349Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"第二行： 对每个分组应用一个函数\n 从当前分组中随机抽取一行，并获取该行的 patientId。sample(1) 返回一行的随机样本，\n 然后通过 ['patientId'] 访问 patientId 列，最后使用 .values[0] 获取该值。\n","metadata":{}},{"cell_type":"code","source":"grouped = image_bbox_df.groupby(['Target', 'class', 'boxes'])\nprint(grouped.size()) # View the size of each group","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:21.347103Z","iopub.execute_input":"2025-05-07T06:59:21.347878Z","iopub.status.idle":"2025-05-07T06:59:21.357445Z","shell.execute_reply.started":"2025-05-07T06:59:21.347859Z","shell.execute_reply":"2025-05-07T06:59:21.356681Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3 Load file Name\nfilenames = os.listdir(dicom_dir)\nrandom.shuffle(filenames)\n\n# split into train and validation filenames\nn_valid_samples = 2560\ntrain_filenames = filenames[n_valid_samples:]\nvalid_filenames = filenames[:n_valid_samples]\nprint('n train samples', len(train_filenames))\nprint('n valid samples', len(valid_filenames))\nn_train_samples = len(filenames) - n_valid_samples","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:21.35818Z","iopub.execute_input":"2025-05-07T06:59:21.35838Z","iopub.status.idle":"2025-05-07T06:59:21.389439Z","shell.execute_reply.started":"2025-05-07T06:59:21.358365Z","shell.execute_reply":"2025-05-07T06:59:21.3887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Total train images:', len(filenames))\nprint('Images with pneumonia:', len(pneumonia_locations))  # Total image count and pneumonia image count\n\n# Histogram of pneumonia counts\nns = [len(value) for value in pneumonia_locations.values()]\nplt.figure()\nplt.hist(ns)\nplt.xlabel('Pneumonia per image')\nplt.xticks(range(1, np.max(ns) + 1))\nplt.show() \n\n# Pneumonia location heatmap\nheatmap = np.zeros((1024, 1024))\nws = []\nhs = []\nfor values in pneumonia_locations.values():\n    for value in values:\n        x, y, w, h = value\n        heatmap[y:y+h, x:x+w] += 1\n        ws.append(w)\n        hs.append(h)\nplt.figure()\nplt.title('Pneumonia location heatmap')\nplt.imshow(heatmap)\n\n# Histogram of pneumonia height lengths\nplt.figure()\nplt.title('Pneumonia height lengths')\nplt.hist(hs, bins=np.linspace(0, 1000, 50))\nplt.show()\n\n# Histogram of pneumonia width lengths\nplt.figure()\nplt.title('Pneumonia width lengths')\nplt.hist(ws, bins=np.linspace(0, 1000, 50))\nplt.show()\n\nprint('Minimum pneumonia height:', np.min(hs))  # Minimum pneumonia height and width\nprint('Minimum pneumonia width:', np.min(ws))","metadata":{"trusted":true,"jupyter":{"outputs_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T06:59:21.390109Z","iopub.execute_input":"2025-05-07T06:59:21.390296Z","iopub.status.idle":"2025-05-07T06:59:24.886701Z","shell.execute_reply.started":"2025-05-07T06:59:21.390281Z","shell.execute_reply":"2025-05-07T06:59:24.8859Z"},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Total train images:', len(filenames))\nprint('Images with pneumonia:', len(pneumonia_locations))  # Total image count and pneumonia image count\n\n# Check if pneumonia images exist\nif pneumonia_locations:\n    ns = [len(value) for value in pneumonia_locations.values()]\n\n    # Histogram of pneumonia counts\n    plt.figure()\n    plt.hist(ns)\n    plt.xlabel('Pneumonia per image')\n    plt.xticks(range(1, np.max(ns) + 1))\n    plt.show() \n\n    # Pneumonia location heatmap\n    heatmap = np.zeros((1024, 1024))\n    ws = []\n    hs = []\n    for values in pneumonia_locations.values():\n        for value in values:\n            x, y, w, h = value\n            heatmap[y:y+h, x:x+w] += 1\n            ws.append(w)\n            hs.append(h)\n\n    plt.figure()\n    plt.title('Pneumonia location heatmap')\n    plt.imshow(heatmap)\n\n    # Histogram of pneumonia height lengths\n    plt.figure()\n    plt.title('Pneumonia height lengths')\n    plt.hist(hs, bins=np.linspace(0, 1000, 50))\n    plt.show()\n\n    # Histogram of pneumonia width lengths\n    plt.figure()\n    plt.title('Pneumonia width lengths')\n    plt.hist(ws, bins=np.linspace(0, 1000, 50))\n    plt.show()\n\n    print('Minimum pneumonia height:', np.min(hs))  # Minimum pneumonia height and width\n    print('Minimum pneumonia width:', np.min(ws))\nelse:\n    print('No pneumonia images found.')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:24.88751Z","iopub.execute_input":"2025-05-07T06:59:24.887798Z","iopub.status.idle":"2025-05-07T06:59:28.033316Z","shell.execute_reply.started":"2025-05-07T06:59:24.887774Z","shell.execute_reply":"2025-05-07T06:59:28.032575Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2.1 label Block diagrams assist in analysis","metadata":{}},{"cell_type":"markdown","source":"#### 2.1.1 EDA","metadata":{}},{"cell_type":"code","source":"def parse_data(bbox_df):  # Read CSV into a dictionary\n    # --- Define lambda to extract coordinates in list [y, x, height, width]\n    extract_box = lambda row: [row['y'], row['x'], row['height'], row['width']]\n\n    parsed = {}\n    for n, row in bbox_df.iterrows():\n        # Initialize\n        pid = row['patientId']\n        if pid not in parsed:\n            parsed[pid] = {\n                # 'dicom': '../input/stage_2_train_images/%s.dcm' % pid,\n                'dicom': os.path.join(dicom_dir, f'{pid}.dcm'),\n                'label': row['Target'],\n                'boxes': []}\n\n        # If label indicates pneumonia, add the box\n        if parsed[pid]['label'] == 1:\n            parsed[pid]['boxes'].append(extract_box(row))\n\n    return parsed\n\nparsed = parse_data(bbox_df)\nprint(parsed['00436515-870c-4b36-a041-de91049b9ab4'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:28.034257Z","iopub.execute_input":"2025-05-07T06:59:28.034489Z","iopub.status.idle":"2025-05-07T06:59:29.247158Z","shell.execute_reply.started":"2025-05-07T06:59:28.03447Z","shell.execute_reply":"2025-05-07T06:59:29.24629Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def draw(data):  # Method to draw a single patient's data\n    # --- Open DICOM file\n    d = pydicom.dcmread(data['dicom'])  # Use read_file for pydicom version 3.0 and below\n    im = d.pixel_array\n\n    # --- Convert from single-channel grayscale to 3-channel RGB\n    im = np.stack([im] * 3, axis=2)\n\n    # --- Add boxes with random color if present\n    for box in data['boxes']:\n        rgb = np.floor(np.random.rand(3) * 256).astype('int')\n        im = overlay_box(im=im, box=box, rgb=rgb, stroke=6)\n\n    pylab.imshow(im, cmap=pylab.cm.gist_gray)\n    pylab.axis('off')\n\ndef overlay_box(im, box, rgb, stroke=1):  # Overlay a single box on the image\n    # --- Convert coordinates to integers\n    box = [int(b) for b in box]\n    \n    # --- Extract coordinates\n    y1, x1, height, width = box\n    y2 = y1 + height\n    x2 = x1 + width\n\n    im[y1:y1 + stroke, x1:x2] = rgb\n    im[y2:y2 + stroke, x1:x2] = rgb\n    im[y1:y2, x1:x1 + stroke] = rgb\n    im[y1:y2, x2:x2 + stroke] = rgb\n\n    return im\n\ndraw(parsed['00436515-870c-4b36-a041-de91049b9ab4'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:29.247988Z","iopub.execute_input":"2025-05-07T06:59:29.248683Z","iopub.status.idle":"2025-05-07T06:59:29.508176Z","shell.execute_reply.started":"2025-05-07T06:59:29.248663Z","shell.execute_reply":"2025-05-07T06:59:29.507415Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patientId = det_class_df['patientId'][0]\ndraw(parsed[patientId])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:29.509146Z","iopub.execute_input":"2025-05-07T06:59:29.509885Z","iopub.status.idle":"2025-05-07T06:59:29.746258Z","shell.execute_reply.started":"2025-05-07T06:59:29.509853Z","shell.execute_reply":"2025-05-07T06:59:29.745502Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### 2.1.2 多图分析","metadata":{}},{"cell_type":"code","source":"# Display locations and bounding boxes\nfig, m_axs = plt.subplots(2, 3, figsize=(20, 10))  # Create a 2-row, 3-column subplot\nfor c_ax, (c_path_tuple, c_rows) in zip(m_axs.flatten(), sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    # Should return a tuple instead of just the path as in 3.6\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read DICOM file\n    c_ax.imshow(c_dicom.pixel_array, cmap='bone')  # Display the image\n    c_ax.set_title('{class}'.format(**c_rows.iloc[0, :]))  # Set the title\n    for i, (_, c_row) in enumerate(c_rows.dropna().iterrows()):  # Iterate through each row\n        c_ax.plot(c_row['x'], c_row['y'], 's', label='{class}'.format(**c_row))  # Draw square markers\n        c_ax.add_patch(Rectangle(xy=(c_row['x'], c_row['y']),\n                                  width=c_row['width'],\n                                  height=c_row['height'], \n                                  alpha=0.5))  # Add rectangle box\n        if i == 0: \n            c_ax.legend()  # Show legend only for the first marker","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:29.746995Z","iopub.execute_input":"2025-05-07T06:59:29.747217Z","iopub.status.idle":"2025-05-07T06:59:31.633912Z","shell.execute_reply.started":"2025-05-07T06:59:29.747202Z","shell.execute_reply":"2025-05-07T06:59:31.632899Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Box distribution\npos_bbox = image_bbox_df.query('Target==1')\npos_bbox.plot.scatter(x='x', y='y')\n\n# Create subplots\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))\nax1.set_xlim(0, 1024)\nax1.set_ylim(0, 1024)\nfor _, c_row in pos_bbox.sample(1000).iterrows():\n    ax1.add_patch(Rectangle(xy=(c_row['x'], c_row['y']),\n                 width=c_row['width'],\n                 height=c_row['height'],\n                           alpha=5e-3))\nax1.set_title('Bounding Box Visualization')\n\n# Display boxes as segmentation\nX_STEPS, Y_STEPS = 1024, 1024\nxx, yy = np.meshgrid(np.linspace(0, 1024, X_STEPS),\n           np.linspace(0, 1024, Y_STEPS), \n           indexing='xy')\nprob_image = np.zeros_like(xx)\nfor _, c_row in pos_bbox.sample(5000).iterrows():\n    c_mask = (xx >= c_row['x']) & (xx <= (c_row['x'] + c_row['width']))\n    c_mask &= (yy >= c_row['y']) & (yy <= (c_row['y'] + c_row['height']))\n    prob_image += c_mask\n\nax2.imshow(prob_image, cmap='hot')\nax2.set_title('Probability Image')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T06:59:31.634847Z","iopub.execute_input":"2025-05-07T06:59:31.635097Z","iopub.status.idle":"2025-05-07T07:00:09.467971Z","shell.execute_reply.started":"2025-05-07T06:59:31.635077Z","shell.execute_reply":"2025-05-07T07:00:09.467276Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Display locations and bounding boxes\nfig, m_axs = plt.subplots(2, 3, figsize=(20, 10))  # Create a 2-row, 3-column subplot\nfor c_ax, (c_path_tuple, c_rows) in zip(m_axs.flatten(), sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read DICOM file\n    c_img_arr = c_dicom.pixel_array\n    \n    # Overlay\n    c_img = plt.cm.gray(c_img_arr)\n    c_img += 0.25 * plt.cm.hot(prob_image / prob_image.max())\n    c_img = np.clip(c_img, 0, 1)\n    \n    c_ax.imshow(c_img)\n    c_ax.set_title('{class}'.format(**c_rows.iloc[0, :]))\n    \n    for i, (_, c_row) in enumerate(c_rows.dropna().iterrows()):  # Iterate through each row\n        c_ax.plot(c_row['x'], c_row['y'], 's', label='{class}'.format(**c_row))\n        c_ax.add_patch(Rectangle(xy=(c_row['x'], c_row['y']),\n                                 width=c_row['width'],\n                                 height=c_row['height'], \n                                 alpha=0.5,\n                                 fill=False))\n        if i == 0:\n            c_ax.legend()\n\n# Save the image\nfig.savefig('overview.png', dpi=600)  # Save with specified dpi\n# plt.close(fig)  # Close the figure to free memory","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:09.473203Z","iopub.execute_input":"2025-05-07T07:00:09.473413Z","iopub.status.idle":"2025-05-07T07:00:25.904978Z","shell.execute_reply.started":"2025-05-07T07:00:09.473397Z","shell.execute_reply":"2025-05-07T07:00:25.904079Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_bbox_df.to_csv('image_bbox_full.csv', index=False) # Save the preprocessing result","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:25.905834Z","iopub.execute_input":"2025-05-07T07:00:25.906074Z","iopub.status.idle":"2025-05-07T07:00:26.127692Z","shell.execute_reply.started":"2025-05-07T07:00:25.90603Z","shell.execute_reply":"2025-05-07T07:00:26.127081Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3. Train","metadata":{}},{"cell_type":"markdown","source":"## 3.1 Data Generator","metadata":{}},{"cell_type":"code","source":"class generator(keras.utils.Sequence):\n    \n    def __init__(self, folder, filenames, pneumonia_locations=None, batch_size=32, image_size=256, shuffle=True, augment=False, predict=False):\n        self.folder = folder\n        self.filenames = filenames\n        self.pneumonia_locations = pneumonia_locations\n        self.batch_size = batch_size\n        self.image_size = image_size\n        self.shuffle = shuffle\n        self.augment = augment\n        self.predict = predict\n        self.on_epoch_end()\n        \n    def __load__(self, filename):\n        # load dicom file as numpy array\n        img = pydicom.dcmread(os.path.join(self.folder, filename)).pixel_array\n        # create empty mask\n        msk = np.zeros(img.shape)\n        # get filename without extension\n        filename = filename.split('.')[0]\n        # if image contains pneumonia\n        if filename in self.pneumonia_locations:\n            # loop through pneumonia\n            for location in self.pneumonia_locations[filename]:\n                # add 1's at the location of the pneumonia\n                x, y, w, h = location\n                msk[y:y+h, x:x+w] = 1\n        # resize both image and mask\n        img = resize(img, (self.image_size, self.image_size), mode='reflect')\n        msk = resize(msk, (self.image_size, self.image_size), mode='reflect') > 0.5\n        # if augment then horizontal flip half the time\n        if self.augment and random.random() > 0.5:\n            img = np.fliplr(img)\n            msk = np.fliplr(msk)\n        # add trailing channel dimension\n        img = np.expand_dims(img, -1)\n        msk = np.expand_dims(msk, -1)\n        return img, msk\n    \n    def __loadpredict__(self, filename):\n        # load dicom file as numpy array\n        img = pydicom.dcmread(os.path.join(self.folder, filename)).pixel_array\n        # resize image\n        img = resize(img, (self.image_size, self.image_size), mode='reflect')\n        # add trailing channel dimension\n        img = np.expand_dims(img, -1)\n        return img\n        \n    def __getitem__(self, index):\n        # select batch\n        filenames = self.filenames[index*self.batch_size:(index+1)*self.batch_size]\n        # predict mode: return images and filenames\n        if self.predict:\n            # load files\n            imgs = [self.__loadpredict__(filename) for filename in filenames]\n            # create numpy batch\n            imgs = np.array(imgs)\n            return imgs, filenames\n        # train mode: return images and masks\n        else:\n            # load files\n            items = [self.__load__(filename) for filename in filenames]\n            # unzip images and masks\n            imgs, msks = zip(*items)\n            # create numpy batch\n            imgs = np.array(imgs)\n            msks = np.array(msks)\n            return imgs, msks\n        \n    def on_epoch_end(self):\n        if self.shuffle:\n            random.shuffle(self.filenames)\n        \n    def __len__(self):\n        if self.predict:\n            # return everything\n            return int(np.ceil(len(self.filenames) / self.batch_size))\n        else:\n            # return full batches only\n            return int(len(self.filenames) / self.batch_size)","metadata":{"trusted":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.128415Z","iopub.execute_input":"2025-05-07T07:00:26.128641Z","iopub.status.idle":"2025-05-07T07:00:26.138906Z","shell.execute_reply.started":"2025-05-07T07:00:26.128615Z","shell.execute_reply":"2025-05-07T07:00:26.138281Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3.2 network framework","metadata":{}},{"cell_type":"code","source":"# Resnet CNN\n# This model is a convolutional neural network based on residual networks and is suitable for image segmentation tasks.\ndef create_downsample(channels, inputs):\n    x = keras.layers.BatchNormalization(momentum=0.9)(inputs)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(channels, 1, padding='same', use_bias=False)(x)\n    x = keras.layers.MaxPool2D(2)(x)\n    return x\n\ndef create_resblock(channels, inputs):\n    x = keras.layers.BatchNormalization(momentum=0.9)(inputs)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(channels, 3, padding='same', use_bias=False)(x)\n    x = keras.layers.BatchNormalization(momentum=0.9)(x)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(channels, 3, padding='same', use_bias=False)(x)\n    return keras.layers.add([x, inputs])\n\ndef create_network(input_size, channels, n_blocks=2, depth=4):\n    # input\n    inputs = keras.Input(shape=(input_size, input_size, 1))\n    x = keras.layers.Conv2D(channels, 3, padding='same', use_bias=False)(inputs)\n    # residual blocks\n    for d in range(depth):\n        channels = channels * 2\n        x = create_downsample(channels, x)\n        for b in range(n_blocks):\n            x = create_resblock(channels, x)\n    # output\n    x = keras.layers.BatchNormalization(momentum=0.9)(x)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(1, 1, activation='sigmoid')(x)\n    outputs = keras.layers.UpSampling2D(2**depth)(x)\n    model = keras.Model(inputs=inputs, outputs=outputs)\n    return model","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.139449Z","iopub.execute_input":"2025-05-07T07:00:26.139667Z","iopub.status.idle":"2025-05-07T07:00:26.153646Z","shell.execute_reply.started":"2025-05-07T07:00:26.139651Z","shell.execute_reply":"2025-05-07T07:00:26.152826Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# unet\ndef create_unet(input_size):\n    inputs = keras.Input(shape=(input_size, input_size, 1))\n\n    # Encoder\n    c1 = keras.layers.Conv2D(64, (3, 3), padding='same')(inputs)\n    c1 = keras.layers.BatchNormalization()(c1)\n    c1 = keras.layers.LeakyReLU()(c1)\n    c1 = keras.layers.Conv2D(64, (3, 3), padding='same')(c1)\n    c1 = keras.layers.BatchNormalization()(c1)\n    c1 = keras.layers.LeakyReLU()(c1)\n    p1 = keras.layers.MaxPooling2D((2, 2))(c1)\n\n    c2 = keras.layers.Conv2D(128, (3, 3), padding='same')(p1)\n    c2 = keras.layers.BatchNormalization()(c2)\n    c2 = keras.layers.LeakyReLU()(c2)\n    c2 = keras.layers.Conv2D(128, (3, 3), padding='same')(c2)\n    c2 = keras.layers.BatchNormalization()(c2)\n    c2 = keras.layers.LeakyReLU()(c2)\n    p2 = keras.layers.MaxPooling2D((2, 2))(c2)\n\n    c3 = keras.layers.Conv2D(256, (3, 3), padding='same')(p2)\n    c3 = keras.layers.BatchNormalization()(c3)\n    c3 = keras.layers.LeakyReLU()(c3)\n    c3 = keras.layers.Conv2D(256, (3, 3), padding='same')(c3)\n    c3 = keras.layers.BatchNormalization()(c3)\n    c3 = keras.layers.LeakyReLU()(c3)\n    p3 = keras.layers.MaxPooling2D((2, 2))(c3)\n\n    # Bottleneck\n    c4 = keras.layers.Conv2D(512, (3, 3), padding='same')(p3)\n    c4 = keras.layers.BatchNormalization()(c4)\n    c4 = keras.layers.LeakyReLU()(c4)\n    c4 = keras.layers.Conv2D(512, (3, 3), padding='same')(c4)\n    c4 = keras.layers.BatchNormalization()(c4)\n    c4 = keras.layers.LeakyReLU()(c4)\n\n    # Decoder\n    u5 = keras.layers.UpSampling2D((2, 2))(c4)\n    u5 = keras.layers.Concatenate()([u5, c3])\n    c5 = keras.layers.Conv2D(256, (3, 3), padding='same')(u5)\n    c5 = keras.layers.BatchNormalization()(c5)\n    c5 = keras.layers.LeakyReLU()(c5)\n    c5 = keras.layers.Conv2D(256, (3, 3), padding='same')(c5)\n    c5 = keras.layers.BatchNormalization()(c5)\n    c5 = keras.layers.LeakyReLU()(c5)\n\n    u6 = keras.layers.UpSampling2D((2, 2))(c5)\n    u6 = keras.layers.Concatenate()([u6, c2])\n    c6 = keras.layers.Conv2D(128, (3, 3), padding='same')(u6)\n    c6 = keras.layers.BatchNormalization()(c6)\n    c6 = keras.layers.LeakyReLU()(c6)\n    c6 = keras.layers.Conv2D(128, (3, 3), padding='same')(c6)\n    c6 = keras.layers.BatchNormalization()(c6)\n    c6 = keras.layers.LeakyReLU()(c6)\n\n    u7 = keras.layers.UpSampling2D((2, 2))(c6)\n    u7 = keras.layers.Concatenate()([u7, c1])\n    c7 = keras.layers.Conv2D(64, (3, 3), padding='same')(u7)\n    c7 = keras.layers.BatchNormalization()(c7)\n    c7 = keras.layers.LeakyReLU()(c7)\n    c7 = keras.layers.Conv2D(64, (3, 3), padding='same')(c7)\n    c7 = keras.layers.BatchNormalization()(c7)\n    c7 = keras.layers.LeakyReLU()(c7)\n\n    outputs = keras.layers.Conv2D(1, (1, 1), activation='sigmoid')(c7)\n\n    model = keras.Model(inputs=[inputs], outputs=[outputs])\n    return model","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.154328Z","iopub.execute_input":"2025-05-07T07:00:26.154522Z","iopub.status.idle":"2025-05-07T07:00:26.169402Z","shell.execute_reply.started":"2025-05-07T07:00:26.154509Z","shell.execute_reply":"2025-05-07T07:00:26.168822Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" # FCN\n\nfrom tensorflow.keras import layers\ndef create_fcn(input_size, base_channels=64):\n    inputs = keras.Input(shape=(input_size, input_size, 1))\n\n    # Encoder\n    c1 = layers.Conv2D(base_channels, 3, activation='relu', padding='same')(inputs)\n    c1 = layers.Conv2D(base_channels, 3, activation='relu', padding='same')(c1)\n    p1 = layers.MaxPooling2D((2, 2))(c1)\n\n    c2 = layers.Conv2D(base_channels*2, 3, activation='relu', padding='same')(p1)\n    c2 = layers.Conv2D(base_channels*2, 3, activation='relu', padding='same')(c2)\n    p2 = layers.MaxPooling2D((2, 2))(c2)\n\n    c3 = layers.Conv2D(base_channels*4, 3, activation='relu', padding='same')(p2)\n    c3 = layers.Conv2D(base_channels*4, 3, activation='relu', padding='same')(c3)\n    p3 = layers.MaxPooling2D((2, 2))(c3)\n\n    # Bottleneck\n    b = layers.Conv2D(base_channels*8, 3, activation='relu', padding='same')(p3)\n    b = layers.Conv2D(base_channels*8, 3, activation='relu', padding='same')(b)\n\n    # Decoder (upsample + concat skip)\n    u3 = layers.UpSampling2D((2, 2))(b)\n    u3 = layers.Concatenate()([u3, c3])\n    u3 = layers.Conv2D(base_channels*4, 3, activation='relu', padding='same')(u3)\n\n    u2 = layers.UpSampling2D((2, 2))(u3)\n    u2 = layers.Concatenate()([u2, c2])\n    u2 = layers.Conv2D(base_channels*2, 3, activation='relu', padding='same')(u2)\n\n    u1 = layers.UpSampling2D((2, 2))(u2)\n    u1 = layers.Concatenate()([u1, c1])\n    u1 = layers.Conv2D(base_channels, 3, activation='relu', padding='same')(u1)\n\n    # Output layer\n    outputs = layers.Conv2D(1, 1, activation='sigmoid')(u1)\n\n    return keras.Model(inputs, outputs)\n","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.170189Z","iopub.execute_input":"2025-05-07T07:00:26.170421Z","iopub.status.idle":"2025-05-07T07:00:26.189187Z","shell.execute_reply.started":"2025-05-07T07:00:26.170406Z","shell.execute_reply":"2025-05-07T07:00:26.188555Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# segnet\ndef create_segnet(input_size, base_channels=64):\n    inputs = keras.Input(shape=(input_size, input_size, 1))\n\n    # Encoder\n    x = layers.Conv2D(base_channels, 3, padding='same', activation='relu')(inputs)\n    x = layers.Conv2D(base_channels, 3, padding='same', activation='relu')(x)\n    x = layers.MaxPooling2D((2, 2))(x)  # down 1\n\n    x = layers.Conv2D(base_channels*2, 3, padding='same', activation='relu')(x)\n    x = layers.Conv2D(base_channels*2, 3, padding='same', activation='relu')(x)\n    x = layers.MaxPooling2D((2, 2))(x)  # down 2\n\n    x = layers.Conv2D(base_channels*4, 3, padding='same', activation='relu')(x)\n    x = layers.Conv2D(base_channels*4, 3, padding='same', activation='relu')(x)\n    x = layers.MaxPooling2D((2, 2))(x)  # down 3\n\n    # Decoder\n    x = layers.UpSampling2D((2, 2))(x)  # up 3\n    x = layers.Conv2D(base_channels*4, 3, padding='same', activation='relu')(x)\n    x = layers.Conv2D(base_channels*4, 3, padding='same', activation='relu')(x)\n\n    x = layers.UpSampling2D((2, 2))(x)  # up 2\n    x = layers.Conv2D(base_channels*2, 3, padding='same', activation='relu')(x)\n    x = layers.Conv2D(base_channels*2, 3, padding='same', activation='relu')(x)\n\n    x = layers.UpSampling2D((2, 2))(x)  # up 1\n    x = layers.Conv2D(base_channels, 3, padding='same', activation='relu')(x)\n    x = layers.Conv2D(base_channels, 3, padding='same', activation='relu')(x)\n\n    # Output\n    outputs = layers.Conv2D(1, 1, activation='sigmoid')(x)\n\n    return keras.Model(inputs=inputs, outputs=outputs)","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.189809Z","iopub.execute_input":"2025-05-07T07:00:26.190025Z","iopub.status.idle":"2025-05-07T07:00:26.203243Z","shell.execute_reply.started":"2025-05-07T07:00:26.190009Z","shell.execute_reply":"2025-05-07T07:00:26.202664Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(keras_cv.__version__)\n# It was version 0.9.0 before the update\n# The higher version is only available locally, approximately 10 or 11","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.204034Z","iopub.execute_input":"2025-05-07T07:00:26.204305Z","iopub.status.idle":"2025-05-07T07:00:26.22274Z","shell.execute_reply.started":"2025-05-07T07:00:26.204282Z","shell.execute_reply":"2025-05-07T07:00:26.222015Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import keras_cv\nprint(dir(keras_cv.models))","metadata":{"trusted":true,"scrolled":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.223483Z","iopub.execute_input":"2025-05-07T07:00:26.224203Z","iopub.status.idle":"2025-05-07T07:00:26.238529Z","shell.execute_reply.started":"2025-05-07T07:00:26.224179Z","shell.execute_reply":"2025-05-07T07:00:26.237846Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"help(BASNet)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.239139Z","iopub.execute_input":"2025-05-07T07:00:26.239329Z","iopub.status.idle":"2025-05-07T07:00:26.338441Z","shell.execute_reply.started":"2025-05-07T07:00:26.239315Z","shell.execute_reply":"2025-05-07T07:00:26.337517Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras_cv.models import (\n    BASNet,\n    Backbone,\n    CLIP,\n    CSPDarkNetBackbone,\n    CSPDarkNetLBackbone,\n    CSPDarkNetMBackbone,\n    CSPDarkNetSBackbone,\n    CSPDarkNetTinyBackbone,\n    CSPDarkNetXLBackbone,\n    CenterPillarBackbone,\n    DeepLabV3Plus,\n    DenseNet121Backbone,\n    DenseNet169Backbone,\n    DenseNet201Backbone,\n    DenseNetBackbone,\n    EfficientNetLiteB0Backbone,\n    EfficientNetLiteB1Backbone,\n    EfficientNetLiteB2Backbone,\n    EfficientNetLiteB3Backbone,\n    EfficientNetLiteB4Backbone,\n    EfficientNetLiteBackbone,\n    EfficientNetV1B0Backbone,\n    EfficientNetV1B1Backbone,\n    EfficientNetV1B2Backbone,\n    EfficientNetV1B3Backbone,\n    EfficientNetV1B4Backbone,\n    EfficientNetV1B5Backbone,\n    EfficientNetV1B6Backbone,\n    EfficientNetV1B7Backbone,\n    EfficientNetV1Backbone,\n    EfficientNetV2B0Backbone,\n    EfficientNetV2B1Backbone,\n    EfficientNetV2B2Backbone,\n    EfficientNetV2B3Backbone,\n    EfficientNetV2Backbone,\n    EfficientNetV2LBackbone,\n    EfficientNetV2MBackbone,\n    EfficientNetV2SBackbone,\n    ImageClassifier,\n    MiTB0Backbone,\n    MiTB1Backbone,\n    MiTB2Backbone,\n    MiTB3Backbone,\n    MiTB4Backbone,\n    MiTB5Backbone,\n    MiTBackbone,\n    MobileNetV3Backbone,\n    MobileNetV3LargeBackbone,\n    MobileNetV3SmallBackbone,\n    MultiHeadCenterPillar,\n    ResNet101Backbone,\n    ResNet101V2Backbone,\n    ResNet152Backbone,\n    ResNet152V2Backbone,\n    ResNet18Backbone,\n    ResNet18V2Backbone,\n    ResNet34Backbone,\n    ResNet34V2Backbone,\n    ResNet50Backbone,\n    ResNet50V2Backbone,\n    ResNetBackbone,\n    ResNetV2Backbone,\n    RetinaNet,\n    SAMMaskDecoder,\n    SAMPromptEncoder,\n    SegFormer,\n    SegFormerB0,\n    SegFormerB1,\n    SegFormerB2,\n    SegFormerB3,\n    SegFormerB4,\n    SegFormerB5,\n    SegmentAnythingModel,\n    StableDiffusion,\n    StableDiffusionV2,\n    Task,\n    TwoWayTransformer,\n    VGG16Backbone,\n    ViTDetBBackbone,\n    ViTDetBackbone,\n    ViTDetHBackbone,\n    ViTDetLBackbone,\n    VideoClassifier,\n    VideoSwinBBackbone,\n    VideoSwinBackbone,\n    VideoSwinSBackbone,\n    VideoSwinTBackbone,\n    YOLOV8Backbone,\n    YOLOV8Detector\n)","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.338884Z","iopub.status.idle":"2025-05-07T07:00:26.339134Z","shell.execute_reply.started":"2025-05-07T07:00:26.339008Z","shell.execute_reply":"2025-05-07T07:00:26.339018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_model(input_size=256):\n    # Create a base model using ResNet50 with a single channel\n    base = ResNet50Backbone(input_shape=(input_size, input_size, 1))  # Change to 1 channel\n\n\ndef create_model(input_size=256, \n                 stackwise_channels=[32, 64, 128, 256], \n                 stackwise_depth=[3, 3, 3, 3],  # Depth for each channel as a list\n                 include_rescaling=True):\n    base = MobileNetV3Backbone(input_shape=(input_size, input_size, 1), \n                          stackwise_channels=stackwise_channels, \n                          stackwise_depth=stackwise_depth, \n                          include_rescaling=include_rescaling)\n\ndef create_model(input_size=256, \n                 stackwise_expansion=[1, 6, 6, 6],  # Expansion ratios\n                 stackwise_filters=[16, 24, 40, 80],  # Number of channels\n                 stackwise_kernel_size=[3, 3, 5, 3],  # Convolution kernel sizes\n                 stackwise_stride=[1, 2, 2, 2],  # Strides\n                 stackwise_se_ratio=[0.25, 0.25, 0.25, 0.25],  # Squeeze-and-Excitation ratios\n                 stackwise_activation=[\"relu\", \"hard_swish\", \"hard_swish\", \"hard_swish\"],  # Activation functions\n                 include_rescaling=True):\n    # Use MobileNetV3Backbone with single channel input shape\n    base = MobileNetV3Backbone(\n        input_shape=(input_size, input_size, 1), \n        stackwise_expansion=stackwise_expansion,\n        stackwise_filters=stackwise_filters,\n        stackwise_kernel_size=stackwise_kernel_size,\n        stackwise_stride=stackwise_stride,\n        stackwise_se_ratio=stackwise_se_ratio,\n        stackwise_activation=stackwise_activation,\n        include_rescaling=include_rescaling\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.339994Z","iopub.status.idle":"2025-05-07T07:00:26.340305Z","shell.execute_reply.started":"2025-05-07T07:00:26.340159Z","shell.execute_reply":"2025-05-07T07:00:26.340175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras import layers, Model\nfrom keras_hub.models import ResNetBackbone  # Ensure correct import\n\ndef create_model(input_size=256, num_classes=10):\n    base = ResNetBackbone(\n        input_conv_filters=[64],                    # Number of filters in the input convolution layer\n        input_conv_kernel_sizes=[7],                # Size of the convolution kernel in the input layer\n        stackwise_num_filters=[64, 128, 256],      # Number of filters in each layer\n        stackwise_num_blocks=[2, 2, 2],             # Number of blocks in each layer\n        stackwise_num_strides=[1, 2, 2],            # Strides for each layer\n        block_type='basic_block',                    # Use an effective block type\n        # include_rescaling=True,                     # Include rescaling layer\n        image_shape=(input_size, input_size, 3)     # Input shape\n    )\n    \n    x = base.output\n    x = layers.GlobalAveragePooling2D()(x)\n    x = layers.Dense(num_classes, activation='softmax')(x)\n\n    return Model(inputs=base.input, outputs=x)\n\n# Create the model\nmodel = create_model()\n\n# Compile the model\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.341639Z","iopub.status.idle":"2025-05-07T07:00:26.341927Z","shell.execute_reply.started":"2025-05-07T07:00:26.341772Z","shell.execute_reply":"2025-05-07T07:00:26.341788Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3.3 training","metadata":{}},{"cell_type":"code","source":"model = create_model()\nmodel.compile(optimizer='adam',loss=iou_bce_loss,metrics=['accuracy', mean_iou])","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.342567Z","iopub.status.idle":"2025-05-07T07:00:26.342837Z","shell.execute_reply.started":"2025-05-07T07:00:26.342723Z","shell.execute_reply":"2025-05-07T07:00:26.342736Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define IOU or Jaccard loss function\ndef iou_loss(y_true, y_pred):\n    y_true = tf.reshape(y_true, [-1])\n    y_pred = tf.reshape(y_pred, [-1])\n    intersection = tf.reduce_sum(y_true * y_pred)\n    score = (intersection + 1.0) / (tf.reduce_sum(y_true) + tf.reduce_sum(y_pred) - intersection + 1.0)\n    return 1 - score\n\n\n# Combine BCE loss and IOU loss\ndef iou_bce_loss(y_true, y_pred):\n    bce_loss = tf.keras.losses.binary_crossentropy(y_true, y_pred)\n    return 0.5 * bce_loss + 0.5 * iou_loss(y_true, y_pred)\n\n# Calculate mean IOU as a metric\ndef mean_iou(y_true, y_pred):\n    y_pred = tf.round(y_pred)\n    y_true = tf.cast(y_true, tf.float32)  # Convert to float\n    y_pred = tf.cast(y_pred, tf.float32)  # Convert to float\n    intersect = tf.reduce_sum(y_true * y_pred, axis=[1, 2, 3])\n    union = tf.reduce_sum(y_true, axis=[1, 2, 3]) + tf.reduce_sum(y_pred, axis=[1, 2, 3])\n    smooth = tf.ones(tf.shape(intersect), dtype=tf.float32)  # Ensure smooth is float\n    return tf.reduce_mean((intersect + smooth) / (union - intersect + smooth))\n\n# Create network and compile\n# model = create_network(input_size=256, channels=32, n_blocks=2, depth=4)\n# model = create_unet(input_size=256)\n# model = create_fcn(input_size=128, base_channels=64)\n# model = create_segnet(input_size=128, base_channels=32)\n\n# Cosine learning rate decay\ndef cosine_annealing(x):\n    lr = 0.001\n    epochs = 25\n    return lr * (np.cos(np.pi * x / epochs) + 1) / 2\n\nlearning_rate = tf.keras.callbacks.LearningRateScheduler(cosine_annealing)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.344057Z","iopub.status.idle":"2025-05-07T07:00:26.344278Z","shell.execute_reply.started":"2025-05-07T07:00:26.344182Z","shell.execute_reply":"2025-05-07T07:00:26.344191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Modified training process\nclass CustomCallback(tf.keras.callbacks.Callback):\n    def on_epoch_end(self, epoch, logs=None):\n        print(f\"Epoch {epoch + 1}: loss = {logs.get('loss')}, mean_iou = {logs.get('mean_iou')}\")\n\n# Create training and validation generators\ntrain_gen = generator(dicom_dir, train_filenames, pneumonia_locations, batch_size=32, image_size=256, shuffle=True, augment=True, predict=False)\nvalid_gen = generator(dicom_dir, valid_filenames, pneumonia_locations, batch_size=32, image_size=256, shuffle=False, predict=False)\n\n# Train the model\nhistory = model.fit(train_gen, validation_data=valid_gen, callbacks=[learning_rate, CustomCallback()], epochs=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.345116Z","iopub.status.idle":"2025-05-07T07:00:26.345387Z","shell.execute_reply.started":"2025-05-07T07:00:26.345257Z","shell.execute_reply":"2025-05-07T07:00:26.345274Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a training and validation generator\ntrain_gen = generator(dicom_dir, train_filenames, pneumonia_locations, batch_size=8, image_size=256, shuffle=True,  augment=True, predict=False)\nvalid_gen = generator(dicom_dir, valid_filenames, pneumonia_locations, batch_size=8, image_size=256, shuffle=False,  predict=False)\n# Reduce the size of batch_size by 32- 16\n\n# Train the Model\nhistory = model.fit(train_gen, validation_data=valid_gen, callbacks=[learning_rate], epochs=1,batch_size=8)","metadata":{"trusted":true,"scrolled":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.346223Z","iopub.status.idle":"2025-05-07T07:00:26.346536Z","shell.execute_reply.started":"2025-05-07T07:00:26.346362Z","shell.execute_reply":"2025-05-07T07:00:26.346373Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(12,4))\nplt.subplot(131)\nplt.plot(history.epoch, history.history[\"loss\"], label=\"Train loss\")\nplt.plot(history.epoch, history.history[\"val_loss\"], label=\"Valid loss\")\nplt.legend()\nplt.subplot(132)\nplt.plot(history.epoch, history.history[\"acc\"], label=\"Train accuracy\")\nplt.plot(history.epoch, history.history[\"val_acc\"], label=\"Valid accuracy\")\nplt.legend()\nplt.subplot(133)\nplt.plot(history.epoch, history.history[\"mean_iou\"], label=\"Train iou\")\nplt.plot(history.epoch, history.history[\"val_mean_iou\"], label=\"Valid iou\")\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.347397Z","iopub.status.idle":"2025-05-07T07:00:26.347687Z","shell.execute_reply.started":"2025-05-07T07:00:26.347569Z","shell.execute_reply":"2025-05-07T07:00:26.347583Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for imgs, msks in valid_gen:\n    # predict batch of images\n    preds = model.predict(imgs)\n    # create figure\n    f, axarr = plt.subplots(4, 8, figsize=(20,15))\n    axarr = axarr.ravel()\n    axidx = 0\n    # loop through batch\n    for img, msk, pred in zip(imgs, msks, preds):\n        # plot image\n        axarr[axidx].imshow(img[:, :, 0])\n        # threshold true mask\n        comp = msk[:, :, 0] > 0.5\n        # apply connected components\n        comp = measure.label(comp)\n        # apply bounding boxes\n        predictionString = ''\n        for region in measure.regionprops(comp):\n            # retrieve x, y, height and width\n            y, x, y2, x2 = region.bbox\n            height = y2 - y\n            width = x2 - x\n            axarr[axidx].add_patch(patches.Rectangle((x,y),width,height,linewidth=2,edgecolor='b',facecolor='none'))\n        # threshold predicted mask\n        comp = pred[:, :, 0] > 0.5\n        # apply connected components\n        comp = measure.label(comp)\n        # apply bounding boxes\n        predictionString = ''\n        for region in measure.regionprops(comp):\n            # retrieve x, y, height and width\n            y, x, y2, x2 = region.bbox\n            height = y2 - y\n            width = x2 - x\n            axarr[axidx].add_patch(patches.Rectangle((x,y),width,height,linewidth=2,edgecolor='r',facecolor='none'))\n        axidx += 1\n    plt.show()\n    # only plot one batch\n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.349329Z","iopub.status.idle":"2025-05-07T07:00:26.349631Z","shell.execute_reply.started":"2025-05-07T07:00:26.349476Z","shell.execute_reply":"2025-05-07T07:00:26.34949Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3.4 test","metadata":{}},{"cell_type":"code","source":"# load and shuffle filenames\nfolder = '../input/stage_2_test_images'\ntest_filenames = os.listdir(folder)\nprint('n test samples:', len(test_filenames))\n\n# create test generator with predict flag set to True\ntest_gen = generator(folder, test_filenames, None, batch_size=25, image_size=256, shuffle=False, predict=True)\n\n# create submission dictionary\nsubmission_dict = {}\n# loop through testset\nfor imgs, filenames in test_gen:\n    # predict batch of images\n    preds = model.predict(imgs)\n    # loop through batch\n    for pred, filename in zip(preds, filenames):\n        # resize predicted mask\n        pred = resize(pred, (1024, 1024), mode='reflect')\n        # threshold predicted mask\n        comp = pred[:, :, 0] > 0.5\n        # apply connected components\n        comp = measure.label(comp)\n        # apply bounding boxes\n        predictionString = ''\n        for region in measure.regionprops(comp):\n            # retrieve x, y, height and width\n            y, x, y2, x2 = region.bbox\n            height = y2 - y\n            width = x2 - x\n            # proxy for confidence score\n            conf = np.mean(pred[y:y+height, x:x+width])\n            # add to predictionString\n            predictionString += str(conf) + ' ' + str(x) + ' ' + str(y) + ' ' + str(width) + ' ' + str(height) + ' '\n        # add filename and predictionString to dictionary\n        filename = filename.split('.')[0]\n        submission_dict[filename] = predictionString\n    # stop if we've got them all\n    if len(submission_dict) >= len(test_filenames):\n        break\n\n# save dictionary as csv file\nsub = pd.DataFrame.from_dict(submission_dict,orient='index')\nsub.index.names = ['patientId']\nsub.columns = ['PredictionString']\nsub.to_csv('submission.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.350858Z","iopub.status.idle":"2025-05-07T07:00:26.351195Z","shell.execute_reply.started":"2025-05-07T07:00:26.35102Z","shell.execute_reply":"2025-05-07T07:00:26.351049Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Temporary Debugging - To improve feature extraction","metadata":{}},{"cell_type":"markdown","source":"## 1. Extract the csv block diagram information","metadata":{}},{"cell_type":"code","source":"# Create a dictionary to store bounding box information\npneumonia_locations = {}\n\n# Iterate through the DataFrame to extract bounding box information\nfor index, row in bbox_df.iterrows():\n    filename = row['patientId']\n    # Assume bounding box columns are named 'x', 'y', 'width', 'height'\n    location = [row['x'], row['y'], row['width'], row['height']]\n    \n    # Only process images labeled as 1 for pneumonia\n    if row['Target'] == 1:\n        if filename in pneumonia_locations:\n            pneumonia_locations[filename].append(location)\n        else:\n            pneumonia_locations[filename] = [location]\n\n# View the extracted bounding box information\n# print(pneumonia_locations)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.351841Z","iopub.status.idle":"2025-05-07T07:00:26.35214Z","shell.execute_reply.started":"2025-05-07T07:00:26.351992Z","shell.execute_reply":"2025-05-07T07:00:26.352006Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. Read the DICOM image","metadata":{}},{"cell_type":"code","source":"# Get the paths of all DICOM files\nimage_df = pd.DataFrame({'path': glob.glob(os.path.join(dicom_dir, '*.dcm'))})\nimage_df['patientId'] = image_df['path'].map(lambda x: os.path.splitext(os.path.basename(x))[0])\n\n# Read the file names and shuffle the order\nfilenames = image_df['path'].tolist()\nrandom.shuffle(filenames)\n\n# Divide the training set and the validation set\nn_valid_samples = 2560\ntrain_filenames = filenames[n_valid_samples:]\nvalid_filenames = filenames[:n_valid_samples]\n\nprint('n train samples', len(train_filenames))\nprint('n valid samples', len(valid_filenames))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.353352Z","iopub.status.idle":"2025-05-07T07:00:26.353553Z","shell.execute_reply.started":"2025-05-07T07:00:26.353459Z","shell.execute_reply":"2025-05-07T07:00:26.353467Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3. Image Feature Integration","metadata":{}},{"cell_type":"code","source":"# Assume image_df is your DataFrame containing DICOM file paths and bounding box information\n\n# Extract regions of interest\nextracted_regions = []\nfor c_path_tuple, c_rows in image_df.groupby('patientId'):  # Group by the correct column name\n    c_path = c_path_tuple[0]\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n    c_img_arr = c_dicom.pixel_array\n    \n    for _, c_row in c_rows.dropna().iterrows():  # Iterate through each row\n        x, y, width, height = c_row['x'], c_row['y'], c_row['width'], c_row['height']\n        region = c_img_arr[y:y+height, x:x+width]  # Extract the region\n        extracted_regions.append(region)\n\n# extracted_regions now contains all the extracted regions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.356287Z","iopub.status.idle":"2025-05-07T07:00:26.357014Z","shell.execute_reply.started":"2025-05-07T07:00:26.356801Z","shell.execute_reply":"2025-05-07T07:00:26.35682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Display locations and bounding boxes\nfig, m_axs = plt.subplots(2, 3, figsize=(20, 10))  # Create a 2-row, 3-column subplot\nfor c_ax, (c_path_tuple, c_rows) in zip(m_axs.flatten(), sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n    c_ax.imshow(c_dicom.pixel_array, cmap='bone')  # Display the image\n    c_ax.set_title('{class}'.format(**c_rows.iloc[0, :]))  # Set the title\n    for i, (_, c_row) in enumerate(c_rows.dropna().iterrows()):  # Iterate through each row\n        c_ax.plot(c_row['x'], c_row['y'], 's', label='{class}'.format(**c_row))  # Draw square markers\n        c_ax.add_patch(Rectangle(xy=(c_row['x'], c_row['y']),\n                                  width=c_row['width'],\n                                  height=c_row['height'], \n                                  alpha=0.5))  # Add rectangle box\n        if i == 0: \n            c_ax.legend()  # Show legend only for the first marker","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.358123Z","iopub.status.idle":"2025-05-07T07:00:26.358384Z","shell.execute_reply.started":"2025-05-07T07:00:26.358256Z","shell.execute_reply":"2025-05-07T07:00:26.358271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.applications import VGG16\nfrom keras.applications.vgg16 import preprocess_input\n\n# Load the pre-trained model\nmodel = VGG16(weights='imagenet', include_top=False)\n\n# Extract features\nfeatures = []\nfor region in extracted_regions:\n    region_resized = np.resize(region, (224, 224, 1))  # Resize to the model input size\n    region_resized = preprocess_input(region_resized)  # Preprocess the input\n    feature = model.predict(np.expand_dims(region_resized, axis=0))\n    features.append(feature.flatten())  # Flatten the features","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.359329Z","iopub.status.idle":"2025-05-07T07:00:26.359579Z","shell.execute_reply.started":"2025-05-07T07:00:26.359463Z","shell.execute_reply":"2025-05-07T07:00:26.359475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport matplotlib.pyplot as plt\nfrom matplotlib.patches import Rectangle\nimport pydicom\n\n# Display locations and bounding boxes\nfig, m_axs = plt.subplots(2, 3, figsize=(20, 10))  # Create a 2-row, 3-column subplot\nimage_sizes = []  # To store the file size of each image\n\nfor c_ax, (c_path_tuple, c_rows) in zip(m_axs.flatten(), sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n\n    # Get file size\n    file_size = os.path.getsize(c_path)  # Get file size (in bytes)\n    image_sizes.append(file_size)  # Store the file size\n\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n    c_ax.imshow(c_dicom.pixel_array, cmap='bone')  # Display the image\n    c_ax.set_title('{class}'.format(**c_rows.iloc[0, :]))  # Set the title\n\n    for i, (_, c_row) in enumerate(c_rows.dropna().iterrows()):  # Iterate through each row\n        c_ax.plot(c_row['x'], c_row['y'], 's', label='{class}'.format(**c_row))  # Draw square markers\n        c_ax.add_patch(Rectangle(xy=(c_row['x'], c_row['y']),\n                                  width=c_row['width'],\n                                  height=c_row['height'], \n                                  alpha=0.5))  # Add rectangle box\n        if i == 0: \n            c_ax.legend()  # Show legend only for the first marker\n\n# Print the file size of each image\nfor idx, size in enumerate(image_sizes):\n    print(f'Figure {idx + 1} file size: {size / 1024:.2f} KB')  # Convert to KB\n\n# Show the images\nplt.show()","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.360627Z","iopub.status.idle":"2025-05-07T07:00:26.360936Z","shell.execute_reply.started":"2025-05-07T07:00:26.360784Z","shell.execute_reply":"2025-05-07T07:00:26.360798Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pydicom\nfrom matplotlib.patches import Rectangle\n\n# Create a 6-row, 4-column subplot\nfig, m_axs = plt.subplots(6, 4, figsize=(20, 30))  \nm_axs = m_axs.flatten()  # Flatten the subplots to a 1D array\n\n# Initialize feature region count\nfeature_count = 0\n\nfor img_index, (c_path_tuple, c_rows) in enumerate(sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n\n    # Display a maximum of 4 feature regions per DICOM file\n    local_feature_count = 0\n    \n    for _, c_row in c_rows.dropna().iterrows():  # Iterate through each row\n        # Calculate the bounding box of the feature region, ensuring integers\n        x = int(c_row['x'])\n        y = int(c_row['y'])\n        width = int(c_row['width'])\n        height = int(c_row['height'])\n\n        # Crop the feature region\n        feature_region = c_dicom.pixel_array[y:y + height, x:x + width]\n\n        # Display only if features exist\n        if local_feature_count < 4 and feature_count < len(m_axs):\n            m_axs[feature_count].imshow(feature_region, cmap='bone')\n            m_axs[feature_count].set_title(f'Image {img_index + 1}, Feature {local_feature_count + 1}')\n            m_axs[feature_count].axis('off')  # Turn off axes\n\n            # Add a rectangle\n            m_axs[feature_count].add_patch(Rectangle(xy=(0, 0), \n                                                      width=width,\n                                                      height=height, \n                                                      edgecolor='red', alpha=0.5))  # Draw a red rectangle\n\n            local_feature_count += 1  # Increment local feature count\n            feature_count += 1  # Increment global feature count\n\n    # If fewer than 4 features, leave unused subplots empty\n    while local_feature_count < 4 and feature_count < len(m_axs):\n        m_axs[feature_count].axis('off')  # Turn off axes\n        feature_count += 1\n        local_feature_count += 1\n\n# Output the number of displayed feature images\nprint(f'Number of feature images displayed: {feature_count}')\nplt.tight_layout()  # Adjust subplot spacing\nplt.show()  # Show the figure","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.362225Z","iopub.status.idle":"2025-05-07T07:00:26.362481Z","shell.execute_reply.started":"2025-05-07T07:00:26.362375Z","shell.execute_reply":"2025-05-07T07:00:26.362387Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pydicom\nfrom matplotlib.patches import Rectangle\n\n# Create a 6-row, 4-column subplot\nfig, m_axs = plt.subplots(6, 4, figsize=(20, 30))  \nm_axs = m_axs.flatten()  # Flatten the subplots to a 1D array\n\n# Initialize feature region count and size list\nfeature_count = 0\nfeature_sizes = []  # To store the size of each feature region\n\nfor img_index, (c_path_tuple, c_rows) in enumerate(sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n\n    # Display a maximum of 4 feature regions per DICOM file\n    local_feature_count = 0\n    \n    for _, c_row in c_rows.dropna().iterrows():  # Iterate through each row\n        # Calculate the bounding box of the feature region, ensuring integers\n        x = int(c_row['x'])\n        y = int(c_row['y'])\n        width = int(c_row['width'])\n        height = int(c_row['height'])\n\n        # Crop the feature region\n        feature_region = c_dicom.pixel_array[y:y + height, x:x + width]\n\n        # Display only if features exist\n        if local_feature_count < 4 and feature_count < len(m_axs):\n            m_axs[feature_count].imshow(feature_region, cmap='bone', extent=[0, width, height, 0])\n            m_axs[feature_count].set_title(f'Image {img_index + 1}, Feature {local_feature_count + 1}')\n            m_axs[feature_count].axis('on')  # Show axes\n\n            # Add a rectangle\n            m_axs[feature_count].add_patch(Rectangle(xy=(0, 0), \n                                                      width=width,\n                                                      height=height, \n                                                      edgecolor='red', alpha=0.5))  # Draw a red rectangle\n\n            # Record the size of the feature region\n            feature_sizes.append(feature_region.nbytes)  # Store size in bytes\n\n            local_feature_count += 1  # Increment local feature count\n            feature_count += 1  # Increment global feature count\n\n    # If fewer than 4 features, leave unused subplots empty\n    while local_feature_count < 4 and feature_count < len(m_axs):\n        m_axs[feature_count].axis('off')  # Turn off axes\n        feature_count += 1\n        local_feature_count += 1\n\n# Print the size of each feature image\nfor idx, size in enumerate(feature_sizes):\n    print(f'Feature {idx + 1} size: {size / 1024:.2f} KB')  # Convert to KB\n\n# Output the number of displayed feature images\nprint(f'Number of feature images displayed: {feature_count}')\nplt.tight_layout()  # Adjust subplot spacing\nplt.show()  # Show the figure","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.363595Z","iopub.status.idle":"2025-05-07T07:00:26.363895Z","shell.execute_reply.started":"2025-05-07T07:00:26.363761Z","shell.execute_reply":"2025-05-07T07:00:26.363773Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pydicom\nfrom matplotlib.patches import Rectangle\n\n# Create a 6-row, 4-column subplot\nfig, m_axs = plt.subplots(6, 4, figsize=(20, 30))  \nm_axs = m_axs.flatten()  # Flatten the subplots to a 1D array\n\n# Initialize feature region count\nfeature_count = 0\n\nfor img_index, (c_path_tuple, c_rows) in enumerate(sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n\n    # Display a maximum of 4 feature regions per DICOM file\n    local_feature_count = 0\n    \n    for _, c_row in c_rows.dropna().iterrows():  # Iterate through each row\n        # Calculate the bounding box of the feature region, ensuring integers\n        x = int(c_row['x'])\n        y = int(c_row['y'])\n        width = int(c_row['width'])\n        height = int(c_row['height'])\n\n        # Crop the feature region\n        feature_region = c_dicom.pixel_array[y:y + height, x:x + width]\n\n        # Display only if features exist\n        if local_feature_count < 4 and feature_count < len(m_axs):\n            m_axs[feature_count].imshow(feature_region, cmap='bone', extent=[0, width, height, 0])\n            m_axs[feature_count].set_title(f'Image {img_index + 1}, Feature {local_feature_count + 1}')\n            m_axs[feature_count].axis('on')  # Show axes\n\n            # Add a rectangle\n            m_axs[feature_count].add_patch(Rectangle(xy=(0, 0), \n                                                      width=width,\n                                                      height=height, \n                                                      edgecolor='red', alpha=0.5))  # Draw a red rectangle\n\n            local_feature_count += 1  # Increment local feature count\n            feature_count += 1  # Increment global feature count\n\n    # If fewer than 4 features, leave unused subplots empty\n    while local_feature_count < 4 and feature_count < len(m_axs):\n        m_axs[feature_count].axis('off')  # Turn off axes\n        feature_count += 1\n        local_feature_count += 1\n\n# Output the number of displayed feature images\nprint(f'Number of feature images displayed: {feature_count}')\nplt.tight_layout()  # Adjust subplot spacing\nplt.show()  # Show the figure","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.365585Z","iopub.status.idle":"2025-05-07T07:00:26.365901Z","shell.execute_reply.started":"2025-05-07T07:00:26.36574Z","shell.execute_reply":"2025-05-07T07:00:26.365755Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pydicom\n\n# Read the DICOM file\ndicom_path =  '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images/0004cfab-14fd-4e49-80ba-63a80b6bddd6.dcm'\ndicom_data = pydicom.dcmread(dicom_path)\n\n# Display Image\nplt.figure(figsize=(10, 8)) # The image size can be adjusted as needed\nplt.imshow(dicom_data.pixel_array, cmap='bone') # Use the 'bone' color map\nplt.axis('off') # Turn off the coordinate axes\nplt.title('DICOM Image') # Optional: Add a title\nplt.show() # Display images","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.367347Z","iopub.status.idle":"2025-05-07T07:00:26.367599Z","shell.execute_reply.started":"2025-05-07T07:00:26.36749Z","shell.execute_reply":"2025-05-07T07:00:26.3675Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pydicom\nfrom matplotlib.patches import Rectangle\n\n# Create a 6-row, 4-column subplot\nfig, m_axs = plt.subplots(6, 4, figsize=(20, 30))  \nm_axs = m_axs.flatten()  # Flatten the subplots to a 1D array\n\n# Initialize feature region count and size list\nfeature_count = 0\nfeature_sizes = []  # To store the size of each feature region\n\nfor img_index, (c_path_tuple, c_rows) in enumerate(sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n\n    # Display a maximum of 4 feature regions per DICOM file\n    local_feature_count = 0\n    \n    for _, c_row in c_rows.dropna().iterrows():  # Iterate through each row\n        # Calculate the bounding box of the feature region, ensuring integers\n        x = int(c_row['x'])\n        y = int(c_row['y'])\n        width = int(c_row['width'])\n        height = int(c_row['height'])\n\n        # Crop the feature region\n        feature_region = c_dicom.pixel_array[y:y + height, x:x + width]\n\n        # Display only if features exist\n        if local_feature_count < 4 and feature_count < len(m_axs):\n            m_axs[feature_count].imshow(feature_region, cmap='bone', extent=[0, width, height, 0])\n            # Add feature region size information to the title\n            feature_size_kb = feature_region.nbytes / 1024  # Convert to KB\n            m_axs[feature_count].set_title(f'Image {img_index + 1}, Feature {local_feature_count + 1}\\nSize: {feature_size_kb:.2f} KB')\n            m_axs[feature_count].axis('on')  # Show axes\n\n            # Add a rectangle\n            m_axs[feature_count].add_patch(Rectangle(xy=(0, 0), \n                                                      width=width,\n                                                      height=height, \n                                                      edgecolor='red', alpha=0.5))  # Draw a red rectangle\n\n            local_feature_count += 1  # Increment local feature count\n            feature_count += 1  # Increment global feature count\n\n    # If fewer than 4 features, leave unused subplots empty\n    while local_feature_count < 4 and feature_count < len(m_axs):\n        m_axs[feature_count].axis('off')  # Turn off axes\n        feature_count += 1\n        local_feature_count += 1\n\n# Output the number of displayed feature images\nprint(f'Number of feature images displayed: {feature_count}')\nplt.tight_layout()  # Adjust subplot spacing\nplt.show()  # Show the figure","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.368284Z","iopub.status.idle":"2025-05-07T07:00:26.368572Z","shell.execute_reply.started":"2025-05-07T07:00:26.368423Z","shell.execute_reply":"2025-05-07T07:00:26.368436Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pydicom\n\n# Read the DICOM file\ndicom_path = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images/0004cfab-14fd-4e49-80ba-63a80b6bddd6.dcm'\nc_dicom = pydicom.dcmread(dicom_path)\n\n# Get the original image size\noriginal_image_size_bytes = c_dicom.pixel_array.nbytes\noriginal_image_size_kb = original_image_size_bytes / 1024  # Convert to KB\n\n# Output original image size\nprint(f'Original Image Size: {original_image_size_bytes} bytes ({original_image_size_kb:.2f} KB)')\n\n# Select feature region rows, assuming extraction from DataFrame\n# Here using feature indices 5, 6, 7, 8 as examples; adjust based on data\nfeature_indices = [5, 6, 7, 8]  # Indices of feature regions\nfeature_coordinates = []\n\nfor index in feature_indices:\n    # Get feature region information from DataFrame\n    c_row = sample_df.iloc[index]  # Adjust index as needed\n    x = int(c_row['x'])\n    y = int(c_row['y'])\n    width = int(c_row['width'])\n    height = int(c_row['height'])\n    feature_coordinates.append((x, y, width, height))\n\nfor idx, (x, y, width, height) in enumerate(feature_coordinates):\n    # Crop the feature region\n    feature_region = c_dicom.pixel_array[y:y + height, x:x + width]\n\n    # Calculate the size of the feature region\n    feature_size_bytes = feature_region.nbytes\n    feature_size_kb = feature_size_bytes / 1024  # Convert to KB\n\n    # Output information\n    print(f'Feature {idx + 5} Size: {feature_size_bytes} bytes ({feature_size_kb:.2f} KB)')\n    print(f'Feature {idx + 5} Dimensions: {feature_region.shape}')  # Output feature region dimensions\n    print(f'Pixel Data Type: {feature_region.dtype}')  # Output pixel data type","metadata":{"trusted":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-05-07T07:00:26.369943Z","iopub.status.idle":"2025-05-07T07:00:26.37025Z","shell.execute_reply.started":"2025-05-07T07:00:26.3701Z","shell.execute_reply":"2025-05-07T07:00:26.370113Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pydicom\nfrom skimage.transform import resize\n\n# Define target size and storage structure\nTARGET_SIZE = (128, 128)  # Adjust based on actual requirements\nFEATURE_MATRIX = []\nMAX_FEATURES_PER_IMAGE = 4\n\nfor img_index, (c_path_tuple, c_rows) in enumerate(sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]\n    dicom_data = pydicom.dcmread(c_path)\n    pixel_array = dicom_data.pixel_array\n    \n    # Store features for the current image\n    image_features = []\n    \n    for _, row in c_rows.dropna().iterrows():\n        if len(image_features) >= MAX_FEATURES_PER_IMAGE:\n            break\n            \n        # Extract feature region\n        x = int(row['x'])\n        y = int(row['y'])\n        w = int(row['width'])\n        h = int(row['height'])\n        feature_region = pixel_array[y:y+h, x:x+w]\n        \n        # Normalize processing\n        processed_feature = resize(feature_region, TARGET_SIZE, preserve_range=True)\n        processed_feature = (processed_feature - np.mean(processed_feature)) / np.std(processed_feature)\n        \n        image_features.append(processed_feature)\n    \n    # Fill in insufficient features\n    while len(image_features) < MAX_FEATURES_PER_IMAGE:\n        image_features.append(np.zeros(TARGET_SIZE))  # Zero padding\n        \n    # Add to the main matrix\n    FEATURE_MATRIX.append(np.stack(image_features))\n\n# Convert to NumPy array\nFEATURE_MATRIX = np.array(FEATURE_MATRIX)\nprint(f\"Generated feature matrix shape: {FEATURE_MATRIX.shape}\")  # (X, 4, H, W)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.371394Z","iopub.status.idle":"2025-05-07T07:00:26.371688Z","shell.execute_reply.started":"2025-05-07T07:00:26.371537Z","shell.execute_reply":"2025-05-07T07:00:26.37155Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 4. dataloader","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pydicom\nimport pandas as pd\nfrom skimage.transform import resize\nfrom tqdm import tqdm\nimport os\n\n# Configuration parameters\nMAX_FEATURES_PER_IMAGE = 4\nTARGET_SIZE = (128, 128)\nNORMALIZE_MODE = 'standard'\nSAFE_MODE = True  # Safe mode to handle exceptional values automatically\n\ndef safe_int_convert(value, default=0):\n    \"\"\"Safely convert value to integer.\"\"\"\n    try:\n        return int(float(value))\n    except (ValueError, TypeError):\n        return default\n\ndef process_features(df):\n    # Preallocate matrix memory (adjust based on actual data volume)\n    total_images = len(df['path'].unique())\n    feature_matrix = np.zeros((total_images, MAX_FEATURES_PER_IMAGE, *TARGET_SIZE), dtype=np.float32)\n    \n    valid_image_count = 0\n    \n    for img_idx, (c_path_tuple, c_rows) in enumerate(tqdm(df.groupby('path'), desc='Processing DICOMs')):\n        try:\n            c_path = c_path_tuple[0] if isinstance(c_path_tuple, (tuple, list)) else c_path_tuple\n            \n            if not os.path.isfile(c_path):\n                continue\n                \n            dicom_data = pydicom.dcmread(c_path)\n            pixel_array = dicom_data.pixel_array.astype(np.float32)\n            \n            # Process all features of the current image\n            feature_count = 0\n            for _, row in c_rows.iterrows():\n                if feature_count >= MAX_FEATURES_PER_IMAGE:\n                    break\n                \n                # Safely convert coordinates (handle NaN)\n                x = safe_int_convert(row.get('x'))\n                y = safe_int_convert(row.get('y'))\n                w = max(safe_int_convert(row.get('width')), 1)\n                h = max(safe_int_convert(row.get('height')), 1)\n                \n                # Validate coordinate effectiveness\n                if SAFE_MODE:\n                    h_max, w_max = pixel_array.shape\n                    x = min(max(x, 0), w_max - 1)\n                    y = min(max(y, 0), h_max - 1)\n                    w = min(w, w_max - x)\n                    h = min(h, h_max - y)\n                \n                try:\n                    feature = pixel_array[y:y+h, x:x+w]\n                    resized_feature = resize(feature, TARGET_SIZE, preserve_range=True)\n                    \n                    # Normalization\n                    if NORMALIZE_MODE == 'standard':\n                        eps = 1e-8\n                        resized_feature = (resized_feature - np.mean(resized_feature)) / (np.std(resized_feature) + eps)\n                    elif NORMALIZE_MODE == 'zero_one':\n                        f_min, f_max = np.min(resized_feature), np.max(resized_feature)\n                        resized_feature = (resized_feature - f_min) / (f_max - f_min + 1e-8)\n                    \n                    feature_matrix[valid_image_count, feature_count] = resized_feature\n                    feature_count += 1\n                    \n                except Exception as feat_error:\n                    if not SAFE_MODE:\n                        raise\n                    continue\n            \n            valid_image_count += 1\n            \n        except Exception as img_error:\n            print(f\"Skipped {c_path}: {str(img_error)}\")\n            continue\n    \n    # Trim to the actual valid image count\n    return feature_matrix[:valid_image_count]\n\n# Usage example\nif __name__ == \"__main__\":\n    # Assume sample_df is your DataFrame\n    feature_matrix = process_features(sample_df)\n    \n    # Save results\n    np.save('pneumonia_features.npy', feature_matrix)\n    \n    print(f\"Successfully processed image count: {feature_matrix.shape[0]}\")\n    print(f\"Final matrix shape: {feature_matrix.shape}\")  # (N_valid, 4, 128, 128)\n    print(f\"Memory usage: {feature_matrix.nbytes / 1024**3:.2f} GB\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.372972Z","iopub.status.idle":"2025-05-07T07:00:26.373285Z","shell.execute_reply.started":"2025-05-07T07:00:26.373135Z","shell.execute_reply":"2025-05-07T07:00:26.373148Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Integration of Old and New Features\nDCM_TAG_LIST = ['PatientAge', 'BodyPartExamined', 'ViewPosition', 'PatientSex']\n\ndef get_tags(in_path):\n    c_dicom = pydicom.dcmread(in_path, stop_before_pixels=False) # Read the DICOM file\n    tag_dict = {c_tag: getattr(c_dicom, c_tag, '') for c_tag in DCM_TAG_LIST}\n    tag_dict['path'] = in_path\n    return pd.Series(tag_dict)\n\n# Extract the metadata of each image\nimage_meta_df = image_df.apply(lambda x: get_tags(x['path']), axis=1)\n\n# Display the histogram\nimage_meta_df['PatientAge'] = image_meta_df['PatientAge'].map(int) # Convert to integer type\nimage_meta_df['PatientAge'].hist() # Draw the histogram\n\n# Generate sample_df and select the first sample of each combination\nsample_df = image_bbox_df.groupby(['Target', 'class', 'boxes']).first().reset_index()\n\n# Check Results\nprint(sample_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.374701Z","iopub.status.idle":"2025-05-07T07:00:26.37499Z","shell.execute_reply.started":"2025-05-07T07:00:26.374841Z","shell.execute_reply":"2025-05-07T07:00:26.374854Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(sample_df.shape)\nprint(sample_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.37568Z","iopub.status.idle":"2025-05-07T07:00:26.375976Z","shell.execute_reply.started":"2025-05-07T07:00:26.375818Z","shell.execute_reply":"2025-05-07T07:00:26.375831Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DCM_TAG_LIST = ['PatientAge', 'BodyPartExamined', 'ViewPosition', 'PatientSex']\n\ndef get_tags(in_path):\n    c_dicom = pydicom.dcmread(in_path, stop_before_pixels=False)\n    tag_dict = {c_tag: getattr(c_dicom, c_tag, '') for c_tag in DCM_TAG_LIST}\n    tag_dict['path'] = in_path\n    return pd.Series(tag_dict)\n\nimage_meta_df = image_df.head(1000).apply(lambda x: get_tags(x['path']), axis=1)\nimage_meta_df['PatientAge'] = image_meta_df['PatientAge'].map(int)\nsample_df = image_bbox_df.copy()\nsample_df = sample_df[sample_df['path'].isin(image_meta_df['path'])]\nprint(sample_df.isnull().sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.377072Z","iopub.status.idle":"2025-05-07T07:00:26.377345Z","shell.execute_reply.started":"2025-05-07T07:00:26.377221Z","shell.execute_reply":"2025-05-07T07:00:26.377235Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pydicom\n\n# Assume sample_df is your DataFrame containing DICOM file paths and feature region information\n# Initialize the maximum number of feature regions\nmax_features_per_image = 4\n\n# Calculate the required number of rows\nnum_images = len(sample_df.groupby(['path']))\nfeature_matrix = np.zeros((num_images, max_features_per_image, 256, 256))  # Assume feature region size is 256x256\n\n# Initialize feature region count\nfeature_count = 0\n\nfor img_index, (c_path_tuple, c_rows) in enumerate(sample_df.groupby(['path'])):\n    c_path = c_path_tuple[0]  # Get the first element of the tuple\n    print(f'Loading DICOM file from path: {c_path}')  # Debug information\n    c_dicom = pydicom.dcmread(c_path)  # Read the DICOM file\n\n    # Display a maximum of 4 feature regions per DICOM file\n    local_feature_count = 0\n    \n    for _, c_row in c_rows.dropna().iterrows():  # Iterate through each row\n        # Calculate the bounding box of the feature region, ensuring integers\n        x = int(c_row['x'])\n        y = int(c_row['y'])\n        width = int(c_row['width'])\n        height = int(c_row['height'])\n\n        # Crop the feature region\n        feature_region = c_dicom.pixel_array[y:y + height, x:x + width]\n\n        # Ensure the feature region size is 256x256, padding or cropping as needed\n        if feature_region.shape != (256, 256):\n            feature_region = np.resize(feature_region, (256, 256))  # Resize to appropriate dimensions, or use another method\n\n        # Store only if features exist\n        if local_feature_count < max_features_per_image:\n            feature_matrix[img_index, local_feature_count] = feature_region\n            local_feature_count += 1  # Increment local feature count\n\n    # If fewer than 4 features, fill unused feature regions with zeros\n    while local_feature_count < max_features_per_image:\n        feature_matrix[img_index, local_feature_count] = np.zeros((256, 256))  # Zero padding\n        local_feature_count += 1\n\n# Output the shape of the feature matrix\nprint(f'Feature matrix shape: {feature_matrix.shape}')","metadata":{"trusted":true,"scrolled":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.378362Z","iopub.status.idle":"2025-05-07T07:00:26.378556Z","shell.execute_reply.started":"2025-05-07T07:00:26.378464Z","shell.execute_reply":"2025-05-07T07:00:26.378472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pydicom\nimport numpy as np\nfrom PIL import Image\n\n# Suppose sample_df is your data frame, containing the path of the DICOM file\nimage_list = []\n\nfor c_path in sample_df['path']:\n    print(f'Loading DICOM file from path: {c_path}')\n    c_dicom = pydicom.dcmread(c_path)\n    \n    # Convert the image data to uint8\n    image = c_dicom.pixel_array\n    image_resized = Image.fromarray(image).resize((128, 128))\n    image_resized = np.array(image_resized)\n    \n    # Convert the image data to uint8\n    image_resized = (image_resized - np.min(image_resized)) / (np.max(image_resized) - np.min(image_resized)) * 255\n    image_resized = image_resized.astype(np.uint8)\n    \n    # Add images to the list\n    image_list.append(image_resized)\n    \n    # Clear Memory\n    del c_dicom, image, image_resized\n\n# Convert the list to a NumPy array\nimage_array = np.array(image_list)\n\nprint(f'Image array shape: {image_array.shape}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.379616Z","iopub.status.idle":"2025-05-07T07:00:26.379942Z","shell.execute_reply.started":"2025-05-07T07:00:26.379775Z","shell.execute_reply":"2025-05-07T07:00:26.379789Z"},"scrolled":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pydicom\nimport numpy as np\nimport torch\nfrom torchvision import transforms\n\n# Assume sample_df is your DataFrame containing DICOM file paths\nimage_list = []\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\ntransform = transforms.Compose([\n    transforms.ToPILImage(),\n    transforms.Resize((128, 128)),\n    transforms.ToTensor(),  # Convert to tensor and normalize to [0, 1]\n    transforms.Lambda(lambda x: (x * 255).byte()),  # Convert to uint8\n])\n\nfor c_path in sample_df['path']:\n    print(f'Loading DICOM file from path: {c_path}')\n    c_dicom = pydicom.dcmread(c_path)\n\n    # Convert image data to tensor and move to GPU\n    image = torch.tensor(c_dicom.pixel_array, device=device)\n    image_resized = transform(image)\n\n    # Append the image to the list\n    image_list.append(image_resized.cpu().numpy())  # Move back to CPU for further processing\n\n    # Clean up memory\n    del c_dicom, image\n\n# Convert list to NumPy array\nimage_array = np.array(image_list)\n\nprint(f'Image array shape: {image_array.shape}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.380735Z","iopub.status.idle":"2025-05-07T07:00:26.381023Z","shell.execute_reply.started":"2025-05-07T07:00:26.380875Z","shell.execute_reply":"2025-05-07T07:00:26.380888Z"},"scrolled":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pydicom\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torchvision.models as models\nimport torchvision.transforms as T\nfrom PIL import Image\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nresnet = models.resnet18(weights='ResNet18_Weights.DEFAULT')\nresnet.fc = torch.nn.Identity()\nresnet = resnet.to(device).eval()\n\ntransform = T.Compose([\n    T.Resize((128, 128)),\n    T.ToTensor(),\n    T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\nall_features = []\npaths = []\n\nfor idx, row in sample_df.iterrows():\n    if pd.isna(row['x']) or pd.isna(row['y']) or pd.isna(row['width']) or pd.isna(row['height']):\n        continue\n\n    dicom = pydicom.dcmread(row['path'])\n    img = dicom.pixel_array.astype(np.float32)\n\n    x, y, w, h = map(int, [row['x'], row['y'], row['width'], row['height']])\n    cropped = img[y:y+h, x:x+w]\n\n    cropped = (cropped - np.min(cropped)) / (np.max(cropped) - np.min(cropped) + 1e-5)\n    pil = Image.fromarray((cropped * 255).astype(np.uint8))\n\n    # Convert grayscale images to RGB images\n    pil = pil.convert(\"RGB\")\n\n    tensor = transform(pil).unsqueeze(0).to(device)\n    with torch.no_grad():\n        feat = resnet(tensor).cpu()\n\n    all_features.append(feat.squeeze(0).numpy())\n    paths.append(row['path'])\n\nnp.save('bbox_features.npy', np.stack(all_features))\npd.DataFrame({'path': paths}).to_csv('bbox_paths.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.38208Z","iopub.status.idle":"2025-05-07T07:00:26.38238Z","shell.execute_reply.started":"2025-05-07T07:00:26.382227Z","shell.execute_reply":"2025-05-07T07:00:26.38224Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"build tabular.csv","metadata":{}},{"cell_type":"code","source":"import os\nimport pydicom\nimport pandas as pd\n\n# List all DICOM files in the directory\ndcm_files = [f for f in os.listdir(dicom_dir) if f.endswith('.dcm')]\n\ndata = []\n\nfor fname in dcm_files:\n    dcm_path = os.path.join(dicom_dir, fname)\n    ds = pydicom.dcmread(dcm_path)\n\n    # Retrieve basic fields\n    sex = ds.get(('0010', '0040'), 'N').value if ('0010', '0040') in ds else 'N'\n    age_str = ds.get(('0010', '1010'), '0Y').value if ('0010', '1010') in ds else '0Y'\n    age = int(age_str[:-1]) if age_str.endswith('Y') else 0\n    view_pos = ds.get(('0018', '5101'), 'UNK').value if ('0018', '5101') in ds else 'UNK'\n    rows = int(ds.get(('0028', '0010'), 0).value)\n    cols = int(ds.get(('0028', '0011'), 0).value)\n    spacing = ds.get(('0028', '0030'), ['0.0', '0.0'])\n\n    data.append({\n        'filename': fname,  # Save the filename\n        'sex': 1 if sex == 'M' else 0,\n        'age': age,\n        'view_pos': 1 if view_pos == 'PA' else 0,  # Example binary classification\n        'rows': rows,\n        'cols': cols,\n        'spacing_x': float(spacing[0]),\n        'spacing_y': float(spacing[1])\n    })\n\n# Save all information as a CSV file\ntabular_df = pd.DataFrame(data)\ntabular_df.to_csv('tabular.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.383392Z","iopub.status.idle":"2025-05-07T07:00:26.383608Z","shell.execute_reply.started":"2025-05-07T07:00:26.383509Z","shell.execute_reply":"2025-05-07T07:00:26.383518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load feature vectors + table data\nimage_feat = np.load('bbox_features.npy')  # shape [N, 512]\ntabular_feat = pd.read_csv('tabular.csv').values # Suppose shape [N, T]\n\n# Splicing\nX = np.concatenate([image_feat, tabular_feat], axis=1)\ny = pd.read_csv('labels.csv')['target'].values\n\nIt can be trained with either PyTorch or LightGBM","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.384531Z","iopub.status.idle":"2025-05-07T07:00:26.384816Z","shell.execute_reply.started":"2025-05-07T07:00:26.384657Z","shell.execute_reply":"2025-05-07T07:00:26.384673Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport torch\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score\nfrom torch.utils.data import DataLoader, TensorDataset\n\n# Load image features and paths\nbbox_features = np.load('bbox_features.npy') # Image features\nbbox_paths = pd.read_csv('bbox_paths.csv')['path'].values # Image paths\n\n# Load table data\ntabular_df = pd.read_csv('tabular.csv') # Table data\ntabular_feat = tabular_df.drop(columns=['filename']).values # Get the features of the table data\n\n# Ensure feature matching, assuming that image features and table features are aligned by path\nHere, alignment is achieved through the path (filename), and there is no need for explicit matching. It is assumed that the order is consistent\n# If alignment is required, please ensure that 'filename' exists in tabular.csv and bbox_paths\n\n# Stitching image features and table features\nX = np.concatenate([bbox_features, tabular_feat], axis=1) # concatenate image features and table features\n\n# Load label data\ny = pd.read_csv('labels.csv')['target'].values # Suppose the labels are stored in the labels.csv file","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:00:26.385732Z","iopub.status.idle":"2025-05-07T07:00:26.385946Z","shell.execute_reply.started":"2025-05-07T07:00:26.385844Z","shell.execute_reply":"2025-05-07T07:00:26.385854Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Animation","metadata":{}},{"cell_type":"code","source":"import os\nimport json\nimport glob\nimport random\nimport collections\n\nimport numpy as np\nimport pandas as pd\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:09:41.335242Z","iopub.execute_input":"2025-05-07T07:09:41.335809Z","iopub.status.idle":"2025-05-07T07:09:42.196484Z","shell.execute_reply.started":"2025-05-07T07:09:41.335783Z","shell.execute_reply":"2025-05-07T07:09:42.195932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_dicom(path):\n    dicom = pydicom.read_file(path)\n    data = dicom.pixel_array\n    data = data - np.min(data)\n    if np.max(data) != 0:\n        data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    return data\n\n\ndef visualize_sample(\n    brats21id, \n    slice_i,\n    mgmt_value,\n    types=(\"FLAIR\", \"T1w\", \"T1wCE\", \"T2w\")\n):\n    plt.figure(figsize=(16, 5))\n    patient_path = os.path.join(\n        \"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train/\", \n        str(brats21id).zfill(5),\n    )\n    for i, t in enumerate(types, 1):\n        t_paths = sorted(\n            glob.glob(os.path.join(patient_path, t, \"*\")), \n            key=lambda x: int(x[:-4].split(\"-\")[-1]),\n        )\n        data = load_dicom(t_paths[int(len(t_paths) * slice_i)])\n        plt.subplot(1, 4, i)\n        plt.imshow(data, cmap=\"gray\")\n        plt.title(f\"{t}\", fontsize=16)\n        plt.axis(\"off\")\n\n    plt.suptitle(f\"MGMT_value: {mgmt_value}\", fontsize=16)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:11:50.846298Z","iopub.execute_input":"2025-05-07T07:11:50.846587Z","iopub.status.idle":"2025-05-07T07:11:50.853082Z","shell.execute_reply.started":"2025-05-07T07:11:50.846566Z","shell.execute_reply":"2025-05-07T07:11:50.852352Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls /kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:15:12.497645Z","iopub.execute_input":"2025-05-07T07:15:12.49821Z","iopub.status.idle":"2025-05-07T07:15:12.870013Z","shell.execute_reply.started":"2025-05-07T07:15:12.498179Z","shell.execute_reply":"2025-05-07T07:15:12.869298Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.read_csv(\"/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:13:25.040119Z","iopub.execute_input":"2025-05-07T07:13:25.040819Z","iopub.status.idle":"2025-05-07T07:13:25.075308Z","shell.execute_reply.started":"2025-05-07T07:13:25.040795Z","shell.execute_reply":"2025-05-07T07:13:25.074494Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from matplotlib import animation, rc\nrc('animation', html='jshtml')\n\n\ndef create_animation(ims):\n    fig = plt.figure(figsize=(6, 6))\n    plt.axis('off')\n    im = plt.imshow(ims[0], cmap=\"gray\")\n\n    def animate_func(i):\n        im.set_array(ims[i])\n        return [im]\n\n    return animation.FuncAnimation(fig, animate_func, frames = len(ims), interval = 1000//24)\n    \ndef load_dicom_line(path):\n    t_paths = sorted(\n        glob.glob(os.path.join(path, \"*\")), \n        key=lambda x: int(x[:-4].split(\"-\")[-1]),\n    )\n    images = []\n    for filename in t_paths:\n        data = load_dicom(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n        \n    return images","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:13:51.411349Z","iopub.execute_input":"2025-05-07T07:13:51.411646Z","iopub.status.idle":"2025-05-07T07:13:51.418588Z","shell.execute_reply.started":"2025-05-07T07:13:51.411617Z","shell.execute_reply":"2025-05-07T07:13:51.417988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images = load_dicom_line(\"/input/rsna-miccai-brain-tumor-radiogenomic-classification/train/00000/FLAIR\")\ncreate_animation(images)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T07:14:23.954456Z","iopub.execute_input":"2025-05-07T07:14:23.954722Z","iopub.status.idle":"2025-05-07T07:14:24.015845Z","shell.execute_reply.started":"2025-05-07T07:14:23.954706Z","shell.execute_reply":"2025-05-07T07:14:24.014863Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}