ConstImageIterator.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_ConstImageIterator_H
21 #define MIRTK_ConstImageIterator_H
22 
23 #include "mirtk/Voxel.h"
24 #include "mirtk/Vector4D.h"
25 #include "mirtk/ImageAttributes.h"
26 #include "mirtk/BaseImage.h"
27 
28 
29 namespace mirtk {
30 
31 
32 /**
33  * Base class of const image iterator
34  */
36 {
37  // ---------------------------------------------------------------------------
38  // Initialization
39 protected:
40 
41  /// Calculate pointer increments
42  void CalculateStride();
43 
44  /// Initialize iterator, called by first GoTo command
45  void Initialize();
46 
47 public:
48 
49  // ---------------------------------------------------------------------------
50  // Construction/Destruction
51 
52  /// Constructor
53  ConstImageIterator(const ImageAttributes &, int);
54 
55  /// Constructor
56  ConstImageIterator(const ImageAttributes &, const void * = NULL, int = MIRTK_VOXEL_UNKNOWN);
57 
58  /// Constructor
60 
61  /// Constructor
63 
64  /// Copy constructor
66 
67  /// Assignment operator
69 
70  /// Destructor
71  virtual ~ConstImageIterator();
72 
73  /// Get stride between columns in number of voxels
74  int ColumnStride() const;
75 
76  /// Get stride between rows/lines in number of voxels
77  int LineStride() const;
78 
79  /// Get stride between slices in number of voxels
80  int SliceStride() const;
81 
82  /// Get stride between frames in number of voxels
83  int FrameStride() const;
84 
85  // ---------------------------------------------------------------------------
86  // Image attributes
87 
88  /// Set data type - defines number of bytes per voxel
89  void SetDataType(int);
90 
91  /// Set raw data pointer to start of entire image
92  void SetData(const void *, int = MIRTK_VOXEL_UNKNOWN);
93 
94  /// Whether the image is a 3D+t image sequence
95  /// (i.e., number of voxels in t dimension is greater 1 and dt is not 0)
96  bool IsImageSequence() const;
97 
98  /// Whether the image is a scalar image
99  /// (i.e., number of voxels in t dimension is 1 or dt equal 0)
100  bool IsScalarImage() const;
101 
102  /// Number of voxels in the entire image
103  int NumberOfImageVoxels() const;
104 
105  /// Get number of image channels
106  /// (i.e., number of voxels in t dimension if dt <= 0 or 1 otherwise)
107  int NumberOfImageChannels() const;
108 
109  /// Get number of vector components
110  /// (i.e., number of voxels in t dimension if dt <= 0 or 1 otherwise)
111  int NumberOfVectorComponents() const;
112 
113  /// Get number of iterated frames
114  /// (i.e., number of voxels in t dimension if dt > 0 or 1 otherwise)
115  int NumberOfSequenceFrames() const;
116 
117  // ---------------------------------------------------------------------------
118  // Region attributes
119 
120  /// Whether the image region is a 3D+t image sequence
121  /// (i.e., number of voxels in t dimension > 1 and dt > 0)
122  bool IsSequence() const;
123 
124  /// Whether the image region is scalar
125  /// (i.e., number of voxels in t dimension is 1)
126  bool IsScalar() const;
127 
128  /// Number of voxels in image region
129  int NumberOfVoxels() const;
130 
131  /// Get number of channels in image region
132  int NumberOfChannels() const;
133 
134  /// Get number of vector components considered
135  int NumberOfComponents() const;
136 
137  /// Get number of frames in image region
138  int NumberOfFrames() const;
139 
140  // ---------------------------------------------------------------------------
141  // Region/Neighborhood
142 
143  /// Set 2D image region (start and size)
144  void SetRegion(int, int, int, int);
145 
146  /// Set 2D image region (start and end)
147  void SetRegion(const blocked_range2d<int> &);
148 
149  /// Set 3D image region (start and size)
150  void SetRegion(int, int, int, int, int, int);
151 
152  /// Set 3D image region (start and end)
153  void SetRegion(const blocked_range3d<int> &);
154 
155  /// Set 2D neighborhood (center and radius)
156  void SetNeighborhood(int, int, int, int);
157 
158  /// Set 3D neighborhood (center and radius)
159  void SetNeighborhood(int, int, int, int, int, int);
160 
161  /// Set temporal region (start and size)
162  void SetFrame(int, int = 1);
163 
164  /// Set temporal region (start and end)
165  void SetFrame(const blocked_range<int> &);
166 
167  /// Set temporal region (start and size)
168  void SetChannel(int, int = 1);
169 
170  /// Set temporal region (start and end)
171  void SetChannel(const blocked_range<int> &);
172 
173  /// Set temporal region (start and size)
174  void SetComponent(int, int = 1);
175 
176  /// Set temporal region (start and end)
177  void SetComponent(const blocked_range<int> &);
178 
179  /// Set 4D image region (start and size)
180  void SetRegion(int, int, int, int, int, int, int, int);
181 
182  /// Set 4D neighborhood (center and radius)
183  void SetNeighborhood(int, int, int, int, int, int, int, int);
184 
185  // ---------------------------------------------------------------------------
186  // Position
187 
188  /// Convert iterator position to voxel coordinates
189  void IndexToVoxel(int, int &, int &) const;
190 
191  /// Convert iterator position to voxel coordinates
192  void IndexToVoxel(int, int &, int &, int &) const;
193 
194  /// Convert iterator position to voxel coordinates
195  void IndexToVoxel(int, int &, int &, int &, int &) const;
196 
197  /// Convert iterator position to voxel coordinates
198  void IndexToVoxel(int, Vector4D<int> &) const;
199 
200  /// Convert voxel coordinates to index
201  int VoxelToIndex(int, int, int = 0, int = 0) const;
202 
203  /// Convert voxel coordinates to index
204  int VoxelToIndex(const Vector4D<int> &) const;
205 
206  /// Convert iterator position to voxel coordinates
207  void PosToVoxel(int, int &, int &) const;
208 
209  /// Convert iterator position to voxel coordinates
210  void PosToVoxel(int, int &, int &, int &) const;
211 
212  /// Convert iterator position to voxel coordinates
213  void PosToVoxel(int, int &, int &, int &, int &) const;
214 
215  /// Convert iterator position to voxel coordinates
216  void PosToVoxel(int, Vector4D<int> &) const;
217 
218  /// Convert iterator position to voxel index
219  int PosToIndex(int) const;
220 
221  /// Convert voxel index to iterator position
222  int IndexToPos(int) const;
223 
224  /// Convert voxel cooridnates to iterator position
225  int VoxelToPos(int, int, int = 0, int = 0) const;
226 
227  /// Convert voxel cooridnates to iterator position
228  int VoxelToPos(const Vector4D<int> &) const;
229 
230  /// Current iterator position within image region
231  int Pos() const;
232 
233  /// Index of voxel at current iterator position
234  int Index() const;
235 
236  /// Coordinates of voxel at current iterator position
237  void Voxel(int &, int &) const;
238 
239  /// Coordinates of voxel at current iterator position
240  void Voxel(int &, int &, int &) const;
241 
242  /// Coordinates of voxel at current iterator position
243  void Voxel(int &, int &, int &, int &) const;
244 
245  // ---------------------------------------------------------------------------
246  // Iteration
247 
248  /// Go to voxel with specified coordinates relative to entire image
249  void GoToVoxel(int, int, int = -1, int = -1);
250 
251  /// Go to voxel with specified coordinates relative to entire image
252  void GoToVoxel(const Vector4D<int> &);
253 
254  /// Go to voxel with specified index relative to entire image
255  void GoToIndex(int);
256 
257  /// Go to begin of region
258  void GoToBegin();
259 
260  /// Go to center of region
261  void GoToCenter();
262 
263  /// Go to end of region
264  void GoToEnd();
265 
266  /// Go to specified position within image region
267  void GoToPos(int);
268 
269  /// Whether iterator is valid and not yet at end of region
270  operator bool() const;
271 
272  /// Whether iterator reached the start of the region and is invalid now
273  bool IsAtBegin() const;
274 
275  /// Whether iterator reached the end of the region and is invalid now
276  bool IsAtEnd() const;
277 
278  /// Pre-decrement operator
279  void operator --();
280 
281  /// Pre-increment operator
282  void operator ++();
283 
284  /// Get pointer to current iterator position
285  ///
286  /// The VoxelType template argument must match the actual scalar type of the image.
287  template <class VoxelType>
288  const VoxelType *Current() const;
289 
290  /// Get pointer to current iterator position
291  ///
292  /// The VoxelType template argument must match the actual scalar type of the image.
293  ///
294  /// \param[in] t Channel/Component/Frame stride relative to current iterator position.
295  /// For example, set iterator region to only the first channel/frame and
296  /// then access other channels/vector components/frames using this method.
297  template <class VoxelType>
298  const VoxelType *Current(int) const;
299 
300  /// Get pointer to current iterator position and post-increment iterator
301  ///
302  /// The VoxelType template argument must match the actual scalar type of the image.
303  template <class VoxelType>
304  const VoxelType *Next();
305 
306  /// Get pointer to current iterator position and post-increment iterator
307  ///
308  /// The VoxelType template argument must match the actual scalar type of the image.
309  ///
310  /// \param[in] t Channel/Component/Frame stride relative to current iterator position.
311  /// For example, set iterator region to only the first channel/frame and
312  /// then access other channels/vector components/frames using this method.
313  template <class VoxelType>
314  const VoxelType *Next(int);
315 
316  /// Get reference to voxel value at current iterator position
317  ///
318  /// The VoxelType template argument must match the actual scalar type of the image.
319  template <class VoxelType>
320  const VoxelType &Value() const;
321 
322  /// Get reference to voxel value at current iterator position
323  ///
324  /// The VoxelType template argument must match the actual scalar type of the image.
325  ///
326  /// \param[in] t Channel/Component/Frame stride relative to current iterator position.
327  /// For example, set iterator region to only the first channel/frame and
328  /// then access other channels/vector components/frames using this method.
329  template <class VoxelType>
330  const VoxelType &Value(int t) const;
331 
332  /// Get current voxel value casted to double
333  virtual double ValueAsDouble() const;
334 
335  /// Get current voxel value casted to double
336  ///
337  /// \param[in] t Channel/Component/Frame stride relative to current iterator position.
338  /// For example, set iterator region to only the first channel/frame and
339  /// then access other channels/vector components/frames using this method.
340  virtual double ValueAsDouble(int) const;
341 
342  /// Move given raw image data pointer to the current iterator position assuming
343  /// it is at the voxel position at which the iterator has been before
344  ///
345  /// This method is useful when iterating over multiple images with common
346  /// image attributes simultaneously. An iterator instance associated with one
347  /// of the images or initialized with the image attributes corresponding to all
348  /// images is then sufficient to reduce the associated overhead. Raw pointers
349  /// to the voxel data of the other images can then be moved to the next position
350  /// using this method after the iterator itself has been incremented or decremented.
351  ///
352  /// Note that after a GoTo method of the iterator has been called, this method
353  /// moves the raw image data pointer returned by BaseImage::GetScalarPointer
354  /// to the same position as the iterator was moved to by the GoTo method.
355  ///
356  /// \code
357  /// ConstImageIterator it(gradient.GetImageAttributes(), gradient.GetScalarType());
358  /// double *gx = gradient.GetPointerToVoxels(0, 0, 0, 0);
359  /// double *gy = gradient.GetPointerToVoxels(0, 0, 0, 1);
360  /// double *gz = gradient.GetPointerToVoxels(0, 0, 0, 2);
361  ///
362  /// it.GoToBegin();
363  /// while (!it.IsAtEnd()) {
364  /// // do something with the data
365  /// ++it; // must be done before moving the other data pointers
366  /// it.Move(gx), it.Move(gy), it.Move(gz);
367  /// }
368  ///
369  /// it.GoToEnd();
370  /// while (!it.IsAtBegin()) {
371  /// // do something with the data
372  /// --it; // must be done before moving the other data pointers
373  /// it.Move(gx), it.Move(gy), it.Move(gz);
374  /// }
375  /// \endcode
376  template <class VoxelType>
377  void Move(const VoxelType *&) const;
378 
379  /// Move given raw image data pointer to the current iterator position assuming
380  /// it is at the voxel position at which the iterator has been before
381  template <class VoxelType>
382  void Move(VoxelType *&) const;
383 
384  // ---------------------------------------------------------------------------
385  // Members
386 protected:
387 
388  const char *_Data; ///< Pointer to begin of entire image
389  Vector4D<int> _DataSize; ///< Size of the entire image
390  bool _IsImageSequence; ///< Whether the image is a sequence
391 
392  Vector4D<int> _Index; ///< Start index of the image region
393  Vector4D<int> _Begin; ///< First index of the image region
394  Vector4D<int> _End; ///< Last index of the image region
395  Vector4D<int> _Size; ///< Size of image region
396  int _XYZ; ///< Number of voxels per frame of the image
397  int _ColumnStride; ///< Increment in number of bytes (size of voxel type)
398  int _LineStride; ///< Increment at end of line in number of bytes
399  int _SliceStride; ///< Increment at end of slice in number of bytes
400  int _FrameStride; ///< Increment at end of frame in number of bytes
401  int _Inc; ///< Previous pointer increment in number of bytes
402  const char *_Next; ///< Pointer to next image voxel
403 
404 };
405 
406 //////////////////////////////////////////////////////////////////////////////
407 // Inline definitions
408 //////////////////////////////////////////////////////////////////////////////
409 
410 // ===========================================================================
411 // Construction/Destruction
412 // ===========================================================================
413 
414 // ---------------------------------------------------------------------------
416 :
417  _Data (NULL),
418  _DataSize (attr._x, attr._y, attr._z, attr._t),
419  _IsImageSequence (attr._t > 1 && attr._dt > .0),
420  _Index (0, 0, 0, 0),
421  _Begin (0, 0, 0, 0),
422  _End (attr._x-1, attr._y-1, attr._z-1, attr._t-1),
423  _Size (attr._x, attr._y, attr._z, attr._t),
424  _XYZ (attr._x * attr._y * attr._z),
425  _ColumnStride (DataTypeSize(type)),
426  _LineStride (0),
427  _SliceStride (0),
428  _FrameStride (0),
429  _Inc (0),
430  _Next (NULL)
431 {
432 }
433 
434 // ---------------------------------------------------------------------------
435 inline ConstImageIterator::ConstImageIterator(const ImageAttributes &attr, const void *data, int type)
436 :
437  _Data (reinterpret_cast<const char *>(data)),
438  _DataSize (attr._x, attr._y, attr._z, attr._t),
439  _IsImageSequence (attr._t > 1 && attr._dt > .0),
440  _Index (0, 0, 0, 0),
441  _Begin (0, 0, 0, 0),
442  _End (attr._x-1, attr._y-1, attr._z-1, attr._t-1),
443  _Size (attr._x, attr._y, attr._z, attr._t),
444  _XYZ (attr._x * attr._y * attr._z),
445  _ColumnStride (DataTypeSize(type)),
446  _LineStride (0),
447  _SliceStride (0),
448  _FrameStride (0),
449  _Inc (0),
450  _Next (NULL)
451 {
452 }
453 
454 // ---------------------------------------------------------------------------
456 :
457  _Data (reinterpret_cast<const char *>(image.GetScalarPointer())),
458  _DataSize (image.GetX(), image.GetY(), image.GetZ(), image.GetT()),
459  _IsImageSequence (image.GetT() > 1 && image.GetTSize() > .0),
460  _Index (0, 0, 0, 0),
461  _Begin (0, 0, 0, 0),
462  _End (image.GetX()-1, image.GetY()-1, image.GetZ()-1, image.GetT()-1),
463  _Size (image.GetX(), image.GetY(), image.GetZ(), image.GetT()),
464  _XYZ (image.GetX() * image.GetY() * image.GetZ()),
465  _ColumnStride (image.GetScalarTypeSize()),
466  _LineStride (0),
467  _SliceStride (0),
468  _FrameStride (0),
469  _Inc (0),
470  _Next (NULL)
471 {
472 }
473 
474 // ---------------------------------------------------------------------------
476 :
477  _Data (reinterpret_cast<const char *>(image->GetScalarPointer())),
478  _DataSize (image->GetX(), image->GetY(), image->GetZ(), image->GetT()),
479  _IsImageSequence (image->GetT() > 1 && image->GetTSize() > .0),
480  _Index (0, 0, 0, 0),
481  _Begin (0, 0, 0, 0),
482  _End (image->GetX()-1, image->GetY()-1, image->GetZ()-1, image->GetT()-1),
483  _Size (image->GetX(), image->GetY(), image->GetZ(), image->GetT()),
484  _XYZ (image->GetX() * image->GetY() * image->GetZ()),
485  _ColumnStride (image->GetScalarTypeSize()),
486  _LineStride (0),
487  _SliceStride (0),
488  _FrameStride (0),
489  _Inc (0),
490  _Next (NULL)
491 {
492 }
493 
494 // ---------------------------------------------------------------------------
496 :
497  _Data (other._Data),
498  _DataSize (other._DataSize),
500  _Index (other._Index),
501  _Begin (other._Begin),
502  _End (other._End),
503  _Size (other._Size),
504  _XYZ (other._XYZ),
506  _LineStride (other._LineStride),
507  _SliceStride (other._SliceStride),
508  _FrameStride (other._FrameStride),
509  _Inc (other._Inc),
510  _Next (other._Next)
511 {
512 }
513 
514 // ---------------------------------------------------------------------------
516 {
517  _Data = rhs._Data;
518  _DataSize = rhs._DataSize;
520  _Index = rhs._Index;
521  _Begin = rhs._Begin;
522  _End = rhs._End;
523  _Size = rhs._Size;
524  _XYZ = rhs._XYZ;
526  _LineStride = rhs._LineStride;
529  _Inc = rhs._Inc;
530  _Next = rhs._Next;
531  return *this;
532 }
533 
534 // ---------------------------------------------------------------------------
536 {
537 }
538 
539 // ---------------------------------------------------------------------------
541 {
542  // Pointer increments at end of line/slice/frame in number of voxels
543  _LineStride = _DataSize._x - _Size._x + 1;
544  _SliceStride = (_DataSize._y - _Size._y + 1) * _DataSize._x - _Size._x + 1;
545  _FrameStride = ((_DataSize._z - _Size._z + 1) * _DataSize._y - _Size._y + 1) * _DataSize._x - _Size._x + 1;
546  // Multiply by number of bytes per voxel
547  if (_ColumnStride == 0) _ColumnStride = 1;
551 }
552 
553 // ---------------------------------------------------------------------------
555 {
556  return 1;
557 }
558 
559 // ---------------------------------------------------------------------------
561 {
562  return _LineStride / _ColumnStride;
563 }
564 
565 // ---------------------------------------------------------------------------
567 {
568  return _SliceStride / _ColumnStride;
569 }
570 
571 // ---------------------------------------------------------------------------
573 {
574  return _FrameStride / _ColumnStride;
575 }
576 
577 // ===========================================================================
578 // Image attributes
579 // ===========================================================================
580 
581 // ---------------------------------------------------------------------------
582 inline void ConstImageIterator::SetDataType(int type)
583 {
584  const int size = DataTypeSize(type);
585  if (size == 0) {
586  cerr << "ConstImageIterator::SetDataType: Unknown data type: " << type << endl;
587  exit(1);
588  }
589  if (_ColumnStride != size) {
590  _ColumnStride = size;
591  _LineStride = 0;
592  }
593 }
594 
595 // ---------------------------------------------------------------------------
596 inline void ConstImageIterator::SetData(const void *data, int type)
597 {
598  if (type != MIRTK_VOXEL_UNKNOWN) {
599  SetDataType(type);
600  }
601  _Data = reinterpret_cast<const char *>(data);
602  _Next = NULL;
603 }
604 
605 // ---------------------------------------------------------------------------
607 {
608  return _IsImageSequence;
609 }
610 
611 // ---------------------------------------------------------------------------
613 {
614  return _DataSize._t == 1 || _IsImageSequence;
615 }
616 
617 // ---------------------------------------------------------------------------
619 {
621 }
622 
623 // ---------------------------------------------------------------------------
625 {
626  return _IsImageSequence ? 1 : _DataSize._t;
627 }
628 
629 // ---------------------------------------------------------------------------
631 {
632  return NumberOfImageChannels();
633 }
634 
635 // ---------------------------------------------------------------------------
637 {
638  return _IsImageSequence ? _DataSize._t : 1;
639 }
640 
641 // ===========================================================================
642 // Region attributes
643 // ===========================================================================
644 
645 // ---------------------------------------------------------------------------
647 {
648  return _Size._t > 1 && _IsImageSequence;
649 }
650 
651 // ---------------------------------------------------------------------------
652 inline bool ConstImageIterator::IsScalar() const
653 {
654  return _Size._t == 1;
655 }
656 
657 // ---------------------------------------------------------------------------
659 {
660  return _Size._x * _Size._y * _Size._z * _Size._t;
661 }
662 
663 // ---------------------------------------------------------------------------
665 {
666  return IsSequence() ? 1 : _Size._t;
667 }
668 
669 // ---------------------------------------------------------------------------
671 {
672  return NumberOfChannels();
673 }
674 
675 // ---------------------------------------------------------------------------
677 {
678  return IsSequence() ? _Size._t : 1;
679 }
680 
681 // ===========================================================================
682 // Region
683 // ===========================================================================
684 
685 // ---------------------------------------------------------------------------
686 inline void ConstImageIterator::SetRegion(int i, int j, int k, int ni, int nj, int nk)
687 {
688  // Allow negative size value which means all voxels up to the image boundary
689  if (ni < 0) ni = _DataSize._x - i;
690  if (nj < 0) nj = _DataSize._y - j;
691  if (nk < 0) nk = _DataSize._z - k;
692  // Note: DO NOT change frame/channel selection here!
693  // Done by SetFrame/SetChannel/SetComponent.
694  _Begin._x = i;
695  _Begin._y = j;
696  _Begin._z = k;
697  _End ._x = i + ni - 1;
698  _End ._y = j + nj - 1;
699  _End ._z = k + nk - 1;
700  _Size ._x = ni;
701  _Size ._y = nj;
702  _Size ._z = nk;
703  // Check image region
704  if (_Begin._x < 0 || _Begin._x >= _DataSize._x || _End._x >= _DataSize._x ||
705  _Begin._y < 0 || _Begin._y >= _DataSize._y || _End._y >= _DataSize._y ||
706  _Begin._z < 0 || _Begin._z >= _DataSize._z || _End._z >= _DataSize._z ||
707  _Begin._t < 0 || _Begin._t >= _DataSize._t || _End._t >= _DataSize._t) {
708  cerr << "ConstImageIterator::SetRegion: Region at least partially outside of image domain" << endl;
709  exit(1);
710  }
711  // Invalidate current strides
712  _LineStride = 0;
713 }
714 
715 // ---------------------------------------------------------------------------
716 inline void ConstImageIterator::SetRegion(int i, int j, int ni, int nj)
717 {
718  SetRegion(i, j, 0, ni, nj, 1);
719 }
720 
721 // ---------------------------------------------------------------------------
723 {
724  SetRegion(r.cols().begin(),
725  r.rows().begin(),
726  r.cols().end() - r.cols().begin(),
727  r.rows().end() - r.rows().begin());
728 }
729 
730 // ---------------------------------------------------------------------------
732 {
733  SetRegion(r.cols ().begin(),
734  r.rows ().begin(),
735  r.pages().begin(),
736  r.cols ().end() - r.cols ().begin(),
737  r.rows ().end() - r.rows ().begin(),
738  r.pages().end() - r.pages().begin());
739 }
740 
741 // ---------------------------------------------------------------------------
742 inline void ConstImageIterator::SetChannel(int c, int nc)
743 {
744  if (!_IsImageSequence) {
745  if (c < 0 || c >= _DataSize._t) {
746  cerr << "ConstImageIterator::SetChannel/Component: Channel index out of bounds (c=" << c << ")" << endl;
747  exit(1);
748  }
749  // Allow negative value to select all channels starting at c
750  if (nc < 1) nc = _DataSize._t - c;
751  if ((c + nc) > _DataSize._t) {
752  cerr << "ConstImageIterator::SetChannel/Component: Channel range out of bounds (c=" << c << ", nc=" << nc << ")" << endl;
753  exit(1);
754  }
755  // Set range of channels
756  _Begin._t = c;
757  _End ._t = c + nc - 1;
758  _Size ._t = nc;
759  // Invalidate current strides
760  _LineStride = 0;
761  } else if (c != 0 || nc != 1) {
762  cerr << "ConstImageIterator::SetChannel/Component: Channel index/range out of bounds (c=" << c << ", nc=" << nc << ")" << endl;
763  exit(1);
764  }
765 }
766 
767 // ---------------------------------------------------------------------------
769 {
770  SetChannel(r.begin(), r.end() - r.begin());
771 }
772 
773 // ---------------------------------------------------------------------------
774 inline void ConstImageIterator::SetComponent(int c, int nc)
775 {
776  SetChannel(c, nc);
777 }
778 
779 // ---------------------------------------------------------------------------
781 {
782  SetFrame(r.begin(), r.end() - r.begin());
783 }
784 
785 // ---------------------------------------------------------------------------
786 inline void ConstImageIterator::SetFrame(int l, int nl)
787 {
788  if (_IsImageSequence) {
789  if (l < 0 || l >= _DataSize._t) {
790  cerr << "ConstImageIterator::SetFrame: Frame index out of bounds (l=" << l << ")" << endl;
791  exit(1);
792  }
793  // Allow negative value to select all frames starting at c
794  if (nl < 1) nl = _DataSize._t - l;
795  if ((l + nl) > _DataSize._t) {
796  cerr << "ConstImageIterator::SetFrame: Frame range out of bounds (l=" << l << ", nl=" << nl << ")" << endl;
797  exit(1);
798  }
799  // Set range of frames
800  _Begin._t = l;
801  _End ._t = l + nl - 1;
802  _Size ._t = nl;
803  // Invalidate current strides
804  _LineStride = 0;
805  } else if (l != 0 || nl != 1) {
806  cerr << "ConstImageIterator::SetFrame: Frame index/range out of bounds (l=" << l << ", nl=" << nl << ")" << endl;
807  exit(1);
808  }
809 }
810 
811 // ---------------------------------------------------------------------------
813 {
814  SetFrame(r.begin(), r.end() - r.begin());
815 }
816 
817 // ---------------------------------------------------------------------------
818 inline void ConstImageIterator::SetRegion(int i, int j, int k, int l, int ni, int nj, int nk, int nl)
819 {
820  SetRegion(i, j, k, ni, nj, nk);
821  if (IsSequence()) SetFrame (l, nl);
822  else SetChannel(l, nl);
823 }
824 
825 // ---------------------------------------------------------------------------
826 inline void ConstImageIterator::SetNeighborhood(int i, int j, int k, int ri, int rj, int rk)
827 {
828  if (ri < 0) ri = 0;
829  if (rj < 0) rj = 0;
830  if (rk < 0) rk = 0;
831  if (0 <= i && i < _DataSize._x && 0 <= j && j < _DataSize._y && 0 <= k && k < _DataSize._z) {
832  int i1 = i - ri;
833  int j1 = j - rj;
834  int k1 = k - rk;
835  int i2 = i + ri;
836  int j2 = j + rj;
837  int k2 = k + rk;
838 
839  if (i1 < 0) i1 = 0;
840  if (j1 < 0) j1 = 0;
841  if (k1 < 0) k1 = 0;
842  if (i2 >= _DataSize._x) i2 = _DataSize._x - 1;
843  if (j2 >= _DataSize._y) j2 = _DataSize._y - 1;
844  if (k2 >= _DataSize._z) k2 = _DataSize._z - 1;
845 
846  SetRegion(i1, j1, k1, i2-i1+1, j2-j1+1, k2-k1+1);
847  } else {
848  cerr << "ConstImageIterator::SetNeighborhood: Neighborhood out of bounds" << endl;
849  exit(1);
850  }
851 }
852 
853 // ---------------------------------------------------------------------------
854 inline void ConstImageIterator::SetNeighborhood(int i, int j, int ri, int rj)
855 {
856  SetNeighborhood(i, j, 0, ri, rj, 0);
857 }
858 
859 // ---------------------------------------------------------------------------
860 inline void ConstImageIterator::SetNeighborhood(int i, int j, int k, int l, int ri, int rj, int rk, int rl)
861 {
862  if (ri < 0) ri = 0;
863  if (rj < 0) rj = 0;
864  if (rk < 0) rk = 0;
865  if (rl < 0) rl = 0;
866  SetNeighborhood(i, j, k, ri, rj, rk);
867  if (_IsImageSequence) {
868  if (0 <= l && l < _DataSize._t) {
869  int l1 = l - rl;
870  int l2 = l + rl;
871  if (l1 < 0) l1 = 0;
872  if (l2 >= _DataSize._t) l2 = _DataSize._t - 1;
873  SetFrame(l1, l2-l1+1);
874  } else {
875  cerr << "ConstImageIterator::SetNeighborhood: Neighborhood out of bounds" << endl;
876  exit(1);
877  }
878  } else if (l != 0 || rl != 0) {
879  cerr << "ConstImageIterator::SetNeighborhood: 4D neighborhood only valid for image sequences (i.e., dt > 0)" << endl;
880  exit(1);
881  }
882 }
883 
884 // ===========================================================================
885 // Position
886 // ===========================================================================
887 
888 // ---------------------------------------------------------------------------
889 inline void ConstImageIterator::IndexToVoxel(int idx, int &i, int &j) const
890 {
891  const int n = _DataSize._x * _DataSize._y;
892  idx = idx % (n * _DataSize._z) % n;
893  j = idx / _DataSize._x;
894  i = idx % _DataSize._x;
895 }
896 
897 // ---------------------------------------------------------------------------
898 inline void ConstImageIterator::IndexToVoxel(int idx, int &i, int &j, int &k) const
899 {
900  int n;
902  idx = idx % n;
903  n = _DataSize._x * _DataSize._y;
904  k = idx / n;
905  j = idx % n / _DataSize._x;
906  i = idx % n % _DataSize._x;
907 }
908 
909 // ---------------------------------------------------------------------------
910 inline void ConstImageIterator::IndexToVoxel(int idx, int &i, int &j, int &k, int &l) const
911 {
912  int n;
914  l = idx / n;
915  idx = idx % n;
916  n = _DataSize._x * _DataSize._y;
917  k = idx / n;
918  j = idx % n / _DataSize._x;
919  i = idx % n % _DataSize._x;
920 }
921 
922 // ---------------------------------------------------------------------------
923 inline void ConstImageIterator::IndexToVoxel(int idx, Vector4D<int> &v) const
924 {
925  IndexToVoxel(v._x, v._y, v._z, v._t);
926 }
927 
928 // ---------------------------------------------------------------------------
929 inline int ConstImageIterator::VoxelToIndex(int i, int j, int k, int l) const
930 {
931  return i + _DataSize._x * (j + _DataSize._y * (k + _DataSize._z * l));
932 }
933 
934 // ---------------------------------------------------------------------------
936 {
937  return VoxelToIndex(v._x, v._y, v._z, v._t);
938 }
939 
940 // ---------------------------------------------------------------------------
941 inline void ConstImageIterator::PosToVoxel(int pos, int &i, int &j) const
942 {
943  const int n = _Size._x * _Size._y;
944  pos = pos % (n * _Size._z) % n;
945  j = pos / _Size._x;
946  i = pos % _Size._x;
947 }
948 
949 // ---------------------------------------------------------------------------
950 inline void ConstImageIterator::PosToVoxel(int pos, int &i, int &j, int &k) const
951 {
952  int n;
953  n = _Size._x * _Size._y * _Size._z;
954  pos = pos % n;
955  n = _Size._x * _Size._y;
956  k = pos / n;
957  j = pos % n / _Size._x;
958  i = pos % n % _Size._x;
959 }
960 
961 // ---------------------------------------------------------------------------
962 inline void ConstImageIterator::PosToVoxel(int pos, int &i, int &j, int &k, int &l) const
963 {
964  int n;
965  n = _Size._x * _Size._y * _Size._z;
966  l = pos / n;
967  pos = pos % n;
968  n = _Size._x * _Size._y;
969  k = pos / n;
970  j = pos % n / _Size._x;
971  i = pos % n % _Size._x;
972 }
973 
974 // ---------------------------------------------------------------------------
975 inline void ConstImageIterator::PosToVoxel(int pos, Vector4D<int> &v) const
976 {
977  return PosToVoxel(v._x, v._y, v._z, v._t);
978 }
979 
980 // ---------------------------------------------------------------------------
981 inline int ConstImageIterator::PosToIndex(int pos) const
982 {
983  int i, j, k, l;
984  PosToVoxel(pos, i, j, k, l);
985  return VoxelToIndex(i, j, k, l);
986 }
987 
988 // ---------------------------------------------------------------------------
989 inline int ConstImageIterator::VoxelToPos(int i, int j, int k, int l) const
990 {
991  return (i - _Begin._x) + _Size._x * ((j - _Begin._y) + _Size._y * ((k - _Begin._z) + _Size._z * (l - _Begin._t)));
992 }
993 
994 // ---------------------------------------------------------------------------
996 {
997  return VoxelToPos(v._x, v._y, v._z, v._t);
998 }
999 
1000 // ---------------------------------------------------------------------------
1001 inline int ConstImageIterator::IndexToPos(int idx) const
1002 {
1003  int i, j, k, l;
1004  IndexToVoxel(idx, i, j, k, l);
1005  return VoxelToPos(i, j, k, l);
1006 }
1007 
1008 // ---------------------------------------------------------------------------
1009 inline int ConstImageIterator::Pos() const
1010 {
1011  return VoxelToPos(_Index);
1012 }
1013 
1014 // ---------------------------------------------------------------------------
1015 inline int ConstImageIterator::Index() const
1016 {
1017  return static_cast<int>(_Next - reinterpret_cast<const char *>(_Data)) / _ColumnStride;
1018 }
1019 
1020 // ---------------------------------------------------------------------------
1021 inline void ConstImageIterator::Voxel(int &i, int &j) const
1022 {
1023  i = _Index._x;
1024  j = _Index._y;
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 inline void ConstImageIterator::Voxel(int &i, int &j, int &k) const
1029 {
1030  i = _Index._x;
1031  j = _Index._y;
1032  k = _Index._z;
1033 }
1034 
1035 // ---------------------------------------------------------------------------
1036 inline void ConstImageIterator::Voxel(int &i, int &j, int &k, int &l) const
1037 {
1038  i = _Index._x;
1039  j = _Index._y;
1040  k = _Index._z;
1041  l = _Index._t;
1042 }
1043 
1044 // ===========================================================================
1045 // Iteration
1046 // ===========================================================================
1047 
1048 // ---------------------------------------------------------------------------
1050 {
1051  if (_LineStride == 0) CalculateStride();
1053  if (_Data) _Next = reinterpret_cast<const char *>(_Data) + _Inc;
1054  else _Next = nullptr;
1055 }
1056 
1057 // ---------------------------------------------------------------------------
1059 {
1060  _Index = v;
1061  Initialize();
1062 }
1063 
1064 // ---------------------------------------------------------------------------
1065 inline void ConstImageIterator::GoToVoxel(int i, int j, int k, int l)
1066 {
1067  _Index = Vector4D<int>(i, j, k, l);
1068  Initialize();
1069 }
1070 
1071 // ---------------------------------------------------------------------------
1072 inline void ConstImageIterator::GoToIndex(int idx)
1073 {
1074  IndexToVoxel(idx, _Index);
1075  Initialize();
1076 }
1077 
1078 // ---------------------------------------------------------------------------
1079 inline void ConstImageIterator::GoToPos(int pos)
1080 {
1081  PosToVoxel(pos, _Index);
1082  Initialize();
1083 }
1084 
1085 // ---------------------------------------------------------------------------
1087 {
1088  _Index = _Begin;
1089  Initialize();
1090 }
1091 
1092 // ---------------------------------------------------------------------------
1094 {
1095  _Index = _Begin + _Size/2;
1096  Initialize();
1097 }
1098 
1099 // ---------------------------------------------------------------------------
1101 {
1102  _Index = _End;
1103  Initialize();
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1108 {
1109  return _Index._x < _Begin._x;
1110 }
1111 
1112 // ---------------------------------------------------------------------------
1113 inline bool ConstImageIterator::IsAtEnd() const
1114 {
1115  return _Index._t > _End._t;
1116 }
1117 
1118 // ---------------------------------------------------------------------------
1119 inline ConstImageIterator::operator bool() const
1120 {
1121  return !(IsAtBegin() || IsAtEnd());
1122 }
1123 
1124 // ---------------------------------------------------------------------------
1126 {
1127  // Note: Store number of bytes skipped in member variable so that the
1128  // Move method can make use of it to increment external pointers.
1129  if (_Index._t > _Begin._t) {
1130  _Index._x = _End._x;
1131  _Index._y = _End._y;
1132  _Index._z = _End._z;
1133  --_Index._t;
1134  _Inc = -_FrameStride;
1135  } else if (_Index._z > _Begin._z) {
1136  _Index._x = _End._x;
1137  _Index._y = _End._y;
1138  --_Index._z;
1139  _Inc = -_SliceStride;
1140  } else if (_Index._y > _Begin._y) {
1141  _Index._x = _End._x;
1142  --_Index._y;
1143  _Inc = -_LineStride;
1144  } else {
1145  --_Index._x;
1146  _Inc = -_ColumnStride;
1147  }
1148  if (_Next) _Next += _Inc;
1149 }
1150 
1151 // ---------------------------------------------------------------------------
1153 {
1154  // Note: Store number of bytes skipped in member variable so that the
1155  // Move method can make use of it to increment external pointers.
1156  if (_Index._x < _End._x) {
1157  ++_Index._x;
1158  _Inc = _ColumnStride;
1159  } else if (_Index._y < _End._y) {
1160  _Index._x = _Begin._x;
1161  ++_Index._y;
1162  _Inc = _LineStride;
1163  } else if (_Index._z < _End._z) {
1164  _Index._x = _Begin._x;
1165  _Index._y = _Begin._y;
1166  ++_Index._z;
1167  _Inc = _SliceStride;
1168  } else {
1169  _Index._x = _Begin._x;
1170  _Index._y = _Begin._y;
1171  _Index._z = _Begin._z;
1172  ++_Index._t;
1173  _Inc = _FrameStride;
1174  }
1175  if (_Next) _Next += _Inc;
1176 }
1177 
1178 // ---------------------------------------------------------------------------
1179 template <class VoxelType>
1180 inline const VoxelType *ConstImageIterator::Current() const
1181 {
1182  return reinterpret_cast<const VoxelType *>(_Next);
1183 }
1184 
1185 // ---------------------------------------------------------------------------
1186 template <class VoxelType>
1187 inline const VoxelType *ConstImageIterator::Current(int t) const
1188 {
1189  return reinterpret_cast<const VoxelType *>(_Next + t * _XYZ);
1190 }
1191 
1192 // ---------------------------------------------------------------------------
1193 template <class VoxelType>
1194 inline const VoxelType *ConstImageIterator::Next()
1195 {
1196  const VoxelType *current = reinterpret_cast<const VoxelType *>(_Next);
1197  this->operator ++();
1198  return current;
1199 }
1200 
1201 // ---------------------------------------------------------------------------
1202 template <class VoxelType>
1203 inline const VoxelType *ConstImageIterator::Next(int t)
1204 {
1205  const VoxelType *current = reinterpret_cast<const VoxelType *>(_Next + t * _XYZ);
1206  this->operator ++();
1207  return current;
1208 }
1209 
1210 // ---------------------------------------------------------------------------
1211 template <class VoxelType>
1212 inline const VoxelType &ConstImageIterator::Value() const
1213 {
1214  return *reinterpret_cast<const VoxelType *>(_Next);
1215 }
1216 
1217 // ---------------------------------------------------------------------------
1218 template <class VoxelType>
1219 inline const VoxelType &ConstImageIterator::Value(int t) const
1220 {
1221  return *reinterpret_cast<const VoxelType *>(_Next + t * _XYZ);
1222 }
1223 
1224 // ---------------------------------------------------------------------------
1226 {
1227  return Value<double>();
1228 }
1229 
1230 // ---------------------------------------------------------------------------
1231 inline double ConstImageIterator::ValueAsDouble(int t) const
1232 {
1233  return Value<double>(t);
1234 }
1235 
1236 // ---------------------------------------------------------------------------
1237 template <class VoxelType>
1238 inline void ConstImageIterator::Move(const VoxelType *&p) const
1239 {
1240  p += _Inc / _ColumnStride;
1241 }
1242 
1243 // ---------------------------------------------------------------------------
1244 template <class VoxelType>
1245 inline void ConstImageIterator::Move(VoxelType *&p) const
1246 {
1247  p += _Inc / _ColumnStride;
1248 }
1249 
1250 
1251 } // namespace mirtk
1252 
1253 #endif // MIRTK_ConstImageIterator_H
void SetChannel(int, int=1)
Set temporal region (start and size)
void CalculateStride()
Calculate pointer increments.
int NumberOfFrames() const
Get number of frames in image region.
void SetComponent(int, int=1)
Set temporal region (start and size)
int PosToIndex(int) const
Convert iterator position to voxel index.
void GoToIndex(int)
Go to voxel with specified index relative to entire image.
int _XYZ
Number of voxels per frame of the image.
Vector4D< int > _DataSize
Size of the entire image.
virtual ~ConstImageIterator()
Destructor.
void GoToEnd()
Go to end of region.
int LineStride() const
Get stride between rows/lines in number of voxels.
Two-dimensional range.
Definition: Parallel.h:168
int NumberOfComponents() const
Get number of vector components considered.
void Move(const VoxelType *&) const
Vector4D< int > _End
Last index of the image region.
int _Inc
Previous pointer increment in number of bytes.
T _z
The z component.
Definition: Vector4D.h:45
One-dimensional range.
Definition: Parallel.h:155
int _FrameStride
Increment at end of frame in number of bytes.
int _SliceStride
Increment at end of slice in number of bytes.
int Index() const
Index of voxel at current iterator position.
void GoToBegin()
Go to begin of region.
const VoxelType & Value() const
int SliceStride() const
Get stride between slices in number of voxels.
const char * _Next
Pointer to next image voxel.
void SetDataType(int)
Set data type - defines number of bytes per voxel.
void Initialize()
Initialize iterator, called by first GoTo command.
T _t
The t component.
Definition: Vector4D.h:46
void PosToVoxel(int, int &, int &) const
Convert iterator position to voxel coordinates.
void SetNeighborhood(int, int, int, int)
Set 2D neighborhood (center and radius)
Definition: IOConfig.h:41
void GoToVoxel(int, int, int=-1, int=-1)
Go to voxel with specified coordinates relative to entire image.
void SetData(const void *, int=MIRTK_VOXEL_UNKNOWN)
Set raw data pointer to start of entire image.
int ColumnStride() const
Get stride between columns in number of voxels.
Vector4D< int > _Index
Start index of the image region.
bool _IsImageSequence
Whether the image is a sequence.
ConstImageIterator(const ImageAttributes &, int)
Constructor.
int VoxelToIndex(int, int, int=0, int=0) const
Convert voxel coordinates to index.
T _x
The x component.
Definition: Vector4D.h:43
const char * _Data
Pointer to begin of entire image.
void GoToPos(int)
Go to specified position within image region.
void SetRegion(int, int, int, int)
Set 2D image region (start and size)
Three-dimensional range.
Definition: Parallel.h:197
int NumberOfImageVoxels() const
Number of voxels in the entire image.
int VoxelToPos(int, int, int=0, int=0) const
Convert voxel cooridnates to iterator position.
Vector4D< int > _Size
Size of image region.
int _LineStride
Increment at end of line in number of bytes.
bool IsAtEnd() const
Whether iterator reached the end of the region and is invalid now.
virtual double ValueAsDouble() const
Get current voxel value casted to double.
void operator--()
Pre-decrement operator.
void SetFrame(int, int=1)
Set temporal region (start and size)
const VoxelType * Current() const
int Pos() const
Current iterator position within image region.
int FrameStride() const
Get stride between frames in number of voxels.
void operator++()
Pre-increment operator.
Vector4D< int > _Begin
First index of the image region.
ConstImageIterator & operator=(const ConstImageIterator &)
Assignment operator.
void GoToCenter()
Go to center of region.
bool IsAtBegin() const
Whether iterator reached the start of the region and is invalid now.
int NumberOfChannels() const
Get number of channels in image region.
T _y
The y component.
Definition: Vector4D.h:44
void IndexToVoxel(int, int &, int &) const
Convert iterator position to voxel coordinates.
int _ColumnStride
Increment in number of bytes (size of voxel type)
int IndexToPos(int) const
Convert voxel index to iterator position.
int NumberOfVoxels() const
Number of voxels in image region.
void Voxel(int &, int &) const
Coordinates of voxel at current iterator position.