Skip to content

Cannot detect a transform file's stored parameter precision without fully reading it #6830

Description

@blowekamp

Summary

itk::TransformFileReaderTemplate<T> (and every concrete TransformIOBase backend: HDF5, Legacy/Txt, Matlab) silently coerces a stored transform's parameter precision to whatever T the reader was instantiated with, with no way for a caller to discover the file's actual on-disk precision without fully reading it into that precision.

This is a real cost for large transforms. A dense DisplacementFieldTransform stored in single precision (float) on disk gets its parameter array upconverted to double during the read itself, doubling that array's memory footprint, before a caller (e.g. SimpleITK, which only ever instantiates the double reader) has any chance to notice or opt out.

Where this happens

All three read backends funnel through the same choke point, TransformIOBaseTemplate<TParametersValueType>::CorrectTransformPrecisionType():

  • Modules/IO/TransformHDF5/src/itkHDF5TransformIO.cxx:317
  • Modules/IO/TransformInsightLegacy/src/itkTxtTransformIO.cxx:171
  • Modules/IO/TransformMatlab/src/itkMatlabTransformIO.cxx:103

Each reads the on-disk type-name string (e.g. "DisplacementFieldTransform_float_3_3") into a local variable, then calls Superclass::CorrectTransformPrecisionType(name) (Modules/IO/TransformBase/include/itkTransformIOBase.h:185-215), which mutates that string in place so it matches the reader's own template parameter ("float" -> "double" or vice versa) before CreateTransform() instantiates the transform. The original, as-stored name is discarded — there is no accessor that exposes it afterward.

Concretely, in HDF5TransformIOTemplate<TParametersValueType>::ReadParameters() (itkHDF5TransformIO.cxx:159-201), the numeric conversion is an explicit per-element static_cast<ParametersValueType>(buf[i]) from whatever the file actually stored. There is no way to ask "is this file float or double?" without going through this same path — i.e., without reading (and precision-converting) the entire parameter array.

Both TransformFileReaderTemplate<float> and TransformFileReaderTemplate<double> are fully instantiated and available, but neither one's success/failure is diagnostic of the file's real precision: CorrectTransformPrecisionType unconditionally coerces the name to match whichever template you picked, so reading a double-precision file with the float reader "succeeds" too (silently downcasting), and vice versa.

Request

  1. A cheap way to query a transform file's stored parameter precision (float/double) — analogous to ImageIOBase::ReadImageInformation() for images — without reading the full parameter array. Ideally exposed uniformly across backends via TransformIOBaseTemplate, since format-specific type-name parsing is already centralized in CorrectTransformPrecisionType.
  2. Failing that (as a smaller first step), simply preserve the as-stored type name string as a member on TransformIOBaseTemplate before CorrectTransformPrecisionType mutates it, with a public getter (e.g. GetReadTransformTypeName()). This costs nothing extra (the string is already read for every transform read) and would let callers such as TransformFileReader::GetTransformIO()->GetReadTransformTypeName() at least detect after a read that an implicit precision conversion happened, and warn the user.

Motivating context

This surfaced while investigating SimpleITK#2710: SimpleITK's Transform wraps itk::TransformBaseTemplate<double> exclusively, so sitk.ReadTransform() always uses the double-precision reader. For a float-precision DisplacementFieldTransform stored on disk, this means every read silently doubles the field's memory footprint with no diagnostic — worse than the already-reported cost of sitk.DisplacementFieldTransform(image), which at least throws when handed a float32 image directly rather than converting silently.

Measured example: a 4003 float32 displacement field (768 MiB on disk) read via sitk.ReadTransform() added ~3.6 GiB of RSS versus ~1.5 GiB for an explicit sitk.Cast(field, sitk.sitkVectorFloat64) + DisplacementFieldTransform construction of the same field read as a plain image — the transform-file path is both silent and, in this measurement, more expensive than the already-known workaround.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions