33 lines
1.3 KiB
TypeScript
33 lines
1.3 KiB
TypeScript
/**
|
|
* Multi-label segmentation helpers (pure — no VTK, no DOM, unit-testable).
|
|
*
|
|
* A single labelsTr/<case>.nii.gz can encode many organs as integer voxel values
|
|
* (e.g. TotalSegmentator: 1..117). These split such a volume's scalar array into the
|
|
* distinct label values present, and into a per-value binary (0/1) mask the renderer
|
|
* can extract as one coloured iso-surface. The VTK wrappers live in `niftiLoader`.
|
|
*/
|
|
|
|
/** Distinct non-zero integer label values present in a segmentation's scalar array, ascending. */
|
|
export function distinctLabelValues(scalars: ArrayLike<number>): number[] {
|
|
const seen = new Set<number>();
|
|
for (let i = 0; i < scalars.length; i++) {
|
|
const v = scalars[i];
|
|
if (v > 0 && Number.isInteger(v)) seen.add(v);
|
|
}
|
|
return [...seen].sort((a, b) => a - b);
|
|
}
|
|
|
|
/** A binary (0/1) Uint8Array mask: 1 where the scalar equals `value`, else 0. */
|
|
export function binaryLabelMask(scalars: ArrayLike<number>, value: number): Uint8Array {
|
|
const out = new Uint8Array(scalars.length);
|
|
for (let i = 0; i < scalars.length; i++) {
|
|
if (scalars[i] === value) out[i] = 1;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/** True when a segmentation holds more than one distinct organ label (so it is worth splitting). */
|
|
export function isMultiLabel(scalars: ArrayLike<number>): boolean {
|
|
return distinctLabelValues(scalars).length > 1;
|
|
}
|