|
2 | 2 | import warnings
|
3 | 3 | import numpy as np
|
4 | 4 | from scipy.io import savemat as _save_mat
|
| 5 | +from nibabel import Nifti1Header, Nifti1Image |
5 | 6 | from nibabel.affines import from_matvec
|
6 | 7 | from .base import (
|
7 | 8 | BaseLinearTransformList,
|
@@ -280,3 +281,64 @@ def from_image(cls, imgobj):
|
280 | 281 | field[..., (0, 1)] *= -1.0
|
281 | 282 |
|
282 | 283 | return imgobj.__class__(field, imgobj.affine, hdr)
|
| 284 | + |
| 285 | + |
| 286 | +class ITKCompositeH5: |
| 287 | + """A data structure for ITK's HDF5 files.""" |
| 288 | + |
| 289 | + @classmethod |
| 290 | + def from_filename(cls, filename): |
| 291 | + """Read the struct from a file given its path.""" |
| 292 | + from h5py import File as H5File |
| 293 | + if not str(filename).endswith('.h5'): |
| 294 | + raise RuntimeError("Extension is not .h5") |
| 295 | + |
| 296 | + with H5File(str(filename)) as f: |
| 297 | + return cls.from_h5obj(f) |
| 298 | + |
| 299 | + @classmethod |
| 300 | + def from_h5obj(cls, fileobj, check=True): |
| 301 | + """Read the struct from a file object.""" |
| 302 | + xfm_list = [] |
| 303 | + h5group = fileobj["TransformGroup"] |
| 304 | + typo_fallback = "Transform" |
| 305 | + try: |
| 306 | + h5group['1'][f"{typo_fallback}Parameters"] |
| 307 | + except KeyError: |
| 308 | + typo_fallback = "Tranform" |
| 309 | + |
| 310 | + for xfm in reversed(h5group.keys())[:-1]: |
| 311 | + if h5group[xfm]["TransformType"][0].startswith(b"AffineTransform"): |
| 312 | + xfm_list.append( |
| 313 | + ITKLinearTransform( |
| 314 | + parameters=np.asanyarray(h5group[xfm][f"{typo_fallback}Parameters"]), |
| 315 | + offset=np.asanyarray(h5group[xfm][f"{typo_fallback}FixedParameters"]) |
| 316 | + ) |
| 317 | + ) |
| 318 | + continue |
| 319 | + if h5group[xfm]["TransformType"][0].startswith(b"DisplacementFieldTransform"): |
| 320 | + _fixed = np.asanyarray(h5group[xfm][f"{typo_fallback}FixedParameters"]) |
| 321 | + shape = _fixed[:3].astype('uint16').tolist() |
| 322 | + offset = _fixed[3:6].astype('uint16') |
| 323 | + zooms = _fixed[6:9].astype('float') |
| 324 | + directions = _fixed[9:].astype('float').reshape((3, 3)) |
| 325 | + affine = from_matvec(directions * zooms, offset) |
| 326 | + field = np.asanyarray(h5group[xfm][f"{typo_fallback}Parameters"]).reshape( |
| 327 | + tuple(shape + [-1]) |
| 328 | + ) |
| 329 | + hdr = Nifti1Header() |
| 330 | + hdr.set_intent("vector") |
| 331 | + hdr.set_data_dtype("float") |
| 332 | + |
| 333 | + xfm_list.append( |
| 334 | + ITKDisplacementsField.from_image( |
| 335 | + Nifti1Image(field.astype("float"), affine, hdr) |
| 336 | + ) |
| 337 | + ) |
| 338 | + continue |
| 339 | + |
| 340 | + raise NotImplementedError( |
| 341 | + f"Unsupported transform type {h5group[xfm]['TransformType'][0]}" |
| 342 | + ) |
| 343 | + |
| 344 | + return xfm_list |
0 commit comments