|
1 | 1 | """Utilities for loading transforms for resampling"""
|
| 2 | +import warnings |
2 | 3 | from pathlib import Path
|
3 | 4 |
|
4 | 5 | import h5py
|
@@ -44,42 +45,59 @@ def load_ants_h5(filename: Path) -> nt.TransformChain:
|
44 | 45 |
|
45 | 46 |
|
46 | 47 | FIXED_PARAMS = np.array([
|
47 |
| - 193.0, 229.0, 193.0, |
48 |
| - 96.0, 132.0, -78.0, |
49 |
| - 1.0, 1.0, 1.0, |
50 |
| - -1.0, 0.0, 0.0, |
| 48 | + 193.0, 229.0, 193.0, # Size |
| 49 | + 96.0, 132.0, -78.0, # Origin |
| 50 | + 1.0, 1.0, 1.0, # Spacing |
| 51 | + -1.0, 0.0, 0.0, # Directions |
51 | 52 | 0.0, -1.0, 0.0,
|
52 | 53 | 0.0, 0.0, 1.0,
|
53 | 54 | ]) # fmt:skip
|
54 | 55 |
|
55 | 56 |
|
56 |
| -def parse_combined_hdf5(h5_fn, to_ras=True): |
| 57 | +def parse_combined_hdf5(h5_fn): |
57 | 58 | # Borrowed from https://github.com/feilong/process
|
58 | 59 | # process.resample.parse_combined_hdf5()
|
59 | 60 | h = h5py.File(h5_fn)
|
60 | 61 | xform = ITKCompositeH5.from_h5obj(h)
|
61 | 62 | affine = xform[0].to_ras()
|
62 | 63 | transform2 = h['TransformGroup']['2']
|
| 64 | + |
63 | 65 | # Confirm these transformations are applicable
|
64 | 66 | if transform2['TransformType'][:][0] != b'DisplacementFieldTransform_float_3_3':
|
65 | 67 | msg = 'Unknown transform type [2]\n'
|
66 | 68 | for i in h['TransformGroup'].keys():
|
67 | 69 | msg += f'[{i}]: {h["TransformGroup"][i]["TransformType"][:][0]}\n'
|
68 | 70 | raise ValueError(msg)
|
69 |
| - if not np.array_equal(transform2['TransformFixedParameters'], FIXED_PARAMS): |
| 71 | + fixed_params = transform2['TransformFixedParameters'][:] |
| 72 | + if not np.array_equal(fixed_params, FIXED_PARAMS): |
70 | 73 | msg = 'Unexpected fixed parameters\n'
|
71 | 74 | msg += f'Expected: {FIXED_PARAMS}\n'
|
72 |
| - msg += f'Found: {transform2["TransformFixedParameters"][:]}' |
73 |
| - raise ValueError(msg) |
| 75 | + msg += f'Found: {fixed_params}' |
| 76 | + if not np.array_equal(fixed_params[6:], FIXED_PARAMS[6:]): |
| 77 | + raise ValueError(msg) |
| 78 | + warnings.warn(msg) |
| 79 | + |
| 80 | + shape = tuple(fixed_params[:3].astype(int)) |
74 | 81 | warp = h['TransformGroup']['2']['TransformParameters'][:]
|
75 |
| - warp = warp.reshape((193, 229, 193, 3)).transpose(2, 1, 0, 3) |
| 82 | + warp = warp.reshape((*shape, 3)).transpose(2, 1, 0, 3) |
76 | 83 | warp *= np.array([-1, -1, 1])
|
77 |
| - warp_affine = np.array( |
78 |
| - [ |
79 |
| - [1.0, 0.0, 0.0, -96.0], |
80 |
| - [0.0, 1.0, 0.0, -132.0], |
81 |
| - [0.0, 0.0, 1.0, -78.0], |
82 |
| - [0.0, 0.0, 0.0, 1.0], |
83 |
| - ] |
84 |
| - ) |
| 84 | + |
| 85 | + warp_affine = np.eye(4) |
| 86 | + warp_affine[:3, :3] = fixed_params[9:].reshape((3, 3)) |
| 87 | + warp_affine[:3, 3] = fixed_params[3:6] |
| 88 | + lps_to_ras = np.eye(4) * np.array([-1, -1, 1, 1]) |
| 89 | + warp_affine = lps_to_ras @ warp_affine |
| 90 | + if np.array_equal(fixed_params, FIXED_PARAMS): |
| 91 | + # Confirm that we construct the right affine when fixed parameters are known |
| 92 | + assert np.array_equal( |
| 93 | + warp_affine, |
| 94 | + np.array( |
| 95 | + [ |
| 96 | + [1.0, 0.0, 0.0, -96.0], |
| 97 | + [0.0, 1.0, 0.0, -132.0], |
| 98 | + [0.0, 0.0, 1.0, -78.0], |
| 99 | + [0.0, 0.0, 0.0, 1.0], |
| 100 | + ] |
| 101 | + ), |
| 102 | + ) |
85 | 103 | return affine, warp, warp_affine
|
0 commit comments