API Reference: I/O Utilities¶
Overview¶
The I/O utilities provide functions for loading, saving, and converting medical images. This document covers the INR format conversion functions. General-purpose load/save functions are documented in the overview.
Module: pycemrg_image_analysis.utilities.io
Public import: pycemrg_image_analysis.utilities
INR Format¶
INR (.inr) is a binary volumetric image format used by Inria. Key properties:
- Fixed-size 256-byte ASCII header (padded to the next 256-byte boundary for large headers)
- Voxel data in Fortran (x-fastest) order immediately after the header
- Carries spacing (
VX,VY,VZ) but no origin — origin is always treated as(0, 0, 0) - Supports integer and float scalar volumes (
VDIM=1only)
Supported dtypes:
INR TYPE |
PIXSIZE |
NumPy dtype |
|---|---|---|
unsigned fixed |
8 | uint8 |
unsigned fixed |
16 | uint16 |
unsigned fixed |
32 | uint32 |
signed fixed |
8 | int8 |
signed fixed |
16 | int16 |
signed fixed |
32 | int32 |
float |
32 | float32 |
float |
64 | float64 |
Quick Start¶
from pycemrg_image_analysis.utilities import convert_inr_to_image, convert_image_to_inr
from pathlib import Path
# Read an INR file → sitk.Image
image = convert_inr_to_image(Path("mesh/myocardium.inr"))
# Write a sitk.Image → INR file
convert_image_to_inr(image, Path("output/myocardium.inr"))
Functions¶
convert_inr_to_image()¶
Read an INR file and return a SimpleITK Image.
Signature:
Parameters:
- inr_path: Path to the .inr file
Returns: sitk.Image with spacing from the header and origin fixed at (0, 0, 0)
Raises:
- FileNotFoundError if inr_path does not exist
- ValueError if the header contains an unsupported TYPE / PIXSIZE combination
Notes:
- Voxel data is read as a flat Fortran-order buffer and reshaped to (XDIM, YDIM, ZDIM) before being handed to SimpleITK. The axis transposition from (x, y, z) to the (z, y, x) layout that SimpleITK expects is handled internally.
- Multi-component volumes (VDIM > 1) are not supported.
Example:
from pycemrg_image_analysis.utilities import convert_inr_to_image, save_image
from pathlib import Path
image = convert_inr_to_image(Path("segmentations/lv.inr"))
print(image.GetSize()) # (XDIM, YDIM, ZDIM)
print(image.GetSpacing()) # (VX, VY, VZ) from header
# Convert to NIfTI for downstream tools
save_image(image, Path("segmentations/lv.nii.gz"))
convert_image_to_inr()¶
Write a SimpleITK Image to an INR file.
Signature:
Parameters:
- image: The sitk.Image to serialize
- inr_path: Destination path for the .inr file (parent directories are created if missing)
Returns: None
Raises:
- ValueError if the image's pixel type has no INR equivalent (see supported dtypes table above)
Notes:
- The image origin is not written to the header. This is consistent with convert_inr_to_image, which always reads origin as (0, 0, 0). A round-trip through INR will lose any non-zero origin.
- Voxel data is extracted in (z, y, x) order from SimpleITK, transposed to (x, y, z), then written in Fortran order — matching the INR layout exactly.
- The header is padded with newlines to the next 256-byte boundary.
Example:
from pycemrg_image_analysis.utilities import load_image, convert_image_to_inr
from pathlib import Path
# Load a NIfTI segmentation and export for an INR-based meshing tool
seg = load_image(Path("segmentations/lv.nii.gz"))
convert_image_to_inr(seg, Path("mesh_input/lv.inr"))
Round-Trip Behaviour¶
image = convert_inr_to_image(Path("original.inr"))
convert_image_to_inr(image, Path("roundtrip.inr"))
# Voxel data and spacing are preserved exactly.
# Origin is always (0, 0, 0) — not round-tripped.
Common Pitfalls¶
Wrong: Expecting origin to be preserved¶
image = load_image(Path("scan.nii.gz"))
print(image.GetOrigin()) # e.g. (-150.0, -80.0, -200.0)
convert_image_to_inr(image, Path("scan.inr"))
recovered = convert_inr_to_image(Path("scan.inr"))
print(recovered.GetOrigin()) # (0.0, 0.0, 0.0) — origin is lost
Right: Re-apply origin after loading if it matters¶
original_origin = image.GetOrigin()
recovered = convert_inr_to_image(Path("scan.inr"))
recovered.SetOrigin(original_origin)
Wrong: Passing a float64 image when the meshing tool expects uint8¶
# Probability map is float64 — INR supports it, but meshing tools may not
convert_image_to_inr(prob_map, Path("mesh_input/prob.inr"))
Right: Cast before writing¶
import SimpleITK as sitk
label_map = sitk.Cast(prob_map, sitk.sitkUInt8)
convert_image_to_inr(label_map, Path("mesh_input/labels.inr"))
See Also¶
- Tests:
tests/unit/test_io.py - Related:
load_image(),save_image()for NIfTI/NRRD/MHA formats