skills/cv/dicom-ipp-z-slice-sort/SKILL.md
Order DICOM slices into a coherent 3D volume by sorting on ImagePositionPatient[2] (the Z coordinate in patient space), with a filename-integer fallback for series whose tag is missing — never trust filename alphabetical order, never trust InstanceNumber
npx skillsauth add wenmin-wu/ds-skills cv-dicom-ipp-z-slice-sortInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
DICOM filenames in a CT series are not guaranteed to be in anatomical order. Different scanners, anonymizers, and export tools produce wildly inconsistent name schemes — 1.dcm may be the topmost slice on one study and the bottommost on the next. InstanceNumber is also unreliable: it can be reset, missing, or assigned in scan order rather than spatial order. The single trustworthy ordering is ImagePositionPatient[2], the Z coordinate of the slice in patient space — sort by it ascending and you get a consistent head→feet (or feet→head, fix later) volume regardless of vendor. Keep an integer-filename fallback for the few exports that strip the tag entirely.
import pydicom
from os import listdir
def load_scans(dcm_dir):
files = listdir(dcm_dir)
try:
slices = [pydicom.dcmread(f'{dcm_dir}/{f}') for f in files]
slices.sort(key=lambda s: float(s.ImagePositionPatient[2]))
except (AttributeError, KeyError):
# fallback: integer-filename order when IPP tag is missing
nums = sorted(int(f.split('.')[0]) for f in files)
slices = [pydicom.dcmread(f'{dcm_dir}/{n}.dcm') for n in nums]
return slices
.dcm file in the series directorypydicom.dcmread and key the sort on float(ds.ImagePositionPatient[2])try/except (AttributeError, KeyError) to catch the rare missing-tag seriespixel_arrays in the resulting order and apply RescaleSlope/Intercept to get HUImagePositionPatient[2], not [0] or [1]: index 2 is the through-plane axis (Z) for axial CT; the other indices are in-plane translation and are constant across slices.cv-ct-z-stack-orientation-flip).'10.dcm' sorts before '2.dcm' lexicographically; integer parsing fixes it.float() cast required: pydicom returns the position as DSfloat which is a string-ish type and won't compare correctly without the cast.data-ai
Scaled Pinball Loss (SPL) metric for evaluating quantile forecasts, normalized by mean absolute successive differences of training data
data-ai
Walk backward through a time series and multiplicatively rescale segments when jumps exceed a fraction of the running mean to correct data collection anomalies
testing
Transform forecasting target to next/current ratio minus one so that optimizing MAE or squared error implicitly minimizes SMAPE
tools
Convert point forecasts to prediction intervals by scaling with logit-transformed quantile ratios passed through a Normal CDF