{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.11.13"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":99552,"databundleVersionId":13441085,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"This notebook is to processes medical CT scan images and their segmentation masks to generate hard samples for training. The dataset can help the model better distinguish between actual vessels and similar-looking non-vessel structures.\n\n*Training Benefit:*\n1) Instead of showing the model mostly easy negative examples (like air or bone), we're focusing on the challenging cases\n2) This helps the model learn more fine-grained features that distinguish true vessels from similar-looking structures\n3) It's similar to how a medical student learns - they need to see not just clear examples of vessels, but also learn what can be mistaken for vessels\n\nSo while we do have labels for all vessels, this approach is deliberately creating a focused dataset of challenging examples to improve the model's discrimination ability in the most difficult cases.","metadata":{}},{"cell_type":"markdown","source":"\n*Main Steps:*\n1) Loads CT scan images and their corresponding segmentation masks (in NIFTI format)\n2) Resamples both to a standardized spacing of 1mm³\n3) Normalizes the CT images using a specific window level (WL=300) and window width (WW=600)\n4) For each vessel label (1-13): a) Finds vessel locations in the mask\n    b) Samples background points within 10 voxels of these vessels\n    c) Creates 2.5D patches (5-slice stacks of size 224×224) centered on these points\n\n*Output:*\n1) Saves aligned masks to ./aligned_masks/\n2) Saves negative patches to ./patches_from_segmentations/\n3) Each series gets its own directory with patches named hard_label{label}_{i}.npy","metadata":{}},{"cell_type":"markdown","source":"# 🚀 Help Others Discover This Work!\n\n## 👍 If the notebooks or dataset were helpful, **please give it an upvote**!\n\nYour support is appreciated and keeps the community growing. 🙌\n\n## 🌟 Please **UPVOTE** if you found it helpful!","metadata":{}},{"cell_type":"markdown","source":"# Initialization","metadata":{}},{"cell_type":"code","source":"import os\nimport json\nimport numpy as np\nimport SimpleITK as sitk\nfrom scipy.ndimage import zoom\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\n\n# --- Config ---\nSEGMENTATION_DIR = \"/kaggle/input/rsna-intracranial-aneurysm-detection/segmentations/\"\nOUTPUT_PATCHES_DIR = \"./patches_from_segmentations/\"\nOUTPUT_MASKS_DIR = \"./aligned_masks/\"\n\nTARGET_SPACING = np.array([1.0, 1.0, 1.0])  # z, y, x in mm\nSTACK_SIZE = 5\nPATCH_SIZE = (224, 224)\nNUM_SAMPLES_PER_LABEL = 16\n\nDEBUG = True\n\n# Vessel label mapping\nVESSEL_LABELS = {\n    1: \"Other Posterior Circulation\",\n    2: \"Basilar Tip\",\n    3: \"Right Posterior Communicating Artery\",\n    4: \"Left Posterior Communicating Artery\",\n    5: \"Right Infraclinoid Internal Carotid Artery\",\n    6: \"Left Infraclinoid Internal Carotid Artery\",\n    7: \"Right Supraclinoid Internal Carotid Artery\",\n    8: \"Left Supraclinoid Internal Carotid Artery\",\n    9: \"Right Middle Cerebral Artery\",\n    10: \"Left Middle Cerebral Artery\",\n    11: \"Right Anterior Cerebral Artery\",\n    12: \"Left Anterior Cerebral Artery\",\n    13: \"Anterior Communicating Artery\"\n}\n\nos.makedirs(OUTPUT_PATCHES_DIR, exist_ok=True)\nos.makedirs(OUTPUT_MASKS_DIR, exist_ok=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:39:20.835751Z","iopub.execute_input":"2025-09-21T05:39:20.836006Z","iopub.status.idle":"2025-09-21T05:39:22.908014Z","shell.execute_reply.started":"2025-09-21T05:39:20.835985Z","shell.execute_reply":"2025-09-21T05:39:22.906532Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Helper Functions","metadata":{}},{"cell_type":"code","source":"# --- Helper Functions ---\n\ndef load_image_and_mask(series_uid):\n    image_path = os.path.join(SEGMENTATION_DIR, f\"{series_uid}.nii\")\n    mask_path = os.path.join(SEGMENTATION_DIR, f\"{series_uid}_cowseg.nii\")\n\n    if not os.path.exists(image_path) or not os.path.exists(mask_path):\n        raise FileNotFoundError(f\"Missing image or mask for {series_uid}\")\n\n    image_sitk = sitk.ReadImage(image_path)\n    mask_sitk = sitk.ReadImage(mask_path)\n\n    image_np = sitk.GetArrayFromImage(image_sitk)\n    mask_np = sitk.GetArrayFromImage(mask_sitk)\n\n    spacing = list(image_sitk.GetSpacing())[::-1]  # Convert to z, y, x\n    origin = image_sitk.GetOrigin()\n    direction = image_sitk.GetDirection()\n\n    return image_np, mask_np, spacing, origin, direction\n\n\ndef resample_volume(volume, original_spacing, new_spacing, order=3):\n    resize_factor = original_spacing / new_spacing\n    return zoom(volume, resize_factor, order=order, mode='nearest')\n\n\ndef normalize_intensity(image, modality):\n    if modality == 'CT':\n        WL, WW = 300, 600\n        min_val = WL - WW // 2\n        max_val = WL + WW // 2\n        image = np.clip(image, min_val, max_val)\n        image = (image - min_val) / (max_val - min_val)\n    else:\n        mean, std = np.mean(image), np.std(image)\n        if std > 0:\n            image = (image - mean) / std\n    return image\n\n\ndef save_mask_as_nii(mask_np, save_path, spacing, origin=None, direction=None):\n    mask_sitk = sitk.GetImageFromArray(mask_np.astype(np.uint8))\n    mask_sitk.SetSpacing(tuple(spacing[::-1]))  # Convert to x, y, z\n    if origin is not None:\n        mask_sitk.SetOrigin(origin)\n    if direction is not None:\n        mask_sitk.SetDirection(direction)\n    sitk.WriteImage(mask_sitk, save_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:39:22.908978Z","iopub.execute_input":"2025-09-21T05:39:22.909427Z","iopub.status.idle":"2025-09-21T05:39:22.922209Z","shell.execute_reply.started":"2025-09-21T05:39:22.909401Z","shell.execute_reply":"2025-09-21T05:39:22.92062Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Strategy\n\nBy sampling negative points that are close to real vessels (within 10 voxels), we're focusing on regions that are most likely to confuse the model\n\nThese regions might include:\n1) Vessel-like structures that aren't actually vessels\n2) Areas where vessels branch or taper off\n3) Regions with similar intensity patterns but no vessels","metadata":{}},{"cell_type":"code","source":"def hard_sample_around_label(resampled_mask, label, num_samples=NUM_SAMPLES_PER_LABEL, radius=10):\n    vessel_coords = np.argwhere(resampled_mask == label)\n    if len(vessel_coords) == 0:\n        return np.empty((0, 3), dtype=int)\n\n    neg_coords = []\n    np.random.shuffle(vessel_coords)\n\n    for coord in vessel_coords:\n        if len(neg_coords) >= num_samples:\n            break\n        z, y, x = coord\n        z_min, z_max = max(0, z - radius), min(resampled_mask.shape[0], z + radius + 1)\n        y_min, y_max = max(0, y - radius), min(resampled_mask.shape[1], y + radius + 1)\n        x_min, x_max = max(0, x - radius), min(resampled_mask.shape[2], x + radius + 1)\n\n        neighborhood = resampled_mask[z_min:z_max, y_min:y_max, x_min:x_max]\n        bg_voxels = np.argwhere(neighborhood == 0)\n        if len(bg_voxels) == 0:\n            continue\n\n        chosen_bg = bg_voxels[np.random.choice(len(bg_voxels))]\n        global_coord = chosen_bg + np.array([z_min, y_min, x_min])\n        neg_coords.append(global_coord)\n\n    if len(neg_coords) > num_samples:\n        indices = np.random.choice(len(neg_coords), num_samples, replace=False)\n        neg_coords = np.array(neg_coords)[indices]\n    else:\n        neg_coords = np.array(neg_coords)\n\n    return neg_coords","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:39:22.924941Z","iopub.execute_input":"2025-09-21T05:39:22.925317Z","iopub.status.idle":"2025-09-21T05:39:22.958754Z","shell.execute_reply.started":"2025-09-21T05:39:22.925258Z","shell.execute_reply":"2025-09-21T05:39:22.957545Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_2d5_stack(volume, center_z, center_y, center_x, patch_size, stack_size):\n    z_dim, y_dim, x_dim = volume.shape\n    half_stack = stack_size // 2\n    half_patch_y, half_patch_x = patch_size[0] // 2, patch_size[1] // 2\n\n    stack = []\n    for i in range(center_z - half_stack, center_z + half_stack + 1):\n        if 0 <= i < z_dim:\n            slice_data = volume[i]\n            crop_y_min = max(0, center_y - half_patch_y)\n            crop_y_max = min(y_dim, center_y + half_patch_y)\n            crop_x_min = max(0, center_x - half_patch_x)\n            crop_x_max = min(x_dim, center_x + half_patch_x)\n\n            cropped_slice = slice_data[crop_y_min:crop_y_max, crop_x_min:crop_x_max]\n\n            pad_y = patch_size[0] - cropped_slice.shape[0]\n            pad_x = patch_size[1] - cropped_slice.shape[1]\n\n            padded_slice = np.pad(cropped_slice,\n                                  ((pad_y // 2, pad_y - pad_y // 2),\n                                   (pad_x // 2, pad_x - pad_x // 2)),\n                                  mode='constant')\n            stack.append(padded_slice)\n        else:\n            stack.append(np.zeros(patch_size))\n    return np.stack(stack)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:39:22.959948Z","iopub.execute_input":"2025-09-21T05:39:22.960265Z","iopub.status.idle":"2025-09-21T05:39:22.997465Z","shell.execute_reply.started":"2025-09-21T05:39:22.960232Z","shell.execute_reply":"2025-09-21T05:39:22.995704Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Main Pipeline","metadata":{}},{"cell_type":"code","source":"# Updated main pipeline to store coordinates\ndef generate_for_all_segmentations():\n    \"\"\"\n    Main function to generate and save hard samples along with their metadata.\n    For each series:\n    1. Load and preprocess image/mask\n    2. Generate hard samples\n    3. Save patches and coordinates\n    \"\"\"\n    nii_files = sorted([\n        f for f in os.listdir(SEGMENTATION_DIR)\n        if f.endswith(\".nii\") and \"_cowseg\" in f\n    ])\n\n    if DEBUG:\n        nii_files = nii_files[:10]\n\n    for fname in tqdm(nii_files, desc=\"Processing segmentation masks\"):\n        series_uid = fname.replace(\"_cowseg.nii\", \"\")\n\n        try:\n            print(f\"\\n--- Processing {series_uid} ---\")\n            image_volume, mask_np, original_spacing, origin, direction = load_image_and_mask(series_uid)\n\n            resampled_image = resample_volume(image_volume, np.array(original_spacing), TARGET_SPACING, order=3)\n            resampled_mask = resample_volume(mask_np, np.array(original_spacing), TARGET_SPACING, order=0).astype(np.uint8)\n\n            normalized_image = normalize_intensity(resampled_image, modality='CT')\n\n            # Save aligned mask\n            mask_out_dir = os.path.join(OUTPUT_MASKS_DIR, series_uid)\n            os.makedirs(mask_out_dir, exist_ok=True)\n            mask_path = os.path.join(mask_out_dir, \"aligned_mask.nii.gz\")\n            save_mask_as_nii(resampled_mask, mask_path, spacing=TARGET_SPACING, origin=origin, direction=direction)\n\n            # Output patches and metadata\n            patch_out_dir = os.path.join(OUTPUT_PATCHES_DIR, series_uid)\n            os.makedirs(patch_out_dir, exist_ok=True)\n\n            # Create metadata dictionary for this series\n            series_metadata = {\n                'series_uid': series_uid,\n                'samples': []\n            }\n\n            for label in range(1, 14):  # Vessel labels 1–13\n                coords = hard_sample_around_label(resampled_mask, label)\n                for i, (z, y, x) in enumerate(coords):\n                    # Generate and save patch\n                    patch = create_2d5_stack(normalized_image, z, y, x, PATCH_SIZE, STACK_SIZE)\n                    patch_fname = f\"hard_label{label}_{i}.npy\"\n                    patch_path = os.path.join(patch_out_dir, patch_fname)\n                    np.save(patch_path, patch)\n\n                    # Store metadata\n                    sample_info = {\n                        'patch_file': patch_fname,\n                        'label': int(label),\n                        'coordinates': {\n                            'z': int(z),\n                            'y': int(y),\n                            'x': int(x)\n                        }\n                    }\n                    series_metadata['samples'].append(sample_info)\n\n            # Save metadata\n            metadata_path = os.path.join(patch_out_dir, 'metadata.json')\n            with open(metadata_path, 'w') as f:\n                json.dump(series_metadata, f, indent=2)\n\n            print(f\"✓ Finished {series_uid}\")\n\n        except Exception as e:\n            print(f\"❌ Error in {series_uid}: {e}\")# Cell removed to avoid duplication","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:39:22.99833Z","iopub.execute_input":"2025-09-21T05:39:22.998719Z","iopub.status.idle":"2025-09-21T05:39:23.036713Z","shell.execute_reply.started":"2025-09-21T05:39:22.998687Z","shell.execute_reply":"2025-09-21T05:39:23.035367Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Code Run","metadata":{}},{"cell_type":"code","source":"# --- Run ---\nif __name__ == \"__main__\":\n    generate_for_all_segmentations()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:39:23.038078Z","iopub.execute_input":"2025-09-21T05:39:23.038514Z","iopub.status.idle":"2025-09-21T05:40:49.566332Z","shell.execute_reply.started":"2025-09-21T05:39:23.038479Z","shell.execute_reply":"2025-09-21T05:40:49.565059Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Visulization","metadata":{}},{"cell_type":"code","source":"# --- Visualization Functions ---\n\ndef visualize_hard_sample_patch(patch_path, title=None):\n    \"\"\"\n    Visualizes a 2.5D patch (stack of slices) with proper windowing.\n    \n    Args:\n        patch_path: Path to the .npy file containing the patch\n        title: Optional title for the plot\n    \"\"\"\n    # Load the patch\n    patch = np.load(patch_path)\n    \n    # Create a figure with subplots for each slice\n    fig, axes = plt.subplots(1, STACK_SIZE, figsize=(15, 3))\n    if title:\n        fig.suptitle(title, fontsize=12)\n    else:\n        fig.suptitle('2.5D Patch Visualization (5 consecutive slices)', fontsize=12)\n    \n    for i, ax in enumerate(axes):\n        ax.imshow(patch[i], cmap='gray')\n        ax.axis('off')\n        ax.set_title(f'Slice {i+1}')\n    \n    plt.tight_layout()\n    plt.show()\n\ndef visualize_hard_sample_location(series_uid, coords, label=None, radius=20):\n    \"\"\"\n    Visualizes the location of a hard sample in the context of the original volume.\n    Shows the central slice with the patch location marked.\n    \n    Args:\n        series_uid: ID of the CT series\n        coords: Dictionary containing z, y, x coordinates\n        label: The vessel label number (1-13)\n        radius: Size of the context region to show around the patch\n    \"\"\"\n    # Get vessel name if label is provided\n    vessel_name = VESSEL_LABELS.get(label, \"Unknown\") if label is not None else \"Unknown\"\n    # Load the original image and mask\n    image_volume, mask_np, original_spacing, _, _ = load_image_and_mask(series_uid)\n    \n    # Get original dimensions\n    orig_depth, orig_height, orig_width = image_volume.shape\n    \n    # Calculate the inverse transformation (from resampled to original space)\n    spacing_scale = np.array(original_spacing) / TARGET_SPACING\n    \n    # Transform coordinates from resampled space (1mm) back to original space\n    # Use floor division to ensure we get valid indices\n    z = min(orig_depth - 1, max(0, int(coords['z'] / spacing_scale[0])))\n    y = min(orig_height - 1, max(0, int(coords['y'] / spacing_scale[1])))\n    x = min(orig_width - 1, max(0, int(coords['x'] / spacing_scale[2])))\n    \n    # Calculate patch size in original space\n    # We need to scale the patch size by the ratio of spacings\n    # If original spacing is larger than 1mm, the patch should be smaller in voxel units\n    patch_size_y = int(PATCH_SIZE[0] * (TARGET_SPACING[1] / original_spacing[1]))\n    patch_size_x = int(PATCH_SIZE[1] * (TARGET_SPACING[2] / original_spacing[2]))\n    \n    # Ensure minimum patch size\n    patch_size_y = max(patch_size_y, 32)\n    patch_size_x = max(patch_size_x, 32)\n    \n    # Scale radius according to spacing\n    scaled_radius = int(radius * (TARGET_SPACING[1] / max(original_spacing[1:])))  # Use max of x,y spacing\n    \n    # Extract regions for visualization with bounds checking\n    z_min = max(0, z - scaled_radius)\n    z_max = min(orig_depth, z + scaled_radius)\n    y_min = max(0, y - scaled_radius)\n    y_max = min(orig_height, y + scaled_radius)\n    x_min = max(0, x - scaled_radius)\n    x_max = min(orig_width, x + scaled_radius)\n    \n    # Get the slices with bounds checking\n    image_slice = image_volume[z]\n    mask_slice = mask_np[z]\n    \n    # Create figure\n    fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 5))\n    fig.suptitle(f'Hard Sample Location (Series: {series_uid})\\nVessel: {vessel_name}', fontsize=12)\n    \n    # Plot full slice with zoomed area marked\n    ax1.imshow(image_slice, cmap='gray')\n    \n    # Add vessel overlay for the full slice\n    if label is not None:\n        # Create binary mask for the specific vessel in full slice\n        full_vessel_mask = (mask_slice == label)\n        # Use a high-contrast colormap\n        vessel_cmap = plt.cm.RdYlBu  # Red-Yellow-Blue colormap for better contrast\n        vessel_cmap.set_bad(alpha=0)\n        full_mask_overlay = np.ma.masked_where(~full_vessel_mask, np.ones_like(mask_slice))\n        ax1.imshow(full_mask_overlay, cmap=vessel_cmap, alpha=0.6)  # Increased opacity\n    \n    # Draw the bounding box for the zoomed area\n    zoom_width = x_max - x_min\n    zoom_height = y_max - y_min\n    rect = plt.Rectangle((x_min, y_min), \n                        zoom_width, zoom_height,\n                        fill=False, color='red', linewidth=2)\n    ax1.add_patch(rect)\n    \n    # Add center point\n    ax1.plot(x, y, 'r+', markersize=10)\n    \n    # Add size annotation\n    ax1.text(x_min, y_min-5, \n             f'Zoom area: {zoom_width}x{zoom_height}px\\nSpacing: {original_spacing[1]:.2f}x{original_spacing[2]:.2f}mm', \n             color='red', fontsize=8)\n    \n    ax1.set_title(f'Full Slice with Zoom Location\\n({VESSEL_LABELS[label] if label else \"Unknown Vessel\"})')\n    ax1.axis('off')\n    \n    # Plot zoomed context region\n    context_img = image_slice[y_min:y_max, x_min:x_max]\n    context_mask = mask_slice[y_min:y_max, x_min:x_max]\n    \n    # Draw patch size in zoomed view\n    patch_rect = plt.Rectangle((x-x_min-patch_size_x//2, y-y_min-patch_size_y//2),\n                              patch_size_x, patch_size_y,\n                              fill=False, color='yellow', linewidth=1, linestyle='--')\n    \n    ax2.imshow(context_img, cmap='gray')\n    ax2.add_patch(patch_rect)  # Add patch size indicator to zoomed view\n    ax2.set_title('Zoomed Context (Image)')\n    ax2.axis('off')\n    \n    # Plot target vessel overlay in context region\n    ax2.imshow(context_img, cmap='gray')\n    \n    if label is not None:\n        # Create binary mask for the specific vessel\n        target_vessel_mask = (context_mask == label)\n        # Use high-contrast colormap for target vessel\n        vessel_cmap = plt.cm.RdYlBu\n        vessel_cmap.set_bad(alpha=0)  # Make non-vessel areas transparent\n        \n        # Create masked array for overlay\n        mask_overlay = np.ma.masked_where(~target_vessel_mask, np.ones_like(context_mask))\n        ax2.imshow(mask_overlay, cmap=vessel_cmap, alpha=0.7)  # Increased opacity\n        ax2.set_title(f'Target Vessel Only\\n({VESSEL_LABELS[label]})')\n    else:\n        ax2.set_title('Target Vessel\\n(No specific vessel)')\n    ax2.axis('off')\n\n    # Plot all vessels overlay in context region\n    ax3.imshow(context_img, cmap='gray')\n    # Create mask for all vessels\n    all_vessels_mask = (context_mask > 0)\n    # Use distinct colors for different vessels\n    all_vessels_cmap = plt.cm.nipy_spectral  # More distinct color separation\n    all_vessels_cmap.set_bad(alpha=0)\n    \n    # Create masked array for all vessels overlay\n    all_mask_overlay = np.ma.masked_where(~all_vessels_mask, context_mask)\n    ax3.imshow(all_mask_overlay, cmap=all_vessels_cmap, alpha=0.6)  # Increased opacity\n    ax3.set_title('All Vessels Overlay')\n    ax3.axis('off')\n    \n    plt.tight_layout()\n    plt.show()\n\ndef visualize_random_hard_samples(n_samples=5):\n    \"\"\"\n    Visualizes random hard samples from the dataset.\n    \n    Args:\n        n_samples: Number of random samples to visualize\n    \"\"\"\n    # Get list of all patch directories\n    series_dirs = [d for d in os.listdir(OUTPUT_PATCHES_DIR) \n                  if os.path.isdir(os.path.join(OUTPUT_PATCHES_DIR, d))]\n    \n    for _ in range(n_samples):\n        # Randomly select a series\n        series_uid = np.random.choice(series_dirs)\n        patch_dir = os.path.join(OUTPUT_PATCHES_DIR, series_uid)\n        \n        # Load metadata\n        metadata_path = os.path.join(patch_dir, 'metadata.json')\n        try:\n            with open(metadata_path, 'r') as f:\n                metadata = json.load(f)\n        except FileNotFoundError:\n            print(f\"Metadata not found for series {series_uid}, skipping...\")\n            continue\n        \n        # Randomly select a sample from metadata\n        if not metadata['samples']:\n            continue\n            \n        sample = np.random.choice(metadata['samples'])\n        patch_path = os.path.join(patch_dir, sample['patch_file'])\n        \n        vessel_label = sample['label']\n        print(f\"\\nVisualizing hard sample:\")\n        print(f\"Series: {series_uid}\")\n        print(f\"Vessel: {VESSEL_LABELS[vessel_label]} (Label {vessel_label})\")\n        print(f\"Coordinates: z={sample['coordinates']['z']}, \"\n              f\"y={sample['coordinates']['y']}, x={sample['coordinates']['x']}\")\n        \n        # Visualize both patch and its location\n        title = f\"Hard Sample - {VESSEL_LABELS[vessel_label]}\"\n        visualize_hard_sample_patch(patch_path, title)\n        visualize_hard_sample_location(series_uid, sample['coordinates'], label=vessel_label)\n        print(\"-\" * 80)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:40:49.567677Z","iopub.execute_input":"2025-09-21T05:40:49.567963Z","iopub.status.idle":"2025-09-21T05:40:49.595204Z","shell.execute_reply.started":"2025-09-21T05:40:49.567941Z","shell.execute_reply":"2025-09-21T05:40:49.593844Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Example: Visualize 5 random hard samples with error handling\nprint(\"Visualizing 5 random hard samples from the dataset...\")\ntry:\n    visualize_random_hard_samples(n_samples=5)\nexcept Exception as e:\n    print(f\"Error during visualization: {str(e)}\")\n    print(\"Original coordinates:\", sample['coordinates'])\n    print(\"Transformed coordinates:\", {'z': z, 'y': y, 'x': x})\n    print(\"Original spacing:\", original_spacing)\n    print(\"Image volume shape:\", image_volume.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:40:49.596508Z","iopub.execute_input":"2025-09-21T05:40:49.596966Z","iopub.status.idle":"2025-09-21T05:40:55.249874Z","shell.execute_reply.started":"2025-09-21T05:40:49.596929Z","shell.execute_reply":"2025-09-21T05:40:55.248988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Example usage: Visualize 5 random hard samples\nprint(\"Visualizing 5 random hard samples from the dataset...\")\nvisualize_random_hard_samples(n_samples=5)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:40:55.252817Z","iopub.execute_input":"2025-09-21T05:40:55.253227Z","iopub.status.idle":"2025-09-21T05:41:01.232556Z","shell.execute_reply.started":"2025-09-21T05:40:55.253194Z","shell.execute_reply":"2025-09-21T05:41:01.23013Z"}},"outputs":[],"execution_count":null}]}