/** * Minimal MetaImage (.mhd) header parser. * * Deliberately dependency-free (no three.js) so it can run under * `node --experimental-strip-types --test`. * * Only the subset the 4D ultrasound data uses is supported: 3D, uncompressed, * uint8. Anything else throws rather than silently mis-rendering. */ export type Matrix3x3 = [number, number, number, number, number, number, number, number, number]; /** Row-major identity — the value MetaImage writes when it has no real orientation. */ export declare const IDENTITY_MATRIX: Matrix3x3; export interface MhdHeader { /** DimSize — x is the fastest-varying axis. e.g. [189, 189, 134] */ dims: [number, number, number]; /** ElementSpacing in mm. e.g. [1, 1, 1] */ spacing: [number, number, number]; /** ElementType, always "MET_UCHAR" here. */ elementType: string; /** CompressedData — always false here (true is rejected). */ compressed: boolean; /** ElementDataFile, relative to the .mhd. e.g. "DZET01_17871377_000.raw" */ elementDataFile: string; /** Offset — world coordinates of voxel (0,0,0). Defaults to the origin. */ offset: [number, number, number]; /** TransformMatrix — row-major direction cosines. Defaults to the identity. */ transformMatrix: Matrix3x3; /** AnatomicalOrientation, e.g. "RAI". `null` when absent. */ anatomicalOrientation: string | null; /** * MetaImage has no standard way to assert "this is the same world frame as that MRI". * DICOM does — FrameOfReferenceUID (0020,0052). MetaImage readers ignore unknown keys, * so a producer can carry the UID across as a custom line. `null` when absent. */ frameOfReferenceUID: string | null; /** * True when Offset or TransformMatrix carry real values, i.e. the header actually places * the volume somewhere. A zero offset with an identity matrix is ambiguous — it may mean * "at the origin, unrotated" or "nobody filled this in" — and is treated as the latter, * because silently trusting it is the dangerous failure mode. */ hasPose: boolean; /** True when ElementSpacing is not the placeholder 1 1 1, i.e. real physical voxel size. */ hasRealSpacing: boolean; } export declare function parseMhdHeader(text: string): MhdHeader; export type RegistrationReason = "no-pose" | "frame-missing" | "frame-mismatch" | "unverified" | "verified"; export interface RegistrationDecision { /** Honour the header's placement? */ registered: boolean; /** Did a FrameOfReferenceUID actually prove the shared world frame? */ frameVerified: boolean; reason: RegistrationReason; } /** * Decide whether a header's pose may be trusted. * * Two independent things must hold, and the second is the one people forget: * * 1. the header must actually carry a pose (`hasPose`), and * 2. that pose must be expressed in the SAME world frame as the scene. * * DICOM proves (2) with FrameOfReferenceUID. MetaImage has no such field, so a producer must * carry the UID across as a custom line. When the caller names the scene's frame and the file * cannot match it, the pose is refused — a pose in another scanner's coordinate system is * worse than no pose at all, because it looks authoritative while being wrong. * * When the caller names no frame, a pose is honoured but reported as `unverified`: nobody * checked, and the UI should not claim otherwise. */ export declare function resolveRegistration(header: MhdHeader, expectedFrameOfReferenceUID?: string | null): RegistrationDecision; /** * voxel index -> world, as a column-major 4x4 (three.js `Matrix4.elements` order). * * ITK/MetaImage convention: `world = Offset + D · (Spacing ∘ index)`, with `D` the * row-major direction matrix from TransformMatrix. * * Only meaningful when `header.hasPose` — otherwise this is the identity scaled by * spacing, which places the volume at the world origin and means nothing. */ export declare function voxelToWorldMatrix(header: MhdHeader): number[]; /** Number of voxels implied by the header — equals the .raw byte length for uint8. */ export declare function voxelCount(header: MhdHeader): number;