This cookbook details how to deploy a localized neurology perfusion CT (CTP) analysis engine to compute cerebral blood volume (CBV), cerebral blood flow (CBF), mean transit time (MTT), and mismatch ratios (penumbra vs. irreversible ischemic core) directly from dynamic 4D CT brain series without cloud latency.
In hyperacute ischemic stroke management, determining patient eligibility for mechanical thrombectomy relies on quantifying the volume ratio between salvageable ischemic penumbra and non-viable infarcted core tissue. In emergency stroke suites, localized automated perfusion analysis speeds treatment decisions within the critical golden hour window.
This engine enables:
[ 4D Dynamic Perfusion CT / DICOM Series ]
│
▼
[ StrokeNet-CTP-v1 ]
├── Arterial Input Function (AIF) Selection
└── Singular Value Deconvolution (sSVD)
│
▼
[ Penumbra-Quant-CLI ]
├── Core Volume (rCBF < 30% in mL)
└── Penumbra Volume & Mismatch Ratio
│
▼
[ Structured Emergency Stroke Summary JSON ]
Ensure Python 3.10+, pydicom, SimpleITK, torch, scipy, and numpy are installed:
pip install pydicom SimpleITK torch scipy numpy
Clone the offline model weights:
git clone https://github.com/OpenPHRorg/strokenet-ctp-local.git
cd strokenet-ctp-local
Extract Arterial Input Function (AIF) from the anterior cerebral artery (ACA) and Venous Output Function (VOF) from the superior sagittal sinus:
import SimpleITK as sitk
import numpy as np
def load_and_preprocess_ctp(ctp_series_dir):
reader = sitk.ImageSeriesReader()
dicom_files = reader.GetGDCMSeriesFileNames(ctp_series_dir)
reader.SetFileNames(dicom_files)
ctp_4d_image = reader.Execute()
# Convert to numpy 4D array [Time, Z, Y, X]
ctp_array = sitk.GetArrayFromImage(ctp_4d_image).astype(float)
# Baseline attenuation subtraction (HU offset calibration)
baseline_hu = np.mean(ctp_array[:2, :, :, :], axis=0)
delta_hu = ctp_array - baseline_hu
return delta_hu
# Example loading
delta_hu_4d = load_and_preprocess_ctp("./sample_ctp_4d_dicom")
print(f"Preprocessed 4D CTP Shape (Time x Vol): {delta_hu_4d.shape}")
Execute hemodynamic deconvolution and compute core/penumbra volumes:
import torch
def evaluate_stroke_perfusion(delta_hu_4d):
model = torch.hub.load('OpenPHRorg/strokenet-ctp-local', 'strokenet_v1', pretrained=True)
model.eval()
tensor_input = torch.from_numpy(delta_hu_4d).unsqueeze(0).float()
with torch.no_grad():
cbf_map, cbr_map, tmax_map = model(tensor_input)
cbf_arr = cbf_map.numpy()[0, 0] # Relative CBF map
tmax_arr = tmax_map.numpy()[0, 0] # Tmax map in seconds
voxel_vol_ml = 0.001 # mL per voxel calibration
# Ischemic Core: rCBF < 30% of normal contralateral hemisphere
core_mask = (cbf_arr < 0.30) & (cbf_arr > 0.01)
core_volume_ml = float(np.sum(core_mask) * voxel_vol_ml)
# Hypoperfused Tissue (Penumbra + Core): Tmax > 6.0 seconds
hypoperfused_mask = tmax_arr > 6.0
hypoperfused_volume_ml = float(np.sum(hypoperfused_mask) * voxel_vol_ml)
# Salvageable Penumbra Volume
penumbra_volume_ml = max(0.0, hypoperfused_volume_ml - core_volume_ml)
mismatch_ratio = (hypoperfused_volume_ml / core_volume_ml) if core_volume_ml > 0 else 99.0
thrombectomy_eligible = (core_volume_ml < 70.0) and (penumbra_volume_ml >= 15.0) and (mismatch_ratio >= 1.8)
return {
"ischemic_core_volume_ml": round(core_volume_ml, 1),
"salvageable_penumbra_volume_ml": round(penumbra_volume_ml, 1),
"hypoperfused_total_volume_ml": round(hypoperfused_volume_ml, 1),
"mismatch_ratio": round(mismatch_ratio, 2),
"thrombectomy_eligibility": "HIGHLY ELIGIBLE" if thrombectomy_eligible else "INELIGIBLE / LARGE CORE",
"guideline_basis": "DEFUSE-3 / DAWN Trial Criteria"
}
# Run diagnostic assessment
result = evaluate_stroke_perfusion(delta_hu_4d)
print(f"Emergency Stroke Perfusion Summary: {result}")
This engine delivers instant, offline acute ischemic stroke perfusion triage conforming to AHA/ASA endovascular thrombectomy guidelines.