mip_dataset
Batch process all volumes in a dataset folder to generate sliding-window Maximum Intensity Projections along a specified anatomical plane.
mip_dataset(
nii_folder: str,
output_path: str,
window_size: int = 10,
view: str = "axial",
saving_mode: str = "case",
debug: bool = False
) -> None
Overview
This function processes all NIfTI volumes in a dataset folder by applying sliding-window Maximum Intensity Projection to each file. For every slice position, it computes the maximum intensity across a local neighborhood, creating an enhanced volume that highlights high-intensity structures like blood vessels or contrast-enhanced regions.
The MIP operation is useful for:
- Enhancing vascular structures in angiography scans
- Improving visibility of contrast-enhanced regions
- Reducing noise while preserving peak intensities
- Creating enhanced datasets for vessel detection or segmentation
Each output volume maintains the same dimensions and spatial metadata as its input, with filenames following the pattern <PREFIX>_mip_<VIEW>.nii.gz.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
nii_folder | str | required | Path to the directory containing NIfTI volumes in .nii.gz format. |
output_path | str | required | Root directory where MIP volumes will be saved. |
window_size | int | 10 | Number of slices on each side of the current position for projection. Effective window: 2×size+1. |
view | str | "axial" | Anatomical plane for projection: "axial", "coronal", or "sagittal". |
saving_mode | str | "case" | Organization mode: "case" (folder per file) or "view" (shared folder). |
debug | bool | False | If True, prints processing summary after completion. |
Returns
None – The function saves MIP volumes to disk.
Output Organization
Saving Modes
Case Mode (saving_mode="case")
Creates a separate folder for each input volume:
output_path/
├── patient_001/
│ └── axial/
│ └── patient_001_mip_axial.nii.gz
├── patient_002/
│ └── axial/
│ └── patient_002_mip_axial.nii.gz
View Mode (saving_mode="view")
Groups all MIP volumes in a single view folder:
output_path/
└── axial/
├── patient_001_mip_axial.nii.gz
├── patient_002_mip_axial.nii.gz
└── ...
Filename Pattern
Each MIP volume is saved as:
<PREFIX>_mip_<VIEW>.nii.gz
Example: Input scan_042.nii.gz → Output scan_042_mip_axial.nii.gz
Window Size Parameter
The window_size parameter controls the neighborhood size for maximum intensity computation:
Effective window length: 2 × window_size + 1
| Window Size | Effective Slices | Effect | Best For |
|---|---|---|---|
| 5 | 11 slices | Minimal smoothing, local enhancement | Fine vessel details |
| 10 | 21 slices | Moderate enhancement, balanced | General purpose (default) |
| 20 | 41 slices | Strong enhancement, wider context | Large vessel structures |
| 30+ | 61+ slices | Maximum enhancement, global view | Overview visualization |
Trade-off: Larger windows enhance more structures but may blur fine details and mix unrelated regions.
Anatomical Views
The view parameter determines the projection axis:
| View | Projection Axis | Description | Common Applications |
|---|---|---|---|
"axial" | Z-axis | Top-down projection | Brain vessels, chest imaging |
"coronal" | Y-axis | Front-back projection | Spine vessels, full body |
"sagittal" | X-axis | Left-right projection | Bilateral vessel comparison |
Exceptions
| Exception | Condition |
|---|---|
FileNotFoundError | The nii_folder does not exist or contains no .nii.gz files |
ValueError | Invalid view or saving_mode parameter |
Usage Notes
- Input Format: Only
.nii.gzfiles are processed - 3D Volumes Required: Input must be 3D NIfTI images
- Sequential Processing: Files are processed one at a time (no parallelization)
- Progress Display: Shows progress bar with current file being processed
- Output Directory: Automatically created if it doesn’t exist
- Spatial Metadata: Affine transformations are preserved from input
Examples
Basic Usage
Generate MIP volumes with default settings:
from nidataset.preprocessing import mip_dataset
mip_dataset(
nii_folder="dataset/angiography/",
output_path="dataset/mip_enhanced/",
window_size=10,
view="axial",
saving_mode="case"
)
# Creates: dataset/mip_enhanced/case_001/axial/case_001_mip_axial.nii.gz, ...
Large Window for Strong Enhancement
Use larger window for prominent vessel visualization:
mip_dataset(
nii_folder="data/vessel_scans/",
output_path="data/enhanced_vessels/",
window_size=20, # 41-slice window
view="axial",
saving_mode="case",
debug=True
)
# Prints summary after processing
Small Window for Detail Preservation
Use smaller window to preserve fine structures:
mip_dataset(
nii_folder="high_res_scans/",
output_path="detail_preserved_mip/",
window_size=5, # 11-slice window
view="coronal",
saving_mode="view",
debug=True
)
Multi-View Processing
Generate MIP volumes for all anatomical views:
from nidataset.preprocessing import mip_dataset
views = ["axial", "coronal", "sagittal"]
base_path = "mip_multi_view/"
for view in views:
print(f"Processing {view} view...")
mip_dataset(
nii_folder="original_scans/",
output_path=base_path,
window_size=15,
view=view,
saving_mode="view",
debug=True
)
# Creates separate folders for each view
Processing Different Datasets
Apply MIP with optimized parameters for different scan types:
from nidataset.preprocessing import mip_dataset
datasets = {
'head_cta': {'folder': 'data/head_cta/', 'window': 10, 'view': 'axial'},
'neck_cta': {'folder': 'data/neck_cta/', 'window': 15, 'view': 'coronal'},
'chest_cta': {'folder': 'data/chest_cta/', 'window': 20, 'view': 'axial'}
}
for name, config in datasets.items():
print(f"Processing {name}...")
mip_dataset(
nii_folder=config['folder'],
output_path=f"mip_results/{name}/",
window_size=config['window'],
view=config['view'],
saving_mode="case",
debug=True
)
Comparing Window Sizes
Test different window sizes to find optimal enhancement:
from nidataset.preprocessing import mip_dataset
window_sizes = [5, 10, 15, 20, 30]
test_folder = "test_scans/"
for size in window_sizes:
mip_dataset(
nii_folder=test_folder,
output_path=f"window_comparison/size_{size}/",
window_size=size,
view="axial",
saving_mode="view",
debug=True
)
print(f"Completed window size {size} (effective: {2*size+1} slices)")
print("\nCompare outputs visually to select optimal window size")
Quality Control Workflow
Generate MIP and verify enhancement quality:
import nibabel as nib
import numpy as np
from nidataset.preprocessing import mip_dataset
# Generate MIP volumes
mip_dataset(
nii_folder="qa/originals/",
output_path="qa/mip_processed/",
window_size=15,
view="axial",
saving_mode="case",
debug=True
)
# Load and compare original vs MIP
original = nib.load("qa/originals/sample.nii.gz")
mip_vol = nib.load("qa/mip_processed/sample/axial/sample_mip_axial.nii.gz")
orig_data = original.get_fdata()
mip_data = mip_vol.get_fdata()
print(f"\nQuality Control:")
print(f" Original shape: {orig_data.shape}")
print(f" MIP shape: {mip_data.shape}")
print(f" Original intensity range: [{orig_data.min():.1f}, {orig_data.max():.1f}]")
print(f" MIP intensity range: [{mip_data.min():.1f}, {mip_data.max():.1f}]")
# Check enhancement (MIP should have higher mean in vessel regions)
vessel_region = orig_data[100:150, 100:150, :] # Example region
vessel_mip = mip_data[100:150, 100:150, :]
print(f" Original vessel region mean: {vessel_region.mean():.1f}")
print(f" MIP vessel region mean: {vessel_mip.mean():.1f}")
print(f" Enhancement factor: {vessel_mip.mean() / vessel_region.mean():.2f}x")
Integration with Segmentation Pipeline
Use MIP as preprocessing for vessel segmentation:
from nidataset.preprocessing import mip_dataset
from nidataset.volume import generate_brain_mask
# Step 1: Generate MIP volumes to enhance vessels
mip_dataset(
nii_folder="pipeline/raw_scans/",
output_path="pipeline/mip_enhanced/",
window_size=15,
view="axial",
saving_mode="case",
debug=True
)
# Step 2: Generate brain masks for MIP volumes
generate_brain_mask_dataset(
nii_folder="pipeline/mip_enhanced/",
output_path="pipeline/brain_masks/",
threshold=(80, 400), # Higher threshold for enhanced vessels
closing_radius=3,
debug=True
)
# Step 3: Apply masks to MIP volumes
import nibabel as nib
import os
mip_folder = "pipeline/mip_enhanced/"
mask_folder = "pipeline/brain_masks/"
output_folder = "pipeline/vessel_focused/"
os.makedirs(output_folder, exist_ok=True)
for case_folder in os.listdir(mip_folder):
case_path = os.path.join(mip_folder, case_folder, "axial")
if os.path.isdir(case_path):
for mip_file in os.listdir(case_path):
if mip_file.endswith('_mip_axial.nii.gz'):
# Load MIP and mask
mip = nib.load(os.path.join(case_path, mip_file))
mip_data = mip.get_fdata()
mask_file = mip_file.replace('_mip_axial', '_brain_mask')
mask = nib.load(os.path.join(mask_folder, mask_file))
mask_data = mask.get_fdata()
# Apply mask
vessel_focused = mip_data * mask_data
# Save
output_img = nib.Nifti1Image(vessel_focused, mip.affine)
output_path = os.path.join(output_folder, mip_file)
nib.save(output_img, output_path)
print("Vessel-focused volumes ready for segmentation")
Batch Processing with Progress Tracking
Process large datasets with detailed progress:
from nidataset.preprocessing import mip_dataset
import time
datasets = ['dataset_A', 'dataset_B', 'dataset_C']
total_start = time.time()
for i, dataset in enumerate(datasets, 1):
print(f"\n{'='*50}")
print(f"Processing dataset {i}/{len(datasets)}: {dataset}")
print(f"{'='*50}")
start_time = time.time()
mip_dataset(
nii_folder=f"data/{dataset}/",
output_path=f"results/{dataset}_mip/",
window_size=15,
view="axial",
saving_mode="case",
debug=True
)
elapsed = time.time() - start_time
print(f"Completed {dataset} in {elapsed:.1f} seconds")
total_elapsed = time.time() - total_start
print(f"\n{'='*50}")
print(f"All datasets processed in {total_elapsed:.1f} seconds")
Creating Training Data with MIP Enhancement
Prepare enhanced training dataset:
from nidataset.preprocessing import mip_dataset
from nidataset.slices import extract_slices_dataset
# Step 1: Generate MIP-enhanced volumes
mip_dataset(
nii_folder="training/raw_volumes/",
output_path="training/mip_volumes/",
window_size=15,
view="axial",
saving_mode="case",
debug=True
)
# Step 2: Extract 2D slices from MIP volumes
# First, collect all MIP files
import os
mip_files = []
for case in os.listdir("training/mip_volumes/"):
case_path = os.path.join("training/mip_volumes/", case, "axial")
if os.path.isdir(case_path):
for f in os.listdir(case_path):
if f.endswith('.nii.gz'):
mip_files.append(os.path.join(case_path, f))
# Create temporary folder with MIP files
temp_mip = "training/temp_mip/"
os.makedirs(temp_mip, exist_ok=True)
for mip_file in mip_files:
shutil.copy(mip_file, temp_mip)
# Extract slices
extract_slices_dataset(
nii_folder=temp_mip,
output_path="training/mip_slices/",
view="axial",
saving_mode="case",
target_size=(512, 512),
save_stats=True
)
print("MIP-enhanced training data prepared")
Analyzing Enhancement Effect
Quantify the MIP enhancement across dataset:
import nibabel as nib
import numpy as np
from nidataset.preprocessing import mip_dataset
import pandas as pd
# Generate MIP volumes
mip_dataset(
nii_folder="analysis/originals/",
output_path="analysis/mip/",
window_size=15,
view="axial",
saving_mode="view",
debug=True
)
# Analyze enhancement
results = []
for orig_file in os.listdir("analysis/originals/"):
if orig_file.endswith('.nii.gz'):
# Load original and MIP
orig = nib.load(f"analysis/originals/{orig_file}")
orig_data = orig.get_fdata()
mip_file = orig_file.replace('.nii.gz', '_mip_axial.nii.gz')
mip = nib.load(f"analysis/mip/axial/{mip_file}")
mip_data = mip.get_fdata()
# Calculate metrics
orig_mean = orig_data[orig_data > 0].mean()
mip_mean = mip_data[mip_data > 0].mean()
orig_max = orig_data.max()
mip_max = mip_data.max()
enhancement_ratio = mip_mean / orig_mean
results.append({
'file': orig_file,
'orig_mean': orig_mean,
'mip_mean': mip_mean,
'enhancement': enhancement_ratio,
'orig_max': orig_max,
'mip_max': mip_max
})
# Create summary
df = pd.DataFrame(results)
print("\nMIP Enhancement Analysis:")
print(f" Average enhancement: {df['enhancement'].mean():.2f}x")
print(f" Min enhancement: {df['enhancement'].min():.2f}x")
print(f" Max enhancement: {df['enhancement'].max():.2f}x")
print(f"\n Mean intensity increase: {(df['mip_mean'] - df['orig_mean']).mean():.1f}")
Typical Workflow
from nidataset.preprocessing import mip_dataset
import nibabel as nib
# 1. Define input and output paths
scan_folder = "dataset/angiography_scans/"
mip_output = "dataset/mip_enhanced/"
# 2. Generate MIP volumes with appropriate window size
mip_dataset(
nii_folder=scan_folder,
output_path=mip_output,
window_size=15, # Adjust based on vessel size
view="axial",
saving_mode="case",
debug=True
)
# 3. Verify a sample result
sample_orig = nib.load("dataset/angiography_scans/sample.nii.gz")
sample_mip = nib.load("dataset/mip_enhanced/sample/axial/sample_mip_axial.nii.gz")
print(f"Original shape: {sample_orig.shape}")
print(f"MIP shape: {sample_mip.shape}")
# 4. Use MIP volumes for:
# - Vessel detection and segmentation
# - Aneurysm identification
# - Vascular analysis
# - Training data for deep learning models