InsightSoftwareConsortium / InsightSoftwareConsortium/ITK
ENH: Support reading MATLAB Level-5 (`.mat` v5) transform files in `itkMatlabTransformIO`
- Dominant language
- C++
- Stars
- 1.7k
- Forks
- 748
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 64
Description
`itkMatlabTransformIO` reads and writes only **MATLAB Level 4** — the 1980s fixed 20-byte header (`type/rows/cols/imag/namlen`) — via the vendored vnl `vnl_matlab_read*`/`vnl_matlab_write*` helpers. MATLAB has defaulted to the tagged Level 5 format since 1996 and to v7.3/HDF5 since R2006b, so ITK silently cannot open `.mat` files produced by any modern MATLAB.
This issue is to decide **whether** to widen to Level-5 *read* while keeping Level-4 read+write forever (the deployed corpus is non-negotiable), and if so, whether to hand-roll it in ITK or vendor matio.
Evidence that the current format really is Level 4
Dumping ITK's own test fixtures:
```
Transforms_double.mat type=0 rows=20 cols=1 name=AffineTransform_double_4_4
Transforms_float.mat type=10 rows=20 cols=1 name=AffineTransform_float_4_4
EmptyCompositeTransform_float.mat type=10 rows=0 name=CompositeTransform_float_3_3
IllegalMat.mat 9 bytes (deliberate bad-file test)
```
Every ITK `.mat` transform ever written by ANTs, Slicer, BRAINSTools, or any registration pipeline is Level 4. Real MATLAB (R2006+) can still *read* v4, but nothing modern *writes* it.
Consumer surface — it is genuinely tiny
- `Modules/IO/TransformMatlab/src/itkMatlabTransformIO.cxx` — the **only** real consumer. It uses roughly eight calls: `vnl_matlab_readhdr(istream)`, `operator!`, `.rows()`, `.cols()`, `.name()`, `.is_single()`, `.read_data(float*)`/`.read_data(double*)`, and `vnl_matlab_write(ostream, double*, n, name)`.
- `Modules/IO/TransformInsightLegacy/src/itkTxtTransformIO.cxx` — `#include`s `vnl/vnl_matlab_read.h` and `vnl/vnl_matlab_write.h` but uses **zero symbols** from either. Stale includes; deleting them is a trivial cleanup that is independent of everything else in this issue and can be done immediately.
The vendored code being relied on is **993 lines** total across `Modules/ThirdParty/VNL/src/vxl/core/vnl/vnl_matlab_{read,write,header,filewrite}.{h,cxx}`.
Third-party library survey (done 2026-07-21 — please don't redo it)
| Library | License | v4 read+write | v5 | Deps | Verdict |
|---|---|---|---|---|---|
| **matio** (tbeu/matio) | BSD-2 | **yes** | yes | none for v4-only; zlib for v5 compression, HDF5 for v7.3 | Only viable third-party candidate |
| matio-cpp (ami-iit) | BSD-2 | via matio | yes | **requires matio** | Additive, not substitutive |
| mat-v4 (bolderflight) | MIT | **write only** | no | none | Cannot read the corpus |
| TinyMAT (jkriege2) | **LGPL-2.1+** | no | write only | zlib | **License-blocked for ITK** |
| cvmatio | — | no | read | **OpenCV** | Non-starter |
matio 1.5.30 (Jan 2026) is actively maintained and its `mat4.c` backend is first-class, not deprecated (`Mat_VarRead4`, `Mat_VarWrite4`, `Mat_CreateVer(..., MAT_FT_MAT4)`). As of mid-2026 there is no permissive header-only single-file MAT *reader* covering Level 4.
**Argument against adopting matio:** it would become ITK's 27th ThirdParty module — 10-25 kLOC of C, `UpdateFromUpstream.sh` machinery, mangled headers, a `USE_SYSTEM_MATIO` path, and Slicer/BRAINSTools coordination — to replace 993 lines used by one file. It also carries a live CVE history (CVE-2025-50343 → `Mat_VarCreateStruct` deprecated in 1.5.30), so adopting it is a tracking obligation, not a vendor-and-forget.
Suggested approach
1. **Establish the actual user need first.** Is anyone filing issues about v5 `.mat` transforms, or is this speculative? Check Discourse (`https://discourse.itk.org/search.json?q=matlab+transform+mat+file`) and `gh issue list -S "matlab transform"` before investing.
2. **If the need is real, prefer read-only v5.** ITK should keep *writing* v4 forever for backward compatibility with the deployed corpus; only *reading* needs to widen. That halves the scope and sidesteps round-trip format questions.
3. **Evaluate ITK-owned code before vendoring.** Level 5's tagged format is more involved than v4 but still modest for the rank-2 numeric-array subset ITK needs (`miMATRIX` / `mxDOUBLE_CLASS` / `mxSINGLE_CLASS`, optionally `miCOMPRESSED` via the already-vendored zlib). An ITK-owned `itkMatlabTransformIOHelper` could be `SizeValueType`-clean, exception-based rather than `std::cerr`-based, and fuzz-tested — none of which the vendored vnl code is. It would also advance the broader VNL-decoupling direction already in flight.
4. **Only reach for matio if v7.3/HDF5 turns out to be required.** That is where hand-rolling stops being sensible, and since ITK already vendors HDF5 the marginal dependency cost there is lower than it first appears.
5. **Independently of all the above, delete the dead `vnl_matlab_*` includes from `itkTxtTransformIO.cxx`.**
Explicitly NOT covered by the already-merged #6682
#6575 item **B91** was a distinct, narrower defect: `vnl_matlab_readhdr::read_hdr()` omitted native type code `1010` (big-endian, column-wise, single-precision) from its no-swap `switch`, so big-endian hosts byte-swapped their own native headers as though foreign. Fixed in **PR #6682** (merged 2026-07-23), vendored-only by maintainer decision, no upstream vxl submission.
That is a **Level-4 endianness bug inside the existing reader**. It adds no Level-5 capability and does not resolve this issue. (B91 was reachable precisely because ITK writes `type=10` for float transforms on little-endian, hence `1010` on big-endian.)
Downstream constraint on any VNL API removal
If this work ends up removing or narrowing the vendored `vnl_matlab_*` API rather than merely layering on top of it, note that ITK-SNAP's vendored `greedy` submodule calls `vnl_matlab_read_or_die` directly (`Submodules/greedy/src/lmshoot/TestGeodesicShooting.cxx`). Any removal must account for it.
`Documentation/Maintenance/ThirdPartyForkConventions.md` documents the process cost that a matio adoption would incur.
Contributor guide
Research direction
First check the linked Discourse search and `gh issue list -S "matlab transform"` to establish whether Level-5 support is needed. Then read `Modules/IO/TransformMatlab/src/itkMatlabTransformIO.cxx` and the vendored `vnl_matlab_*` helpers, preserving existing Level-4 behavior while deciding the read-only Level-5 scope. Independently inspect `Modules/IO/TransformInsightLegacy/src/itkTxtTransformIO.cxx` for the stale includes; done means an agreed implementation path and coverage for the supported formats.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend, data
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100