1 /*
2 * Medical Image Registration ToolKit (MIRTK)
3 *
4 * Copyright 2008-2015 Imperial College London
5 * Copyright 2008-2013 Daniel Rueckert, Julia Schnabel
6 * Copyright 2013-2015 Andreas Schuh
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #ifndef MIRTK_ImageAttributes_H
22 #define MIRTK_ImageAttributes_H
23
24 #include "mirtk/Indent.h"
25 #include "mirtk/Matrix.h"
26 #include "mirtk/Point.h"
27 #include "mirtk/Array.h"
28
29
30 namespace mirtk {
31
32
33 /**
34 * Class which defines the attributes of the imaging geometry
35 */
36 struct ImageAttributes
37 {
38 // ---------------------------------------------------------------------------
39 // Attributes
40 int _x; ///< Image x-dimension (in voxels)
41 int _y; ///< Image y-dimension (in voxels)
42 int _z; ///< Image z-dimension (in voxels)
43 int _t; ///< Image t-dimension (in voxels)
44
45 double _dx; ///< Voxel x-dimensions (in mm)
46 double _dy; ///< Voxel y-dimensions (in mm)
47 double _dz; ///< Voxel z-dimensions (in mm)
48 double _dt; ///< Voxel t-dimensions (in ms)
49
50 double _xorigin; ///< Image x-origin (in mm)
51 double _yorigin; ///< Image y-origin (in mm)
52 double _zorigin; ///< Image z-origin (in mm)
53 double _torigin; ///< Image t-origin (in ms)
54
55 double _xaxis[3]; ///< Direction of x-axis
56 double _yaxis[3]; ///< Direction of y-axis
57 double _zaxis[3]; ///< Direction of z-axis
58
59 Matrix _smat; ///< Affine transformation matrix
60
61 const Matrix *_w2i; ///< Pointer to pre-computed world to image matrix (cf. BaseImage::_matW2I)
62 const Matrix *_i2w; ///< Pointer to pre-computed image to world matrix (cf. BaseImage::_matI2W)
63
64 /// Number of lattice points in image domain
65 int NumberOfLatticePoints() const;
66
67 /// Number of spatial lattice points
68 int NumberOfSpatialPoints() const;
69
70 /// Number of lattice points
71 /// (i.e., NumberOfLatticePoints if _dt != 0, otherwise NumberOfSpatialPoints)
72 int NumberOfPoints() const;
73
74 /// Get number of lattice points in x dimension
75 int X() const;
76
77 /// Get number of lattice points in y dimension
78 int Y() const;
79
80 /// Get number of lattice points in z dimension
81 int Z() const;
82
83 /// Get number of lattice points in t dimension
84 int T() const;
85
86 /// Get number of lattice points in i-th dimension
87 int N(int) const;
88
89 /// Get spacing of lattice points in i-th dimension
90 double Spacing(int) const;
91
92 /// Get spacing of lattice points in x dimension
93 double XSpacing() const;
94
95 /// Get spacing of lattice points in y dimension
96 double YSpacing() const;
97
98 /// Get spacing of lattice points in z dimension
99 double ZSpacing() const;
100
101 /// Get spacing of lattice points in t dimension
102 double TSpacing() const;
103
104 /// Get voxel size/spacing of lattice points in x dimension
105 double XSize() const;
106
107 /// Get voxel size/spacing of lattice points in y dimension
108 double YSize() const;
109
110 /// Get voxel size/spacing of lattice points in z dimension
111 double ZSize() const;
112
113 /// Get voxel size/spacing of lattice points in t dimension
114 double TSize() const;
115
116 // ---------------------------------------------------------------------------
117 // Construction/Destruction
118
119 /// Constructor
120 ImageAttributes();
121
122 /// Constructor
123 ImageAttributes(int, int, double = 1.0, double = 1.0);
124
125 /// Constructor
126 ImageAttributes(int, int, int, double = 1.0, double = 1.0, double = 1.0);
127
128 /// Constructor
129 ImageAttributes(int, int, int, int, double = 1.0, double = 1.0, double = 1.0, double = 1.0);
130
131 /// Copy constructor
132 ImageAttributes(const ImageAttributes &);
133
134 /// Copy operator
135 ImageAttributes& operator= (const ImageAttributes &);
136
137 /// Check if attributes are valid
138 operator bool() const;
139
140 // ---------------------------------------------------------------------------
141 // Comparison
142
143 /// Whether given lattice is fully contained by this image lattice
144 bool ContainsInSpace(const ImageAttributes &attr) const;
145
146 /// Whether spatial attributes are equal
147 bool EqualInSpace(const ImageAttributes &attr) const;
148
149 /// Whether temporal attributes are equal
150 bool EqualInTime(const ImageAttributes &attr) const;
151
152 /// Equality operator
153 bool operator==(const ImageAttributes &attr) const;
154
155 /// Inequality operator
156 bool operator!=(const ImageAttributes &attr) const;
157
158 // ---------------------------------------------------------------------------
159 // Coordinate conversion
160
161 /// Get Index from Lattice
162 int LatticeToIndex(int, int, int = 0, int = 0) const;
163
164 /// Get Index from Lattice
165 void IndexToLattice(int, int *, int *, int * = NULL, int * = NULL) const;
166
167 /// Get Index from Lattice
168 void IndexToLattice(int, int &, int &) const;
169
170 /// Get Index from Lattice
171 void IndexToLattice(int, int &, int &, int &) const;
172
173 /// Get Index from Lattice
174 void IndexToLattice(int, int &, int &, int &, int &) const;
175
176 /// Get world coordinates (in mm) of lattice point
177 void IndexToWorld(int, double &, double &) const;
178
179 /// Get world coordinates (in mm) of lattice point
180 void IndexToWorld(int, double &, double &, double &) const;
181
182 /// Get world coordinates (in mm) of lattice point
183 void IndexToWorld(int, Point &) const;
184
185 /// Get world coordinates (in mm) of lattice point
186 Point IndexToWorld(int) const;
187
188 /// Convert lattice to world coordinate
189 void LatticeToWorld(Point &) const;
190
191 /// Convert lattice to world coordinate
192 void LatticeToWorld(double &, double &, double &) const;
193
194 /// Compute spatial world coordinates of lattice points (_x * _y * _z)
195 void LatticeToWorld(double *, double *, double *) const;
196
197 /// Compute world coordinates of all lattice points (_x * _y * _z * _t)
198 void LatticeToWorld(double *, double *, double *, double *) const;
199
200 /// Convert world to lattice coordinate
201 void WorldToLattice(double &, double &, double &) const;
202
203 /// Convert lattice to world coordinate
204 void WorldToLattice(Point &) const;
205
206 /// Convert lattice to time coordinate
207 double LatticeToTime(double) const;
208
209 /// Convert time to lattice coordinate
210 double TimeToLattice(double) const;
211
212 /// Put affine world coordinate transformation which is applied
213 /// after the image to world coordinate transformation derived from the
214 /// imaging geometry when mapping voxel indices to world coordinates.
215 /// This transformation can be the inverse of the affine transformation
216 /// obtained by an affine registration with this image as source.
217 ///
218 /// \param[in] m Homogeneous transformation matrix.
219 /// \param[in] apply Whether to apply the translation, rotation, and
220 /// scaling directly to the image attributes and store
221 /// only the shearing (if any) as additional transformation.
222 void PutAffineMatrix(const Matrix &m, bool apply = false);
223
224 /// Return transformation matrix for lattice to world coordinates
225 Matrix GetLatticeToWorldMatrix() const;
226
227 /// Return transformation matrix for world to lattice coordinates
228 Matrix GetWorldToLatticeMatrix() const;
229
230 /// Return orientation part of lattice to world coordinate transformation
231 Matrix GetLatticeToWorldOrientation() const;
232
233 /// Return orientation part of lattice to world coordinate transformation
234 Matrix GetWorldToLatticeOrientation() const;
235
236 /// Alias for GetLatticeToWorldMatrix
GetImageToWorldMatrixImageAttributes237 inline Matrix GetImageToWorldMatrix() const { return GetLatticeToWorldMatrix(); }
238 /// Alias for GetWorldToLatticeMatrix
GetWorldToImageMatrixImageAttributes239 inline Matrix GetWorldToImageMatrix() const { return GetWorldToLatticeMatrix(); }
240 /// Alias for GetLatticeToWorldOrientation
GetImageToWorldOrientationImageAttributes241 inline Matrix GetImageToWorldOrientation() const { return GetLatticeToWorldOrientation(); }
242 /// Alias for GetWorldToLatticeOrientation
GetWorldToImageOrientationImageAttributes243 inline Matrix GetWorldToImageOrientation() const { return GetWorldToLatticeOrientation(); }
244
245 // ---------------------------------------------------------------------------
246 // Voxel index checks
247
248 /// Whether voxel index is within finite image domain
249 bool IsInside(int) const;
250
251 /// Whether voxel indices are within finite 2D image domain
252 bool IsInside(int, int) const;
253
254 /// Whether voxel indices are within finite 3D image domain
255 bool IsInside(int, int, int) const;
256
257 /// Whether voxel indices are within finite 4D image domain
258 bool IsInside(int, int, int, int) const;
259
260 /// Whether voxel is index is outside finite image domain
261 bool IsOutside(int) const;
262
263 /// Whether voxel indices are outside finite 4D image domain
264 bool IsOutside(int, int) const;
265
266 /// Whether voxel indices are outside finite 4D image domain
267 bool IsOutside(int, int, int) const;
268
269 /// Whether voxel indices are outside finite 4D image domain
270 bool IsOutside(int, int, int, int) const;
271
272 /// Whether voxel index is at boundary of finite image domain
273 bool IsBoundary(int) const;
274
275 /// Whether voxel indices are at boundary of finite 2D image domain
276 bool IsBoundary(int, int) const;
277
278 /// Whether voxel indices are at boundary of finite 3D image domain
279 bool IsBoundary(int, int, int) const;
280
281 /// Whether voxel indices are at boundary of finite 4D image domain
282 bool IsBoundary(int, int, int, int) const;
283
284 // ---------------------------------------------------------------------------
285 // Output
286
287 /// Image slice area in world space
288 double Area() const;
289
290 /// Image volume in world space
291 double Volume() const;
292
293 /// Amount of space occupied by the image in n-D world space (excluding time dimension)
294 double Space() const;
295
296 /// Print attributes
297 void Print(ostream &, Indent = 0) const;
298
299 /// Print attributes
300 void Print(Indent = 0) const;
301
302 };
303
304 ////////////////////////////////////////////////////////////////////////////////
305 // Inline definitions
306 ////////////////////////////////////////////////////////////////////////////////
307
308 // -----------------------------------------------------------------------------
X()309 inline int ImageAttributes::X() const
310 {
311 return _x;
312 }
313
314 // -----------------------------------------------------------------------------
Y()315 inline int ImageAttributes::Y() const
316 {
317 return _y;
318 }
319
320 // -----------------------------------------------------------------------------
Z()321 inline int ImageAttributes::Z() const
322 {
323 return _z;
324 }
325
326 // -----------------------------------------------------------------------------
T()327 inline int ImageAttributes::T() const
328 {
329 return _t;
330 }
331
332 // -----------------------------------------------------------------------------
N(int i)333 inline int ImageAttributes::N(int i) const
334 {
335 if (i == 0) return _x;
336 if (i == 1) return _y;
337 if (i == 2) return _z;
338 if (i == 3) return _t;
339 return 0;
340 }
341
342 // -----------------------------------------------------------------------------
Spacing(int i)343 inline double ImageAttributes::Spacing(int i) const
344 {
345 if (i == 0) return _dx;
346 if (i == 1) return _dy;
347 if (i == 2) return _dz;
348 if (i == 3) return _dt;
349 return 0.;
350 }
351
352 // -----------------------------------------------------------------------------
XSpacing()353 inline double ImageAttributes::XSpacing() const
354 {
355 return _dx;
356 }
357
358 // -----------------------------------------------------------------------------
YSpacing()359 inline double ImageAttributes::YSpacing() const
360 {
361 return _dy;
362 }
363
364 // -----------------------------------------------------------------------------
ZSpacing()365 inline double ImageAttributes::ZSpacing() const
366 {
367 return _dz;
368 }
369
370 // -----------------------------------------------------------------------------
TSpacing()371 inline double ImageAttributes::TSpacing() const
372 {
373 return _dt;
374 }
375
376 // -----------------------------------------------------------------------------
XSize()377 inline double ImageAttributes::XSize() const
378 {
379 return _dx;
380 }
381
382 // -----------------------------------------------------------------------------
YSize()383 inline double ImageAttributes::YSize() const
384 {
385 return _dy;
386 }
387
388 // -----------------------------------------------------------------------------
ZSize()389 inline double ImageAttributes::ZSize() const
390 {
391 return _dz;
392 }
393
394 // -----------------------------------------------------------------------------
TSize()395 inline double ImageAttributes::TSize() const
396 {
397 return _dt;
398 }
399
400 // -----------------------------------------------------------------------------
401 inline ImageAttributes::operator bool() const
402 {
403 // Note: _dz may be zero for 2D images, _dt may even be negative!
404 return _x > 0 && _y > 0 && _z > 0 && _t > 0 && _dx > .0 && _dy > .0 && _dz >= .0;
405 }
406
407 // -----------------------------------------------------------------------------
408 inline bool ImageAttributes::operator==(const ImageAttributes &attr) const
409 {
410 return EqualInSpace(attr) && EqualInTime(attr);
411 }
412
413 // -----------------------------------------------------------------------------
414 inline bool ImageAttributes::operator!=(const ImageAttributes &attr) const
415 {
416 return !(*this == attr);
417 }
418
419 // -----------------------------------------------------------------------------
LatticeToIndex(int i,int j,int k,int l)420 inline int ImageAttributes::LatticeToIndex(int i, int j, int k, int l) const
421 {
422 return i + _x * (j + _y * (k + _z * l));
423 }
424
425 // -----------------------------------------------------------------------------
IndexToLattice(int index,int * i,int * j,int * k,int * l)426 inline void ImageAttributes::IndexToLattice(int index, int *i, int *j, int *k, int *l) const
427 {
428 int n = _x * _y * _z;
429 if (l) *l = index / n;
430 index = index % n;
431 n = _x * _y;
432 if (k) *k = index / n;
433 *j = index % n / _x;
434 *i = index % n % _x;
435 }
436
437 // -----------------------------------------------------------------------------
NumberOfLatticePoints()438 inline int ImageAttributes::NumberOfLatticePoints() const
439 {
440 return _x * _y * _z * _t;
441 }
442
443 // -----------------------------------------------------------------------------
NumberOfSpatialPoints()444 inline int ImageAttributes::NumberOfSpatialPoints() const
445 {
446 return _x * _y * _z;
447 }
448
449 // -----------------------------------------------------------------------------
NumberOfPoints()450 inline int ImageAttributes::NumberOfPoints() const
451 {
452 return _dt ? NumberOfLatticePoints() : NumberOfSpatialPoints();
453 }
454
455 // -----------------------------------------------------------------------------
IndexToLattice(int index,int & i,int & j)456 inline void ImageAttributes::IndexToLattice(int index, int &i, int &j) const
457 {
458 IndexToLattice(index, &i, &j);
459 }
460
461 // -----------------------------------------------------------------------------
IndexToLattice(int index,int & i,int & j,int & k)462 inline void ImageAttributes::IndexToLattice(int index, int &i, int &j, int &k) const
463 {
464 IndexToLattice(index, &i, &j, &k);
465 }
466
467 // -----------------------------------------------------------------------------
IndexToLattice(int index,int & i,int & j,int & k,int & l)468 inline void ImageAttributes::IndexToLattice(int index, int &i, int &j, int &k, int &l) const
469 {
470 IndexToLattice(index, &i, &j, &k, &l);
471 }
472
473 // -----------------------------------------------------------------------------
IndexToWorld(int idx,double & x,double & y)474 inline void ImageAttributes::IndexToWorld(int idx, double &x, double &y) const
475 {
476 int i, j, k;
477 IndexToLattice(idx, i, j, k);
478 x = i, y = j;
479 double z = k;
480 LatticeToWorld(x, y, z);
481 }
482
483 // -----------------------------------------------------------------------------
IndexToWorld(int idx,double & x,double & y,double & z)484 inline void ImageAttributes::IndexToWorld(int idx, double &x, double &y, double &z) const
485 {
486 int i, j, k;
487 IndexToLattice(idx, i, j, k);
488 x = i, y = j, z = k;
489 LatticeToWorld(x, y, z);
490 }
491
492 // -----------------------------------------------------------------------------
IndexToWorld(int idx,Point & p)493 inline void ImageAttributes::IndexToWorld(int idx, Point &p) const
494 {
495 IndexToWorld(idx, p._x, p._y, p._z);
496 }
497
498 // -----------------------------------------------------------------------------
IndexToWorld(int idx)499 inline Point ImageAttributes::IndexToWorld(int idx) const
500 {
501 Point p;
502 IndexToWorld(idx, p);
503 return p;
504 }
505
506 // -----------------------------------------------------------------------------
LatticeToWorld(double & x,double & y,double & z)507 inline void ImageAttributes::LatticeToWorld(double &x, double &y, double &z) const
508 {
509 Transform(_i2w ? *_i2w : GetImageToWorldMatrix(), x, y, z);
510 }
511
512 // -----------------------------------------------------------------------------
LatticeToWorld(Point & p)513 inline void ImageAttributes::LatticeToWorld(Point &p) const
514 {
515 LatticeToWorld(p._x, p._y, p._z);
516 }
517
518 // -----------------------------------------------------------------------------
LatticeToTime(double t)519 inline double ImageAttributes::LatticeToTime(double t) const
520 {
521 return _torigin + t * _dt;
522 }
523
524 // -----------------------------------------------------------------------------
WorldToLattice(double & x,double & y,double & z)525 inline void ImageAttributes::WorldToLattice(double &x, double &y, double &z) const
526 {
527 Transform(_w2i ? *_w2i : GetWorldToImageMatrix(), x, y, z);
528 }
529
530 // -----------------------------------------------------------------------------
WorldToLattice(Point & p)531 inline void ImageAttributes::WorldToLattice(Point &p) const
532 {
533 WorldToLattice(p._x, p._y, p._z);
534 }
535
536 // -----------------------------------------------------------------------------
TimeToLattice(double t)537 inline double ImageAttributes::TimeToLattice(double t) const
538 {
539 return (_dt ? ((t - _torigin) / _dt) : .0);
540 }
541
542 // -----------------------------------------------------------------------------
GetLatticeToWorldOrientation()543 inline Matrix ImageAttributes::GetLatticeToWorldOrientation() const
544 {
545 Matrix R(3, 3);
546 R(0, 0) = _xaxis[0];
547 R(1, 0) = _xaxis[1];
548 R(2, 0) = _xaxis[2];
549 R(0, 1) = _yaxis[0];
550 R(1, 1) = _yaxis[1];
551 R(2, 1) = _yaxis[2];
552 R(0, 2) = _zaxis[0];
553 R(1, 2) = _zaxis[1];
554 R(2, 2) = _zaxis[2];
555 return R;
556 }
557
558 // -----------------------------------------------------------------------------
GetWorldToLatticeOrientation()559 inline Matrix ImageAttributes::GetWorldToLatticeOrientation() const
560 {
561 Matrix R(3, 3);
562 R(0, 0) = _xaxis[0];
563 R(0, 1) = _xaxis[1];
564 R(0, 2) = _xaxis[2];
565 R(1, 0) = _yaxis[0];
566 R(1, 1) = _yaxis[1];
567 R(1, 2) = _yaxis[2];
568 R(2, 0) = _zaxis[0];
569 R(2, 1) = _zaxis[1];
570 R(2, 2) = _zaxis[2];
571 return R;
572 }
573
574 // -----------------------------------------------------------------------------
IsInside(int idx)575 inline bool ImageAttributes::IsInside(int idx) const
576 {
577 return (0 <= idx && idx < _x * _y * _z * _t);
578 }
579
580 // -----------------------------------------------------------------------------
IsInside(int i,int j)581 inline bool ImageAttributes::IsInside(int i, int j) const
582 {
583 return (0 <= i && i < _x) && (0 <= j && j < _y);
584 }
585
586 // -----------------------------------------------------------------------------
IsInside(int i,int j,int k)587 inline bool ImageAttributes::IsInside(int i, int j, int k) const
588 {
589 return IsInside(i, j) && (0 <= k && k < _z);
590 }
591
592 // -----------------------------------------------------------------------------
IsInside(int i,int j,int k,int l)593 inline bool ImageAttributes::IsInside(int i, int j, int k, int l) const
594 {
595 return IsInside(i, j, k) && (0 <= l && l < _t);
596 }
597
598 // -----------------------------------------------------------------------------
IsOutside(int idx)599 inline bool ImageAttributes::IsOutside(int idx) const
600 {
601 return !IsInside(idx);
602 }
603
604 // -----------------------------------------------------------------------------
IsOutside(int i,int j)605 inline bool ImageAttributes::IsOutside(int i, int j) const
606 {
607 return !IsInside(i, j);
608 }
609
610 // -----------------------------------------------------------------------------
IsOutside(int i,int j,int k)611 inline bool ImageAttributes::IsOutside(int i, int j, int k) const
612 {
613 return !IsInside(i, j, k);
614 }
615
616 // -----------------------------------------------------------------------------
IsOutside(int i,int j,int k,int l)617 inline bool ImageAttributes::IsOutside(int i, int j, int k, int l) const
618 {
619 return !IsInside(i, j, k, l);
620 }
621
622 // -----------------------------------------------------------------------------
IsBoundary(int i,int j)623 inline bool ImageAttributes::IsBoundary(int i, int j) const
624 {
625 return (i == 0 || i == _x - 1) || (j == 0 || j == _y - 1);
626 }
627
628 // -----------------------------------------------------------------------------
IsBoundary(int i,int j,int k)629 inline bool ImageAttributes::IsBoundary(int i, int j, int k) const
630 {
631 return IsBoundary(i, j) || (k == 0 || k == _z - 1);
632 }
633
634 // -----------------------------------------------------------------------------
IsBoundary(int i,int j,int k,int l)635 inline bool ImageAttributes::IsBoundary(int i, int j, int k, int l) const
636 {
637 return IsBoundary(i, j, k) || (l == 0 || l == _t - 1);
638 }
639
640 // -----------------------------------------------------------------------------
IsBoundary(int idx)641 inline bool ImageAttributes::IsBoundary(int idx) const
642 {
643 if (!IsInside(idx)) return false;
644 int i, j, k, l;
645 IndexToLattice(idx, i, j, k, l);
646 if (_t == 1) {
647 if (_z == 1) return IsBoundary(i, j);
648 else return IsBoundary(i, j, k);
649 }
650 return IsBoundary(i, j, k, l);
651 }
652
653 ////////////////////////////////////////////////////////////////////////////////
654 // Image domain helpers
655 ////////////////////////////////////////////////////////////////////////////////
656
657 /// Ensure that image domain has orthogonal basis vectors, i.e., no additional
658 /// affine transformation which contains any shearing
659 ///
660 /// \returns Image grid which fully contains the input image domain but without
661 /// additional affine transformation (_smat is identity matrix).
662 ///
663 /// \remarks The returned image domain need not be an axis-aligned bounding box!
664 /// When the Geometric Tools Engine (GTEngine) library is available,
665 /// the minimum-volume bounding box is returned.
666 ImageAttributes OrthogonalFieldOfView(const ImageAttributes &);
667
668 /// This method implements a method to find a common image grid which fully
669 /// contains all given image grids in world space
670 ///
671 /// The voxel size of the resulting grid corresponds to the average voxel size
672 /// of the input images. The orientation and origin are chosen such that the
673 /// resulting image domain overlaps all input images in world space with a near
674 /// to minimal image volume. The current implementation only uses an heuristic
675 /// approach to find such minimal oriented bounding box of the input domains.
676 /// When the Geometric Tools Engine (GTEngine) library is available, the
677 /// minimum-volume bounding box is returned.
678 ///
679 /// Additional information regarding algorithms to find the optimal
680 /// minimum-volume oriented bounding box (OBB) can be found at:
681 /// - http://stackoverflow.com/questions/7282805/where-can-i-find-a-c-c-implementation-of-the-minimum-bound-box-algorithm
682 /// - http://www.geometrictools.com/LibMathematics/Containment/Containment.html
683 /// - http://link.springer.com/article/10.1007%2FBF00991005?LI=true
684 ///
685 /// \note The final overall image grid computed by this function must be
686 /// independent of the order in which the input attributes are given
687 /// in the input list. Otherwise an inverse consistent registration
688 /// might still depend on the order of the input images.
689 ImageAttributes OverallFieldOfView(const Array<ImageAttributes> &);
690
691
692 } // namespace mirtk
693
694 #endif // MIRTK_ImageAttributes_H
695