{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"}],"dockerImageVersionId":30787,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install ultralytics","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-11-06T13:26:29.672367Z","iopub.execute_input":"2024-11-06T13:26:29.672694Z","iopub.status.idle":"2024-11-06T13:26:43.757374Z","shell.execute_reply.started":"2024-11-06T13:26:29.672655Z","shell.execute_reply":"2024-11-06T13:26:43.756142Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport numpy as np \nimport pandas as pd \n\nimport cv2\nimport pydicom\nfrom PIL import Image\nfrom IPython.display import Image as IPyImage, display\n\nimport os\nimport re\nimport glob\nimport random\nfrom tqdm import tqdm\n\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nsns.set(style=\"whitegrid\")\n\nimport torch\nfrom torch import nn\nimport torch.nn.functional as F\nfrom torch.optim import AdamW\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\n\nfrom sklearn.model_selection import train_test_split\n\nfrom torchvision import transforms\nimport timm\n\nimport yaml\n\nimport albumentations as A\n\nfrom sklearn.model_selection import KFold\n\nfrom ultralytics import YOLO","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:26:43.759885Z","iopub.execute_input":"2024-11-06T13:26:43.760747Z","iopub.status.idle":"2024-11-06T13:26:52.003707Z","shell.execute_reply.started":"2024-11-06T13:26:43.760697Z","shell.execute_reply":"2024-11-06T13:26:52.002741Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train.csv')\nlabel_coords_df = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_label_coordinates.csv')\nseries_desc_df = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_series_descriptions.csv')","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:26:52.004907Z","iopub.execute_input":"2024-11-06T13:26:52.005490Z","iopub.status.idle":"2024-11-06T13:26:52.172833Z","shell.execute_reply.started":"2024-11-06T13:26:52.005423Z","shell.execute_reply":"2024-11-06T13:26:52.171989Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Getting a list of all the study IDs and paths to their images\nimages_dir_path = r'/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images'\nstudy_id_list = os.listdir(images_dir_path)\nstudy_id_paths = [(x, f\"{images_dir_path}/{x}\") for x in study_id_list]\n\n# Initialize the metadata dictionary\nmeta_df = {}\n\n# Process each study and its series\nfor study_id, study_folder_path in study_id_paths:\n    series_ids = []\n    series_descriptions = []\n    \n    # Get all the series IDs (folders) within the study folder\n    try:\n        series_folders = os.listdir(study_folder_path)\n    except FileNotFoundError as e:\n        print(f\"Error: Folder not found for study {study_id}. Skipping this study.\")\n        continue  # Skip this study if the folder doesn't exist\n\n    # Process each series in the study folder\n    for series_id in series_folders:\n        try:\n            # Fetch the series description from the dataframe\n            series_description = series_desc_df[series_desc_df['series_id'] == int(series_id)]['series_description'].iloc[0]\n        except (IndexError, ValueError):\n            # Handle cases where series_id is not found in the dataframe or can't be converted to int\n            series_description = 'Unknown'\n\n        # Append series ID and description to the lists\n        series_ids.append(series_id)\n        series_descriptions.append(series_description)\n    \n    # Add metadata for the current study_id\n    meta_df[int(study_id)] = {\n        'folder_path': study_folder_path,\n        'series_ids': series_ids,\n        'series_descriptions': series_descriptions\n    }\n","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:26:52.174832Z","iopub.execute_input":"2024-11-06T13:26:52.175160Z","iopub.status.idle":"2024-11-06T13:27:07.411929Z","shell.execute_reply.started":"2024-11-06T13:26:52.175125Z","shell.execute_reply":"2024-11-06T13:27:07.410991Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def add_desc(df, meta_df):\n    df['series_desc'] = None\n\n    # Iterate over rows in the dataframe\n    for idx, coor_row in df.iterrows():\n        try:\n            # Find the meta_df for the study_id\n            meta_info = meta_df[int(coor_row['study_id'])]\n\n            # Find the index of the series_id in the meta_info\n            series_index = meta_info['series_ids'].index(str(coor_row['series_id']))\n\n            # Get the corresponding series description\n            series_desc = meta_info['series_descriptions'][series_index]\n\n            # Update the series_desc column\n            df.at[idx, 'series_desc'] = series_desc\n\n        except KeyError:\n            print(f\"Error processing study_id: {coor_row['study_id']} - Study ID not found in meta_df\")\n            df.at[idx, 'series_desc'] = 'Unknown'\n        except ValueError:\n            print(f\"Error processing study_id: {coor_row['study_id']} - Series ID not found in meta_df\")\n            df.at[idx, 'series_desc'] = 'Unknown'\n        except Exception as e:\n            print(f\"Error processing study_id: {coor_row['study_id']} - {e}\")\n            df.at[idx, 'series_desc'] = 'Unknown'\n    \n    return df\n\n# Apply the function\ncoords_with_desc = label_coords_df.copy()\ncoords_with_desc = add_desc(coords_with_desc, meta_df)\ncoords_with_desc.head(20)\n","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:27:07.413531Z","iopub.execute_input":"2024-11-06T13:27:07.414289Z","iopub.status.idle":"2024-11-06T13:27:11.318311Z","shell.execute_reply.started":"2024-11-06T13:27:07.414234Z","shell.execute_reply":"2024-11-06T13:27:11.317409Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sagt1_df = coords_with_desc[coords_with_desc['series_desc'] == 'Sagittal T1'].copy()\nsagt2_df = coords_with_desc[coords_with_desc['series_desc'] == 'Sagittal T2/STIR'].copy()\naxialt2_df = coords_with_desc[coords_with_desc['series_desc'] == 'Axial T2'].copy()","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:27:11.319854Z","iopub.execute_input":"2024-11-06T13:27:11.320265Z","iopub.status.idle":"2024-11-06T13:27:11.362962Z","shell.execute_reply.started":"2024-11-06T13:27:11.320219Z","shell.execute_reply":"2024-11-06T13:27:11.362256Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AxialT2_YOLO:\n    def __init__(self, df, images_dir, output_dir, img_size=384):\n        \"\"\"\n        Initialize Axial T2 YOLO detector\n        Args:\n            df: DataFrame with annotations\n            images_dir: Path to DICOM images\n            output_dir: Path to save processed dataset\n            img_size: Target image size for YOLO\n        \"\"\"\n        self.df = df\n        self.images_dir = images_dir\n        self.output_dir = output_dir\n        self.img_size = img_size\n        \n        # Create initial directory structure\n        self.create_dataset_structure()\n        \n        # Process dataset\n        self.processed_records = self.process_instance_coordinates()\n        self.processed_df = self.process_spine_dataset()\n        \n        # Create YAML and train model\n        self.yaml_path = self.create_dataset_yaml()\n        self.model, self.results = self.train_yolo()\n\n    def create_dataset_structure(self):\n        \"\"\"Create YOLO dataset directory structure\"\"\"\n        for split in ['train', 'val']:\n            for subdir in ['images', 'labels']:\n                path = os.path.join(self.output_dir, split, subdir)\n                os.makedirs(path, exist_ok=True)\n\n    def process_instance_coordinates(self):\n        \"\"\"\n        Process coordinates for Axial images, creating separate records for each level\n        that has both left and right coordinates\n        Returns list of records with coordinates for each complete level\n        \"\"\"\n        result_records = []\n\n        # Group by instance to process each image separately\n        for (study_id, series_id, instance_number), instance_data in self.df.groupby(['study_id', 'series_id', 'instance_number']):\n            # Process each level separately\n            levels_data = {}\n            \n            for _, row in instance_data.iterrows():\n                level = row['level']\n                condition = row['condition']\n                x, y = row['x'], row['y']\n                \n                if level not in levels_data:\n                    levels_data[level] = {'left': None, 'right': None}\n                \n                if 'Left' in condition:\n                    levels_data[level]['left'] = (x, y)\n                elif 'Right' in condition:\n                    levels_data[level]['right'] = (x, y)\n            \n            # Only create records for levels with both coordinates\n            for level, coords in levels_data.items():\n                if coords['left'] is not None and coords['right'] is not None:\n                    record = {\n                        'study_id': study_id,\n                        'series_id': series_id,\n                        'instance_number': instance_number,\n                        'level': level,\n                        'left_coord': coords['left'],\n                        'right_coord': coords['right']\n                    }\n                    result_records.append(record)\n        \n        # Print statistics\n        print(\"\\nDataset Statistics:\")\n        total_complete = len(result_records)\n        \n        print(f\"Total complete level pairs: {total_complete}\")\n        print(\"\\nBy level statistics:\")\n        \n        for level in ['L1/L2', 'L2/L3', 'L3/L4', 'L4/L5', 'L5/S1']:\n            level_count = sum(1 for r in result_records if r['level'] == level)\n            if total_complete > 0:\n                percentage = (level_count / total_complete) * 100\n            else:\n                percentage = 0\n            print(f\"{level}: {level_count} complete pairs ({percentage:.1f}%)\")\n        \n        return result_records\n\n    def create_yolo_annotation(self, record, image_width, image_height):\n        \"\"\"\n        Create YOLO format annotations for a specific level\n        Returns list of annotations for left and right sides\n        \"\"\"\n        annotations = []\n        box_width = 0.05\n        box_height = 0.05\n        \n        # Both coordinates must be present\n        x, y = record['left_coord']\n        x_norm = x / image_width\n        y_norm = y / image_height\n        annotations.append(f\"0 {x_norm:.6f} {y_norm:.6f} {box_width:.6f} {box_height:.6f}\")\n        \n        x, y = record['right_coord']\n        x_norm = x / image_width\n        y_norm = y / image_height\n        annotations.append(f\"1 {x_norm:.6f} {y_norm:.6f} {box_width:.6f} {box_height:.6f}\")\n        \n        return annotations\n\n    def process_spine_dataset(self):\n        \"\"\"Process and save dataset in YOLO format\"\"\"\n        # Split studies\n        studies = set(record['study_id'] for record in self.processed_records)\n        train_studies, val_studies = train_test_split(list(studies), train_size=0.8, random_state=42)\n        \n        processed_counts = {'train': 0, 'val': 0}\n        failed_cases = []\n        \n        for record in tqdm(self.processed_records, desc=\"Processing Axial images\"):\n            try:\n                study_id = str(int(record['study_id']))\n                series_id = str(int(record['series_id']))\n                instance_number = str(int(record['instance_number']))\n                level = record['level'].lower().replace('/', '_')\n                \n                # Construct image path\n                img_path = os.path.join(self.images_dir, study_id, series_id, f\"{instance_number}.dcm\")\n                if not os.path.exists(img_path):\n                    img_path = os.path.join(self.images_dir, study_id, series_id, instance_number)\n                    if os.path.exists(img_path + '.dcm'):\n                        img_path = img_path + '.dcm'\n                    else:\n                        raise FileNotFoundError(f\"Image not found: {img_path}\")\n                \n                # Read and process image\n                ds = pydicom.dcmread(img_path)\n                image = ds.pixel_array\n                h, w = image.shape\n                \n                # Create annotations\n                annotations = self.create_yolo_annotation(record, w, h)\n                \n                # Prepare image\n                image_normalized = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)\n                image_resized = cv2.resize(image_normalized, (self.img_size, self.img_size))\n                \n                # Determine split\n                is_train = record['study_id'] in train_studies\n                split = 'train' if is_train else 'val'\n                \n                # Create unique filenames including level information\n                base_filename = f\"{study_id}_{series_id}_{instance_number}_{level}\"\n                img_filename = f\"{base_filename}.png\"\n                label_filename = f\"{base_filename}.txt\"\n                \n                # Save files\n                cv2.imwrite(os.path.join(self.output_dir, split, 'images', img_filename), \n                           image_resized)\n                with open(os.path.join(self.output_dir, split, 'labels', label_filename), 'w') as f:\n                    f.write('\\n'.join(annotations))\n                \n                processed_counts[split] += 1\n                \n            except Exception as e:\n                failed_cases.append((study_id, series_id, instance_number, str(e)))\n        \n        print(f\"\\nProcessing Summary:\")\n        print(f\"Training images: {processed_counts['train']}\")\n        print(f\"Validation images: {processed_counts['val']}\")\n        \n        if failed_cases:\n            print(\"\\nFailed cases:\")\n            for case in failed_cases:\n                print(f\"Study {case[0]}, Series {case[1]}, Instance {case[2]}: {case[3]}\")\n        \n        return pd.DataFrame(self.processed_records)\n\n    def create_dataset_yaml(self):\n        \"\"\"Create YOLO dataset configuration file\"\"\"\n        yaml_content = {\n            'path': os.path.abspath(self.output_dir),\n            'train': 'train/images',\n            'val': 'val/images',\n            'nc': 2,  # number of classes (left and right)\n            'names': {\n                0: 'left',\n                1: 'right'\n            }\n        }\n\n        yaml_path = os.path.join(self.output_dir, 'dataset.yaml')\n        with open(yaml_path, 'w') as f:\n            yaml.dump(yaml_content, f, sort_keys=False)\n\n        return yaml_path\n\n    def train_yolo(self):\n        \"\"\"Train YOLO model\"\"\"\n        try:\n            model = YOLO('yolov8x.pt')\n            \n            config = {\n                'data': self.yaml_path,\n                'imgsz': self.img_size,\n                'batch': 16,\n                'epochs': 120,\n                'patience': 15,\n                'device': '0',\n                'workers': 8,\n                'project': 'spine_detection',\n                'name': 'axial_t2_yolo',\n                'exist_ok': True,\n                'pretrained': True,\n                'optimizer': 'AdamW',\n                'verbose': True,\n                'seed': 42,\n                'deterministic': True,\n                'dropout': 0.2,\n                'lr0': 0.001,\n                'lrf': 0.01,\n                'momentum': 0.937,\n                'weight_decay': 0.0005,\n                'warmup_epochs': 10,\n                'warmup_momentum': 0.8,\n                'box': 7.5,\n                'cls': 0.5,\n                'dfl': 1.5,\n                'close_mosaic': 10,\n                'amp': True\n            }\n            \n            results = model.train(**config)\n            return model, results\n            \n        except Exception as e:\n            print(f\"Error training model: {str(e)}\")\n            return None, None","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:27:11.364469Z","iopub.execute_input":"2024-11-06T13:27:11.364835Z","iopub.status.idle":"2024-11-06T13:27:11.400235Z","shell.execute_reply.started":"2024-11-06T13:27:11.364791Z","shell.execute_reply":"2024-11-06T13:27:11.399247Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Axial T2\nimages_dir  = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images'\noutput_dir = '/kaggle/working/spine_dataset_axialt2'\n\naxial_t2_model = AxialT2_YOLO(\n    df=axialt2_df,\n    images_dir=images_dir,\n    output_dir=output_dir,\n    img_size=384\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:27:11.401281Z","iopub.execute_input":"2024-11-06T13:27:11.401590Z","iopub.status.idle":"2024-11-06T13:33:29.732612Z","shell.execute_reply.started":"2024-11-06T13:27:11.401558Z","shell.execute_reply":"2024-11-06T13:33:29.731482Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def save_trained_model(model, best_model_path, model_type, save_path='/kaggle/working/'):\n    \"\"\"\n    Save the trained YOLO model with simple fixed naming\n    \n    Args:\n        model: YOLO model object\n        best_model_path: Path to the best model weights\n        model_type: String indicating model type ('sag_t1', 'sag_t2', or 'axial_t2')\n        save_path: Base path to save the model\n    \"\"\"\n    # Define simple model names\n    model_names = {\n        'sag_t1': 'sagittal_t1_spine_detector.pt',\n        'sag_t2': 'sagittal_t2_spine_detector.pt',\n        'axial_t2': 'axial_t2_spine_detector.pt'\n    }\n    \n    if model_type not in model_names:\n        raise ValueError(f\"Invalid model_type: {model_type}. Must be one of {list(model_names.keys())}\")\n    \n    try:\n        if not os.path.exists(best_model_path):\n            print(f\"Best model weights not found at {best_model_path}\")\n            return\n            \n        final_save_path = os.path.join(save_path, model_names[model_type])\n        \n        # Copy the model file\n        import shutil\n        shutil.copy(best_model_path, final_save_path)\n        print(f\"Model saved to {final_save_path}\")\n        \n    except Exception as e:\n        print(f\"Error saving model: {str(e)}\")\n\n# Save models with appropriate type\n#save_trained_model(\n#    sag_t1_model.model, \n#    '/kaggle/working/spine_detection/sagittal_t1_yolo/weights/best.pt',\n#    model_type='sag_t1'\n#)\n\n#save_trained_model(\n#    sag_t2_model.model, \n#    '/kaggle/working/spine_detection/sagittal_t2_yolo/weights/best.pt',\n#    model_type='sag_t2'\n#)\n\nsave_trained_model(\n    axial_t2_model.model, \n    '/kaggle/working/spine_detection/axial_t2_yolo/weights/best.pt',\n    model_type='axial_t2'\n)","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:33:31.761747Z","iopub.execute_input":"2024-11-06T13:33:31.762159Z","iopub.status.idle":"2024-11-06T13:33:31.876649Z","shell.execute_reply.started":"2024-11-06T13:33:31.762115Z","shell.execute_reply":"2024-11-06T13:33:31.875669Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!rm -r yolov8x.pt\n!rm -r yolo11n.pt","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:33:51.038782Z","iopub.execute_input":"2024-11-06T13:33:51.039951Z","iopub.status.idle":"2024-11-06T13:33:53.149527Z","shell.execute_reply.started":"2024-11-06T13:33:51.039893Z","shell.execute_reply":"2024-11-06T13:33:53.148219Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Remove all the folders execpt the weights\nimport shutil\nshutil.rmtree(\"spine_detection\")\n#shutil.rmtree(\"spine_dataset_sagt1\")\n#shutil.rmtree(\"spine_dataset_segt2\")\nshutil.rmtree(\"spine_dataset_axialt2\")","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:34:05.734728Z","iopub.execute_input":"2024-11-06T13:34:05.735140Z","iopub.status.idle":"2024-11-06T13:34:06.175406Z","shell.execute_reply.started":"2024-11-06T13:34:05.735099Z","shell.execute_reply":"2024-11-06T13:34:06.174273Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_axial_predictions(image_path, model_path='axial_t2_spine_detector.pt', \n                         conf_threshold=0.25, iou_threshold=0.45, img_size=384):\n    \"\"\"\n    Plot YOLO predictions for axial images showing left and right sides\n    \n    Args:\n        image_path: Path to DICOM image\n        model_path: Path to saved YOLO model\n        conf_threshold: Confidence threshold for predictions\n        iou_threshold: IOU threshold for NMS\n        img_size: Image size for model input\n    \"\"\"\n    # Load model\n    model = YOLO(model_path)\n    \n    # Read DICOM\n    ds = pydicom.dcmread(image_path)\n    image = ds.pixel_array\n    \n    # Normalize and resize\n    image_normalized = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)\n    image_resized = cv2.resize(image_normalized, (img_size, img_size))\n    \n    # Convert grayscale to RGB\n    image_rgb = np.stack([image_resized] * 3, axis=-1)\n    \n    # Create figure\n    plt.figure(figsize=(15, 7))\n    \n    # Plot original image\n    plt.subplot(1, 2, 1)\n    plt.imshow(image_resized, cmap='gray')\n    plt.title('Original Image')\n    plt.axis('off')\n    \n    # Plot image with predictions\n    plt.subplot(1, 2, 2)\n    plt.imshow(image_resized, cmap='gray')\n    plt.title('Predictions')\n    \n    # Get predictions\n    results = model.predict(\n        source=image_rgb,\n        conf=conf_threshold,\n        iou=iou_threshold\n    )\n    \n    # Define colors and names for left/right sides\n    side_colors = {'left': 'red', 'right': 'blue'}\n    side_names = {0: 'Left', 1: 'Right'}\n    \n    if results[0].boxes is not None:\n        boxes = results[0].boxes.cpu().numpy()\n        \n        # Sort boxes by x-coordinate (left to right)\n        box_data = []\n        for box in boxes:\n            cls_id = int(box.cls[0])\n            conf = box.conf[0]\n            x1, y1, x2, y2 = box.xyxy[0]\n            box_data.append((x1, cls_id, conf, x1, y1, x2, y2))\n        \n        box_data.sort()  # Sort by x1 coordinate\n        \n        # Plot each detection\n        for i, (_, cls_id, conf, x1, y1, x2, y2) in enumerate(box_data):\n            color = side_colors['left'] if cls_id == 0 else side_colors['right']\n            side_name = side_names[cls_id]\n            \n            # Draw bounding box\n            plt.gca().add_patch(plt.Rectangle(\n                (x1, y1), x2-x1, y2-y1,\n                fill=False, color=color, linewidth=2\n            ))\n            \n            # Add label\n            plt.text(\n                x2 + 5, (y1 + y2) / 2, \n                f'{side_name}: {conf:.2f}',\n                color=color, fontsize=8, verticalalignment='center',\n                bbox=dict(facecolor='white', alpha=0.7, edgecolor='none')\n            )\n            \n            # Print detection info\n            print(f\"Found {side_name} side with confidence {conf:.2f}\")\n    else:\n        print(\"No detections found\")\n    \n    plt.axis('off')\n    plt.tight_layout()\n    plt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:34:13.993546Z","iopub.execute_input":"2024-11-06T13:34:13.993926Z","iopub.status.idle":"2024-11-06T13:34:14.010079Z","shell.execute_reply.started":"2024-11-06T13:34:13.993890Z","shell.execute_reply":"2024-11-06T13:34:14.009062Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def process_multiple_axial_images(image_paths, model_path='axial_t2_spine_detector.pt', \n                                conf_threshold=0.15, iou_threshold=0.3):\n    \"\"\"\n    Process multiple axial images and display their predictions\n    \n    Args:\n        image_paths: List of paths to DICOM images\n        model_path: Path to saved YOLO model\n        conf_threshold: Confidence threshold for predictions\n        iou_threshold: IOU threshold for NMS\n    \"\"\"\n    # First, filter images that have predictions\n    valid_images = []\n    model = YOLO(model_path)\n    \n    print(\"Analyzing images...\")\n    for img_path in tqdm(image_paths):\n        ds = pydicom.dcmread(img_path)\n        image = ds.pixel_array\n        image_normalized = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)\n        image_resized = cv2.resize(image_normalized, (384, 384))\n        image_rgb = np.stack([image_resized] * 3, axis=-1)\n        \n        results = model.predict(\n            source=image_rgb,\n            conf=conf_threshold,\n            iou=iou_threshold\n        )\n        \n        if results[0].boxes is not None and len(results[0].boxes) > 0:\n            valid_images.append(img_path)\n    \n    if not valid_images:\n        print(\"No images with valid predictions found\")\n        return\n    \n    print(f\"\\nFound {len(valid_images)} images with valid predictions\")\n    \n    # Process only images with predictions\n    for img_path in valid_images:\n        print(f\"\\nProcessing image: {os.path.basename(img_path)}\")\n        plot_axial_predictions(img_path, model_path, conf_threshold, iou_threshold)\n","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:34:14.672658Z","iopub.execute_input":"2024-11-06T13:34:14.673027Z","iopub.status.idle":"2024-11-06T13:34:14.682635Z","shell.execute_reply.started":"2024-11-06T13:34:14.672992Z","shell.execute_reply":"2024-11-06T13:34:14.681636Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Usage example for Axial T2:\nimage_paths = glob.glob('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images/4646740/3201256954/*.dcm')\nprocess_multiple_axial_images(image_paths, 'axial_t2_spine_detector.pt')","metadata":{"execution":{"iopub.status.busy":"2024-11-06T13:34:16.706726Z","iopub.execute_input":"2024-11-06T13:34:16.707098Z","iopub.status.idle":"2024-11-06T13:34:56.030311Z","shell.execute_reply.started":"2024-11-06T13:34:16.707064Z","shell.execute_reply":"2024-11-06T13:34:56.029301Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null}]}