segstats
tit.atlas.segstats ¶
Pure-Python replacement for FreeSurfer's mri_segstats (region listing).
Lists the unique nonzero integer labels present in a volumetric atlas, with
names resolved from a lookup table (LUT) and voxel counts/volumes computed
directly from the array -- replacing the two
mri_segstats --seg <atlas> --excludeid 0 --ctab-default --sum <out>
subprocess calls in :mod:tit.atlas.voxel and :mod:tit.analyzer.analyzer.
Validated voxel-for-voxel against live mri_segstats (FreeSurfer 7.4.1,
idossha/ti-toolbox_freesurfer:v7.4.1) on sub-ernie's real recon-all
output (aparc.DKTatlas+aseg.mgz, aparc.a2009s+aseg.mgz,
ThalamicNuclei.v13.T1.mgz) and charm's own labeling.nii.gz: identical
label-id sets and voxel counts in every case (see
docs/dev/DECISIONS.md ยง 2026-09-03 (One Docker image and a real development loop) for the exact commands and
numbers).
Public API¶
SegStat
One label's id, name, voxel count and volume.
load_lut
Parse a FreeSurfer-style colour lookup table into {id: name}.
resolve_lut_for_atlas
Pick the right LUT for a voxel atlas: a sidecar file next to it, or the
bundled standard FreeSurfer colour table as a fallback.
compute_segstats
List labels present in a volume with names, voxel counts and volumes.
format_segstats_sum / write_segstats_sum
Render :class:SegStat rows in mri_segstats --sum's own text layout,
kept byte-compatible because other modules in this codebase discover and
parse this exact sidecar filename pattern.
SegStat
dataclass
¶
One label's identity, size and name in a voxel atlas.
Attributes¶
seg_id : int
Integer voxel label.
name : str
Region name, resolved from a LUT or "Label {seg_id}" if
unresolved.
n_voxels : int
Count of voxels carrying this label.
volume_mm3 : float
n_voxels times the volume of one voxel, from the image's own
affine (|det(affine[:3, :3])|).
load_lut ¶
Parse a FreeSurfer-style colour lookup table into {id: name}.
Column-order agnostic (mirrors
:func:tit.opt.roi_spec._parse_lut_line): on each non-comment,
non-blank line the first all-digit token is the label id and the
remaining non-numeric tokens are joined as the name (so a trailing
R G B A colour triple/quad is naturally excluded).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lut_path
|
str
|
Path to a LUT text file. |
required |
Returns:
| Type | Description |
|---|---|
dict[int, str]
|
|
dict[int, str]
|
be read. |
Source code in tit/atlas/segstats.py
resolve_lut_for_atlas ¶
Pick the LUT that names atlas_path's integer labels.
Mirrors the sidecar-first, bundled-fallback resolution already used for
display names elsewhere in the codebase
(:func:tit.opt.roi_spec.resolve_volume_label_names,
RoiPickerWidget._find_volume_lut): a sidecar colour table sitting
next to the atlas file wins (labeling_LUT.txt for charm's
labeling.nii.gz, else {stem}_LUT.txt); for the legacy thalamic-
nuclei atlas family (ThalamicNuclei.v13.T1*.mgz) the vendored
resources/atlas/ThalamicNuclei_LUT.txt is tried next (FreeSurfer's
own id -> name table for that atlas, absent from the general-purpose
FreeSurferColorLUT.txt); and the bundled standard FreeSurfer colour
table (resources/atlas/FreeSurferColorLUT.txt, --ctab-default's
own table) is the final fallback -- covering the other FreeSurfer volume
atlases (aparc.DKTatlas+aseg.mgz and friends) that ship no sidecar of
their own.
The thalamic-nuclei table is a fixed id -> name mapping, not read from
the per-subject ThalamicNuclei.v13.T1.volumes.txt sidecar some
recon-all outputs carry: that file lists names in a fixed but
non-numeric (anatomically grouped) order that does not line up 1:1
against any one subject's own sorted voxel-label ids -- confirmed against
three real subjects' derivatives, where the set of ids actually
carrying voxels differs subject to subject (small nuclei are sometimes
absent), so pairing by row order would silently produce wrong names for
some ids. See ThalamicNuclei_LUT.txt's own header for the full
citation and verification note.
Deliberately does not treat a {stem}_labels.txt file as a LUT
candidate: that filename is this module's own mri_segstats-format
cache (see :func:write_segstats_sum), not a colour table -- confusing
the two would misparse the summary's Index/NVoxels/Volume_mm3
columns as label names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
atlas_path
|
str
|
Absolute path to the atlas volume. |
required |
Returns:
| Type | Description |
|---|---|
dict[int, str]
|
|
dict[int, str]
|
can be found or read. |
Source code in tit/atlas/segstats.py
compute_segstats ¶
List labels present in atlas_path with names, voxel counts and volumes.
Replaces mri_segstats --seg <atlas_path> --excludeid 0 --sum <out>:
every unique nonzero integer voxel value becomes one :class:SegStat,
named via lut ("Label {id}" when unresolved), with n_voxels
from :func:numpy.unique and volume_mm3 = n_voxels *
|det(affine[:3, :3])| -- matches mri_segstats's own per-voxel
volume for an orthogonal affine (the case for every atlas this codebase
ships or produces). Validated with exact voxel-count matches against
live mri_segstats output (module docstring).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
atlas_path
|
str
|
Path to a label volume ( |
required |
lut
|
dict[int, str] | None
|
Optional |
None
|
Returns:
| Type | Description |
|---|---|
list[SegStat]
|
class: |
list[SegStat]
|
|
Source code in tit/atlas/segstats.py
format_segstats_sum ¶
Render stats in mri_segstats --sum's own text layout.
Kept byte-compatible with FreeSurfer's historical output columns
(Index SegId NVoxels Volume_mm3 StructName) because other modules in
this codebase (:mod:tit.opt.roi_spec, :mod:tit.viewspec) discover and
parse this exact sidecar filename pattern ({atlas_stem}_labels.txt)
for cache reuse -- changing the column layout would silently break those
readers.
Source code in tit/atlas/segstats.py
write_segstats_sum ¶
Write :func:format_segstats_sum's text to out_path.