Cookbook 68: Offline Clinical Neurology Stroke Ischemic Core & Penumbra Perfusion Engine

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.

1. Overview & Use Case

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 ]

2. Installation & Prerequisites

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

3. Dynamic 4D CTP Preprocessing & AIF Extraction

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}")

4. Inference & Penumbra / Core Mismatch Calculation

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}")

5. Verification & Summary

This engine delivers instant, offline acute ischemic stroke perfusion triage conforming to AHA/ASA endovascular thrombectomy guidelines.