HashImage.hxx
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Antonios Makropoulos
5  * Copyright 2017 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 
21 #ifndef MIRTK_HashImage_HXX
22 #define MIRTK_HashImage_HXX
23 
24 #include "mirtk/ImageConfig.h"
25 #include "mirtk/Math.h"
26 #include "mirtk/Memory.h"
27 #include "mirtk/Path.h"
28 #include "mirtk/Matrix3x3.h"
29 #include "mirtk/VoxelCast.h"
30 #include "mirtk/Vector3D.h"
31 #include "mirtk/Point.h"
32 
33 #include "mirtk/ImageReader.h"
34 #include "mirtk/ImageWriter.h"
35 
36 
37 #if defined(HAVE_VTK) && MIRTK_Image_WITH_VTK
38 # include "vtkStructuredPoints.h"
39 #endif
40 
41 // Default output image file name extension used by HashImage::Write
42 // if none was provided (e.g., when called by debugging library functions
43 // such as overridden EnergyTerm::WriteDataSets implementations).
44 #ifndef MIRTK_Image_DEFAULT_EXT
45 # define MIRTK_Image_DEFAULT_EXT ".gipl"
46 #endif
47 
48 
49 namespace mirtk {
50 
51 
52 // =============================================================================
53 // Construction/Destruction
54 // =============================================================================
55 
56 // -----------------------------------------------------------------------------
57 // Note: Base class BaseImage must be initialized before calling this function!
58 template <class VoxelType>
60 {
61  // Delete existing mask (if any)
62  if (_maskOwner) Delete(_mask);
63  // Free previously allocated memory
64  _Data.clear();
65  _DefaultValue = VoxelType();
66 }
67 
68 // -----------------------------------------------------------------------------
69 template <class VoxelType>
71 
72 // -----------------------------------------------------------------------------
73 template <class VoxelType>
75 {
76  Read(fname);
77 }
78 
79 // -----------------------------------------------------------------------------
80 template <class VoxelType>
81 HashImage<VoxelType>::HashImage(int x, int y, int z, int t)
82 {
83  ImageAttributes attr;
84  attr._x = x;
85  attr._y = y;
86  attr._z = z;
87  attr._t = t;
88  PutAttributes(attr);
89  AllocateImage();
90 }
91 
92 // -----------------------------------------------------------------------------
93 template <class VoxelType>
94 HashImage<VoxelType>::HashImage(int x, int y, int z, int t, int n)
95 {
96  if (t > 1 && n > 1) {
97  cerr << "HashImage::HashImage: 5D images not supported! Use 4D image with vector voxel type instead." << endl;
98  exit(1);
99  }
100  ImageAttributes attr;
101  if (n > 1) t = n, attr._dt = .0; // i.e., vector image with n components
102  attr._x = x;
103  attr._y = y;
104  attr._z = z;
105  attr._t = t;
106  PutAttributes(attr);
107  AllocateImage();
108 }
109 
110 // -----------------------------------------------------------------------------
111 template <class VoxelType>
113 :
114  BaseImage(attr, n)
115 {
116  AllocateImage();
117 }
118 
119 // -----------------------------------------------------------------------------
120 template <class VoxelType>
122 :
123  BaseImage(image)
124 {
125  // Initialize image
126  AllocateImage();
127  // Copy/cast data
128  CopyFrom(image);
129 }
130 
131 
132 // -----------------------------------------------------------------------------
133 template <class VoxelType>
135 :
136  BaseImage(image)
137 {
138  AllocateImage();
139  CopyFrom(image);
140 }
141 
142 // -----------------------------------------------------------------------------
143 template <class VoxelType> template <class VoxelType2>
145 :
146  BaseImage(image)
147 {
148  AllocateImage();
149  CopyFrom(image);
150 }
151 
152 // -----------------------------------------------------------------------------
153 template <class VoxelType> template <class VoxelType2>
155 :
156  BaseImage(image)
157 {
158  AllocateImage();
159  CopyFrom(image);
160 }
161 
162 // -----------------------------------------------------------------------------
163 template <class VoxelType>
165 {
166  Clear();
167 }
168 
169 
170 // -----------------------------------------------------------------------------
171 template <class VoxelType> void HashImage<VoxelType>::Clear()
172 {
173  _Data.clear();
174  if (_maskOwner) Delete(_mask);
176 }
177 
178 
179 // =============================================================================
180 // Initialization
181 // =============================================================================
182 
183 // -----------------------------------------------------------------------------
184 template <class VoxelType>
186 {
187  return new HashImage<VoxelType>(*this);
188 }
189 
190 // -----------------------------------------------------------------------------
191 template <class VoxelType> void HashImage<VoxelType>::Initialize()
192 {
193  *this = VoxelType();
194 }
195 
196 // -----------------------------------------------------------------------------
197 template <class VoxelType>
199 {
200  // Initialize attributes
201  ImageAttributes attr(a);
202  if (n >= 1) {
203  attr._t = n;
204  attr._dt = 0.; // i.e., vector image with n components
205  }
206  // Initialize memory
207  if (_attr._x != attr._x || _attr._y != attr._y || _attr._z != attr._z || _attr._t != attr._t) {
208  PutAttributes(attr);
209  AllocateImage();
210  } else {
211  PutAttributes(attr);
212  _DefaultValue = VoxelType();
213  *this = VoxelType();
214  }
215 }
216 
217 // -----------------------------------------------------------------------------
218 template <class VoxelType>
219 void HashImage<VoxelType>::Initialize(int x, int y, int z, int t, int n)
220 {
221  ImageAttributes attr(_attr);
222  attr._x = x;
223  attr._y = y;
224  attr._z = z;
225  attr._t = t;
226  this->Initialize(attr, n);
227 }
228 
229 // -----------------------------------------------------------------------------
230 template <class VoxelType>
231 void HashImage<VoxelType>::Initialize(int x, int y, int z, int t)
232 {
233  this->Initialize(x, y, z, t, 1);
234 }
235 
236 // -----------------------------------------------------------------------------
237 template <class VoxelType>
239 {
240  if (this != &image) {
241  VoxelType value;
242  _Data.clear();
243  _DefaultValue = VoxelType();
244 
245  for (int idx = 0; idx < _NumberOfVoxels; ++idx) {
246  Put(idx, voxel_cast<VoxelType>(image.GetAsVector(idx) ));
247  }
248  if (_maskOwner) delete _mask;
249  if (image.OwnsMask()) {
250  _mask = new BinaryImage(*image.GetMask());
251  _maskOwner = true;
252  } else {
253  _mask = const_cast<BinaryImage *>(image.GetMask());
254  _maskOwner = false;
255  }
256  if (image.HasBackgroundValue()) {
258  }
259  }
260 }
261 
262 // -----------------------------------------------------------------------------
263 template <class VoxelType> template <class VoxelType2>
265 {
266  _Data.clear();
267  _DefaultValue = VoxelType();
268 
269  for (int idx = 0; idx < _NumberOfVoxels; ++idx) {
270  Put(idx, voxel_cast<VoxelType>(image.Get(idx)));
271  }
272 
273  if (_maskOwner) delete _mask;
274  if (image.OwnsMask()) {
275  _mask = new BinaryImage(*image.GetMask());
276  _maskOwner = true;
277  } else {
278  _mask = const_cast<BinaryImage *>(image.GetMask());
279  _maskOwner = false;
280  }
281  if (image.HasBackgroundValue()) {
283  }
284 }
285 
286 // -----------------------------------------------------------------------------
287 template <class VoxelType> template <class VoxelType2>
289 {
290  _Data.clear();
291  _DefaultValue = voxel_cast<VoxelType>(image.DefaultValue());
292 
293  for (auto it = image.Begin(); it != image.End(); ++it) {
294  Put(it->first, voxel_cast<VoxelType>(it->second));
295  }
296 
297  if (_maskOwner) delete _mask;
298  if (image.OwnsMask()) {
299  _mask = new BinaryImage(*image.GetMask());
300  _maskOwner = true;
301  } else {
302  _mask = const_cast<BinaryImage *>(image.GetMask());
303  _maskOwner = false;
304  }
305  if (image.HasBackgroundValue()) {
307  }
308 }
309 
310 
311 // -----------------------------------------------------------------------------
312 template <class VoxelType> template <class VoxelType2>
314 {
315  image.Initialize(_attr);
316  image = voxel_cast<VoxelType2>(_DefaultValue);
317  for (auto it = Begin(); it != End(); ++it) {
318  image.Put(it->first, voxel_cast<VoxelType2>(it->second));
319  }
320 }
321 
322 // -----------------------------------------------------------------------------
323 template <class VoxelType>
325 {
326  _Data.clear();
327  _DefaultValue=scalar;
328  return *this;
329 }
330 
331 // -----------------------------------------------------------------------------
332 template <class VoxelType>
334 {
335  if (this != &image) {
336  this->Initialize(image.Attributes());
337  this->CopyFrom(image);
338  }
339  return *this;
340 }
341 // -----------------------------------------------------------------------------
342 template <class VoxelType> template <class VoxelType2>
344 {
345  this->Initialize(image.Attributes());
346  this->CopyFrom(image);
347  return *this;
348 }
349 
350 // -----------------------------------------------------------------------------
351 template <class VoxelType>
353 {
354  if (this != &image) {
355  this->Initialize(image.Attributes());
356  this->CopyFrom(image);
357  }
358  return *this;
359 }
360 
361 // -----------------------------------------------------------------------------
362 template <class VoxelType> template <class VoxelType2>
364 {
365  this->Initialize(image.GetImageAttributes());
366  CopyFrom(image);
367 }
368 
369 // -----------------------------------------------------------------------------
370 template <class VoxelType> template <class VoxelType2>
372 {
373  if (this->GetImageAttributes() != image.GetImageAttributes()) return false;
374  if (_DefaultValue != image.DefaultValue()) return false;
375  if (_Data.size() != image.NumberOfNonDefaultVoxels()) return false;
376  for (int idx = 0; idx < _NumberOfVoxels; ++idx) {
377  if (IsForeground(idx) && image.IsForeground(idx)){
378  if(Get(idx)!= voxel_cast<VoxelType>(image.Get(idx)))
379  return false;
380  }
381  }
382  return true;
383 }
384 
385 
386 // =============================================================================
387 // Region-of-interest extraction
388 // =============================================================================
389 
390 // -----------------------------------------------------------------------------
391 template <class VoxelType>
393 ::GetRegion(HashImage &image, int k, int m) const
394 {
395  int i, j;
396  double x1, y1, z1, t1, x2, y2, z2, t2;
397 
398  if ((k < 0) || (k >= _attr._z) || (m < 0) || (m >= _attr._t)) {
399  Throw(ERR_InvalidArgument, __FUNCTION__, "Parameter out of range");
400  }
401 
402  // Initialize
403  ImageAttributes attr = this->Attributes();
404  attr._z = 1;
405  attr._t = 1;
406  attr._xorigin = 0;
407  attr._yorigin = 0;
408  attr._zorigin = 0;
409  image.Initialize(attr);
410 
411  // Calculate position of first voxel in roi in original image
412  x1 = 0;
413  y1 = 0;
414  z1 = k;
415  this->ImageToWorld(x1, y1, z1);
416  t1 = this->ImageToTime(m);
417 
418  // Calculate position of first voxel in roi in new image
419  x2 = 0;
420  y2 = 0;
421  z2 = 0;
422  t2 = 0;
423  image.ImageToWorld(x2, y2, z2);
424  t2 = image.ImageToTime(0);
425 
426  // Shift origin of new image accordingly
427  image.PutOrigin(x1 - x2, y1 - y2, z1 - z2, t1 - t2);
428 
429  // Copy region
430  VoxelType value, empty=image.DefaultValue();
431  for (j = 0; j < _attr._y; j++)
432  for (i = 0; i < _attr._x; i++) {
433  value=Get(i,j,k,m);
434  if(value!=empty) image.Put(i,j,0,0, value );
435  }
436 }
437 
438 // -----------------------------------------------------------------------------
439 template <class VoxelType>
441 ::GetRegion(int k, int m) const
442 {
443  HashImage<VoxelType> image;
444  this->GetRegion(image, k, m);
445  return image;
446 }
447 
448 // -----------------------------------------------------------------------------
449 template <class VoxelType>
451 ::GetRegion(BaseImage *&base, int k, int m) const
452 {
453  HashImage<VoxelType> *image = dynamic_cast<HashImage<VoxelType> *>(base);
454  if (image == NULL) {
455  delete base;
456  image = new HashImage<VoxelType>();
457  base = image;
458  }
459  this->GetRegion(*image, k, m);
460 }
461 
462 // -----------------------------------------------------------------------------
463 template <class VoxelType>
465 ::GetRegion(HashImage &image, int i1, int j1, int k1,
466  int i2, int j2, int k2) const
467 {
468  int i, j, k, l;
469  double x1, y1, z1, x2, y2, z2;
470 
471  if ((i1 < 0) || (i1 >= i2) ||
472  (j1 < 0) || (j1 >= j2) ||
473  (k1 < 0) || (k1 >= k2) ||
474  (i2 > _attr._x) || (j2 > _attr._y) || (k2 > _attr._z)) {
475  Throw(ERR_InvalidArgument, __FUNCTION__, "Parameter out of range");
476  }
477 
478  // Initialize
479  ImageAttributes attr = this->Attributes();
480  attr._x = i2 - i1;
481  attr._y = j2 - j1;
482  attr._z = k2 - k1;
483  attr._xorigin = 0;
484  attr._yorigin = 0;
485  attr._zorigin = 0;
486  image.Initialize(attr);
487 
488  // Calculate position of first voxel in roi in original image
489  x1 = i1;
490  y1 = j1;
491  z1 = k1;
492  this->ImageToWorld(x1, y1, z1);
493 
494  // Calculate position of first voxel in roi in new image
495  x2 = 0;
496  y2 = 0;
497  z2 = 0;
498  image.ImageToWorld(x2, y2, z2);
499 
500  // Shift origin of new image accordingly
501  image.PutOrigin(x1 - x2, y1 - y2, z1 - z2);
502 
503  // Copy region
504  VoxelType value, empty=image.DefaultValue();
505  for (l = 0; l < _attr._t; l++)
506  for (k = k1; k < k2; k++)
507  for (j = j1; j < j2; j++)
508  for (i = i1; i < i2; i++) {
509  value= Get(i,j,k,l);
510  if(value!=empty) image.Put(i-i1,j-j1,k-k1,l, value );
511  }
512 }
513 
514 // -----------------------------------------------------------------------------
515 template <class VoxelType>
517 ::GetRegion(int i1, int j1, int k1, int i2, int j2, int k2) const
518 {
519  HashImage<VoxelType> image;
520  this->GetRegion(image, i1, j1, k1, i2, j2, k2);
521  return image;
522 }
523 
524 // -----------------------------------------------------------------------------
525 template <class VoxelType>
527 ::GetRegion(BaseImage *&base, int i1, int j1, int k1, int i2, int j2, int k2) const
528 {
529  HashImage<VoxelType> *image = dynamic_cast<HashImage<VoxelType> *>(base);
530  if (image == NULL) {
531  delete base;
532  image = new HashImage<VoxelType>();
533  base = image;
534  }
535  this->GetRegion(*image, i1, j1, k1, i2, j2, k2);
536 }
537 
538 // -----------------------------------------------------------------------------
539 template <class VoxelType>
541 ::GetRegion(HashImage &image, int i1, int j1, int k1, int l1,
542  int i2, int j2, int k2, int l2) const
543 {
544  int i, j, k, l;
545  double x1, y1, z1, x2, y2, z2;
546 
547  if ((i1 < 0) || (i1 >= i2) ||
548  (j1 < 0) || (j1 >= j2) ||
549  (k1 < 0) || (k1 >= k2) ||
550  (l1 < 0) || (l1 >= l2) ||
551  (i2 > _attr._x) || (j2 > _attr._y) || (k2 > _attr._z) || (l2 > _attr._t)) {
552  Throw(ERR_InvalidArgument, __FUNCTION__, "Parameter out of range");
553  }
554 
555  // Initialize
556  ImageAttributes attr = this->Attributes();
557  attr._x = i2 - i1;
558  attr._y = j2 - j1;
559  attr._z = k2 - k1;
560  attr._t = l2 - l1;
561  attr._xorigin = 0;
562  attr._yorigin = 0;
563  attr._zorigin = 0;
564  image.Initialize(attr);
565 
566  // Calculate position of first voxel in roi in original image
567  x1 = i1;
568  y1 = j1;
569  z1 = k1;
570  this->ImageToWorld(x1, y1, z1);
571 
572  // Calculate position of first voxel in roi in new image
573  x2 = 0;
574  y2 = 0;
575  z2 = 0;
576  image.ImageToWorld(x2, y2, z2);
577 
578  // Shift origin of new image accordingly
579  image.PutOrigin(x1 - x2, y1 - y2, z1 - z2);
580 
581  // Copy region
582  VoxelType value, empty=image.DefaultValue();
583  for (l = l1; l < l2; l++)
584  for (k = k1; k < k2; k++)
585  for (j = j1; j < j2; j++)
586  for (i = i1; i < i2; i++) {
587  value= Get(i,j,k,l);
588  if(value!=empty) image.Put(i-i1,j-j1,k-k1,l-l1, value );
589  }
590 }
591 
592 // -----------------------------------------------------------------------------
593 template <class VoxelType>
595 ::GetRegion(int i1, int j1, int k1, int l1, int i2, int j2, int k2, int l2) const
596 {
597  HashImage<VoxelType> image;
598  this->GetRegion(image, i1, j1, k1, l1, i2, j2, k2, l2);
599  return image;
600 }
601 
602 // -----------------------------------------------------------------------------
603 template <class VoxelType>
605 ::GetRegion(BaseImage *&base, int i1, int j1, int k1, int l1, int i2, int j2, int k2, int l2) const
606 {
607  HashImage<VoxelType> *image = dynamic_cast<HashImage<VoxelType> *>(base);
608  if (image == NULL) {
609  delete base;
610  image = new HashImage<VoxelType>();
611  base = image;
612  }
613  this->GetRegion(*image, i1, j1, k1, l1, i2, j2, k2, l2);
614 }
615 
616 // -----------------------------------------------------------------------------
617 template <class VoxelType>
618 void HashImage<VoxelType>::GetFrame(HashImage &image, int l1, int l2) const
619 {
620  if (l2 < 0) l2 = l1;
621 
622  if ((l2 < 0) || (l1 >= _attr._t)) {
623  Throw(ERR_InvalidArgument, __FUNCTION__, "Parameter out of range");
624  }
625 
626  if (l1 < 0) l1 = 0;
627  if (l2 >= _attr._t) l2 = _attr._t - 1;
628 
629  // Initialize
630  ImageAttributes attr = this->Attributes();
631  attr._t = l2 - l1 + 1;
632  attr._torigin = this->ImageToTime(l1);
633  image.Initialize(attr);
634 
635  // Copy region
636  VoxelType value, empty=image.DefaultValue();
637  for (int l = l1; l <= l2; l++)
638  for (int k = 0; k < _attr._z; k++)
639  for (int j = 0; j < _attr._y; j++)
640  for (int i = 0; i < _attr._x; i++) {
641  value= Get(i,j,k,l);
642  if(value!=empty) image.Put(i,j,k,l-l1, value );
643  }
644 }
645 
646 // -----------------------------------------------------------------------------
647 template <class VoxelType>
649 {
650  HashImage<VoxelType> image;
651  this->GetFrame(image, l1, l2);
652  return image;
653 }
654 
655 // -----------------------------------------------------------------------------
656 template <class VoxelType>
657 void HashImage<VoxelType>::GetFrame(BaseImage *&base, int l1, int l2) const
658 {
659  HashImage<VoxelType> *image = dynamic_cast<HashImage<VoxelType> *>(base);
660  if (image == NULL) {
661  delete base;
662  image = new HashImage<VoxelType>();
663  base = image;
664  }
665  this->GetFrame(*image, l1, l2);
666 }
667 
668 
669 // =============================================================================
670 // Image arithmetic
671 // =============================================================================
672 
673 // -----------------------------------------------------------------------------
674 template <class VoxelType>
676 {
677  if (image.Attributes() != this->Attributes()) {
678  cerr << "HashImage::operator+=: Size mismatch in images" << endl;
679  this->Attributes().Print();
680  image.Attributes().Print();
681  exit(1);
682  }
683 
684  for (int idx = 0; idx < _NumberOfVoxels; idx++) {
685  if (IsForeground(idx) && image.IsForeground(idx))
686  Put(idx, Get(idx)+image.Get(idx));
687  }
688  return *this;
689 }
690 
691 // -----------------------------------------------------------------------------
692 template <class VoxelType>
694 {
695  if (image.Attributes() != this->Attributes()) {
696  cerr << "HashImage::operator-=: Size mismatch in images" << endl;
697  this->Attributes().Print();
698  image.Attributes().Print();
699  exit(1);
700  }
701 
702  for (int idx = 0; idx < _NumberOfVoxels; idx++) {
703  if (IsForeground(idx) && image.IsForeground(idx))
704  Put(idx, Get(idx)-image.Get(idx));
705  }
706  return *this;
707 }
708 
709 // -----------------------------------------------------------------------------
710 template <class VoxelType>
712 {
713  if (image.Attributes() != this->Attributes()) {
714  cerr << "HashImage::operator*=: Size mismatch in images" << endl;
715  this->Attributes().Print();
716  image.Attributes().Print();
717  exit(1);
718  }
719 
720  for (int idx = 0; idx < _NumberOfVoxels; idx++) {
721  if (IsForeground(idx) && image.IsForeground(idx))
722  Put(idx, Get(idx)*image.Get(idx));
723  }
724  return *this;
725 }
726 
727 // -----------------------------------------------------------------------------
728 template <class VoxelType>
730 {
731  if (image.Attributes() != this->Attributes()) {
732  cerr << "HashImage::operator/=: Size mismatch in images" << endl;
733  this->Attributes().Print();
734  image.Attributes().Print();
735  exit(1);
736  }
737 
738  VoxelType value;
739  for (int idx = 0; idx < _NumberOfVoxels; idx++) {
740  if (IsForeground(idx) && image.IsForeground(idx)){
741  value=image.Get(idx);
742  if(value != VoxelType()){
743  value=Get(idx)/value;
744  }
745  Put(idx, value);
746  }
747  }
748  return *this;
749 }
750 
752 {
753  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=float3x3");
754  return *this;
755 }
756 
758 {
759  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=double3x3");
760  return *this;
761 }
762 
763 // -----------------------------------------------------------------------------
764 template <class VoxelType>
766 {
767  _DefaultValue += scalar;
768  for ( auto it = Begin(); it != End(); ++it ){
769  if (IsForeground(it->first)){
770  _Data[it->first] +=scalar;
771  }
772  }
773  return *this;
774 }
775 
776 // -----------------------------------------------------------------------------
777 template <class VoxelType>
779 {
780  _DefaultValue -= scalar;
781  for ( auto it = Begin(); it != End(); ++it ){
782  if (IsForeground(it->first)){
783  _Data[it->first] -=scalar;
784  }
785  }
786  return *this;
787 }
788 
789 // -----------------------------------------------------------------------------
790 template <class VoxelType>
792 {
793  _DefaultValue *= scalar;
794  if(scalar==0){
795  _Data.clear();
796  }else{
797  for ( auto it = Begin(); it != End(); ++it ){
798  if (IsForeground(it->first)){
799  _Data[it->first] *=scalar;
800  }
801  }
802  }
803  return *this;
804 }
805 
806 // -----------------------------------------------------------------------------
807 template <class VoxelType>
809 {
810  if (scalar) {
811  _DefaultValue /= scalar;
812  for ( auto it = Begin(); it != End(); ++it ){
813  if (IsForeground(it->first)){
814  _Data[it->first] /=scalar;
815  }
816  }
817  } else {
818  cerr << "HashImage::operator/=: Division by zero" << endl;
819  }
820  return *this;
821 }
822 
823 // -----------------------------------------------------------------------------
824 
825 template <class VoxelType>
827 {
828  HashImage<VoxelType> tmp(*this);
829  tmp += image;
830  return tmp;
831 }
832 
833 // -----------------------------------------------------------------------------
834 template <class VoxelType>
836 {
837  HashImage<VoxelType> tmp(*this);
838  tmp -= image;
839  return tmp;
840 }
841 
842 // -----------------------------------------------------------------------------
843 template <class VoxelType>
845 {
846  HashImage<VoxelType> tmp(*this);
847  tmp *= image;
848  return tmp;
849 }
850 
851 // -----------------------------------------------------------------------------
852 template <class VoxelType>
854 {
855  HashImage<VoxelType> tmp(*this);
856  tmp /= image;
857  return tmp;
858 }
859 // -----------------------------------------------------------------------------
860 template <class VoxelType>
862 {
863  HashImage<VoxelType> tmp(*this);
864  tmp += scalar;
865  return tmp;
866 }
867 
868 // -----------------------------------------------------------------------------
869 template <class VoxelType>
871 {
872  HashImage<VoxelType> tmp(*this);
873  tmp -= scalar;
874  return tmp;
875 }
876 
877 // -----------------------------------------------------------------------------
878 template <class VoxelType>
880 {
881  HashImage<VoxelType> tmp(*this);
882  tmp *= scalar;
883  return tmp;
884 }
885 
886 // -----------------------------------------------------------------------------
887 template <class VoxelType>
889 {
890  HashImage<VoxelType> tmp(*this);
891  tmp /= scalar;
892  return tmp;
893 }
894 
895 
896 // =============================================================================
897 // Thresholding
898 // =============================================================================
899 
900 // -----------------------------------------------------------------------------
901 template <class VoxelType>
902 void HashImage<VoxelType>::PutBackgroundValueAsDouble(double value, bool threshold)
903 {
904  _bg = value;
905  _bgSet = true;
906  if (threshold) {
907  const VoxelType bg = voxel_cast<VoxelType>(this->_bg);
908 
909  bool changedValue=false;
910  if( _DefaultValue < bg){
911  changedValue=true;
912  _DefaultValue=bg;
913  }
914 
915  bool modify=false;
916  for ( auto it = Begin(); it != End();){
917  modify=(it->second < bg);
918  if(modify && changedValue){
919  // this erase also increases the iterator to the next element...
920  it = _Data.erase( it );
921  }else {
922  if(modify){
923  _Data[it->first]=bg;
924  }
925  it++;
926  }
927  }
928 
929  }
930 }
931 
932 template <> inline void HashImage<float3x3>::PutBackgroundValueAsDouble(double value, bool threshold)
933 {
934  BaseImage::PutBackgroundValueAsDouble(value, threshold);
935 }
936 
937 template <> inline void HashImage<double3x3>::PutBackgroundValueAsDouble(double value, bool threshold)
938 {
939  BaseImage::PutBackgroundValueAsDouble(value, threshold);
940 }
941 
942 
943 // =============================================================================
944 // Common image statistics
945 // =============================================================================
946 
947 // -----------------------------------------------------------------------------
948 template <class VoxelType>
950 {
951  min = max = _DefaultValue;
952 
953  VoxelType value;
954  for ( auto it = Begin(); it != End(); ++it ){
955  if (IsForeground(it->first)) {
956  value=it->second;
957  if (value < min) min = value;
958  if (value > max) max = value;
959  }
960  }
961 }
962 
963 template <> inline void HashImage<float3x3 >::GetMinMax(VoxelType &, VoxelType &) const
964 {
965  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=float3x3");
966 }
967 
968 template <> inline void HashImage<double3x3>::GetMinMax(VoxelType &, VoxelType &) const
969 {
970  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=double3x3");
971 }
972 
973 // -----------------------------------------------------------------------------
974 template <class VoxelType>
976 {
977  min = max = _DefaultValue;
978  VoxelType value;
979  for ( auto it = Begin(); it != End(); ++it ){
980  value=it->second;
981  if (value != pad) {
982  if (value < min) min = value;
983  if (value > max) max = value;
984  }
985  }
986 }
987 
988 template <> inline void HashImage<float3x3 >::GetMinMax(VoxelType &, VoxelType &, VoxelType) const
989 {
990  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=float3x3");
991 }
992 
993 template <> inline void HashImage<double3x3>::GetMinMax(VoxelType &, VoxelType &, VoxelType) const
994 {
995  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=double3x3");
996 }
997 
998 // -----------------------------------------------------------------------------
999 template <class VoxelType>
1001 {
1002  VoxelType min_val, max_val;
1003  this->GetMinMax(min_val, max_val);
1004  RealType slope = voxel_cast<RealType>(max - min) / voxel_cast<RealType>(max_val - min_val);
1005  RealType inter = voxel_cast<RealType>(min) - slope * voxel_cast<RealType>(min_val);
1006 
1007  _DefaultValue = inter + slope * _DefaultValue;
1008  for ( auto it = Begin(); it != End(); ++it ){
1009  if (IsForeground(it->first)) {
1010  _Data[it->first]=static_cast<VoxelType>(inter + slope *it->second);
1011  }
1012  }
1013 }
1014 
1015 template <> inline void HashImage<float3x3>::PutMinMax(VoxelType, VoxelType)
1016 {
1017  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=float3x3");
1018 }
1019 
1020 template <> inline void HashImage<double3x3>::PutMinMax(VoxelType, VoxelType)
1021 {
1022  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=double3x3");
1023 }
1024 
1025 
1026 // =============================================================================
1027 // Common image manipulations
1028 // =============================================================================
1029 
1030 // -----------------------------------------------------------------------------
1031 template <class VoxelType>
1032 void HashImage<VoxelType>::ReflectX(bool modify_axes)
1033 {
1034  VoxelType value;
1035  for (int t = 0; t < _attr._t; ++t)
1036  for (int z = 0; z < _attr._z; ++z)
1037  for (int y = 0; y < _attr._y; ++y)
1038  for (int x = 0; x < _attr._x / 2; ++x) {
1039  value=Get(x,y,z,t);
1040  Put(x,y,z,t, Get(_attr._x-(x+1),y,z,t));
1041  Put(_attr._x-(x+1),y,z,t, value);
1042  }
1043  if (modify_axes) {
1044  _attr._xaxis[0] = -_attr._xaxis[0];
1045  _attr._xaxis[1] = -_attr._xaxis[1];
1046  _attr._xaxis[2] = -_attr._xaxis[2];
1047  UpdateMatrix();
1048  }
1049 }
1050 
1051 // -----------------------------------------------------------------------------
1052 template <class VoxelType>
1053 void HashImage<VoxelType>::ReflectY(bool modify_axes)
1054 {
1055  VoxelType value;
1056  for (int t = 0; t < _attr._t; ++t)
1057  for (int z = 0; z < _attr._z; ++z)
1058  for (int y = 0; y < _attr._y / 2; ++y)
1059  for (int x = 0; x < _attr._x; ++x) {
1060  value=Get(x,y,z,t);
1061  Put(x,y,z,t, Get(x,_attr._y-(y+1),z,t));
1062  Put(x,_attr._y-(y+1),z,t, value);
1063  }
1064  if (modify_axes) {
1065  _attr._yaxis[0] = -_attr._yaxis[0];
1066  _attr._yaxis[1] = -_attr._yaxis[1];
1067  _attr._yaxis[2] = -_attr._yaxis[2];
1068  UpdateMatrix();
1069  }
1070 }
1071 
1072 // -----------------------------------------------------------------------------
1073 template <class VoxelType>
1074 void HashImage<VoxelType>::ReflectZ(bool modify_axes)
1075 {
1076  VoxelType value;
1077  for (int t = 0; t < _attr._t; ++t)
1078  for (int z = 0; z < _attr._z / 2; ++z)
1079  for (int y = 0; y < _attr._y; ++y)
1080  for (int x = 0; x < _attr._x; ++x) {
1081  value=Get(x,y,z,t);
1082  Put(x,y,z,t, Get(x,y,_attr._z-(z+1),t));
1083  Put(x,y,_attr._z-(z+1),t, value);
1084  }
1085  if (modify_axes) {
1086  _attr._zaxis[0] = -_attr._zaxis[0];
1087  _attr._zaxis[1] = -_attr._zaxis[1];
1088  _attr._zaxis[2] = -_attr._zaxis[2];
1089  UpdateMatrix();
1090  }
1091 }
1092 
1093 // -----------------------------------------------------------------------------
1094 template <class VoxelType>
1095 void HashImage<VoxelType>::ReflectT(bool modify_axes)
1096 {
1097  VoxelType value;
1098  for (int t = 0; t < _attr._t / 2; ++t)
1099  for (int z = 0; z < _attr._z; ++z)
1100  for (int y = 0; y < _attr._y; ++y)
1101  for (int x = 0; x < _attr._x; ++x) {
1102  value=Get(x,y,z,t);
1103  Put(x,y,z,t, Get(x,y,z,_attr._t-(t+1)));
1104  Put(x,y,z,_attr._t-(t+1), value);
1105  }
1106  if (modify_axes) {
1107  _attr._dt = -_attr._dt;
1108  }
1109 }
1110 
1111 
1112 // -----------------------------------------------------------------------------
1113 template <class VoxelType>
1115 {
1116  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1117 }
1118 
1119 // -----------------------------------------------------------------------------
1120 template <class VoxelType>
1122 {
1123  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1124 }
1125 
1126 // -----------------------------------------------------------------------------
1127 template <class VoxelType>
1129 {
1130  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1131 }
1132 
1133 // -----------------------------------------------------------------------------
1134 template <class VoxelType>
1136 {
1137  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1138 }
1139 
1140 // -----------------------------------------------------------------------------
1141 template <class VoxelType>
1143 {
1144  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1145 }
1146 
1147 // -----------------------------------------------------------------------------
1148 template <class VoxelType>
1150 {
1151  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1152 }
1153 
1154 
1155 // -----------------------------------------------------------------------------
1156 template <class VoxelType>
1158 {
1159  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1160 }
1161 
1162 // -----------------------------------------------------------------------------
1163 template <class VoxelType>
1165 {
1166  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1167 }
1168 
1169 // -----------------------------------------------------------------------------
1170 template <class VoxelType>
1172 {
1173  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1174 }
1175 
1176 // -----------------------------------------------------------------------------
1177 template <class VoxelType>
1179 {
1180  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1181 }
1182 
1183 // -----------------------------------------------------------------------------
1184 template <class VoxelType>
1186 {
1187  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1188 }
1189 
1190 // -----------------------------------------------------------------------------
1191 template <class VoxelType>
1193 {
1194  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1195 }
1196 
1197 // =============================================================================
1198 // VTK interface
1199 // =============================================================================
1200 #if defined(HAVE_VTK) && MIRTK_Image_WITH_VTK
1201 
1202 // -----------------------------------------------------------------------------
1203 template <class VoxelType>
1204 void HashImage<VoxelType>::ImageToVTK(vtkStructuredPoints *vtk) const
1205 {
1206  if (this->ImageToVTKScalarType() == VTK_VOID) {
1207  Throw(ERR_LogicError, __FUNCTION__, "Cannot convert image with this VoxelType to VTK structured points");
1208  }
1209  double x = 0, y = 0, z = 0;
1210  this->ImageToWorld(x, y, z);
1211  vtk->SetOrigin (x, y, z);
1212  vtk->SetDimensions(_attr._x, _attr._y, _attr._z);
1213  vtk->SetSpacing (_attr._dx, _attr._dy, _attr._dz);
1214 #if VTK_MAJOR_VERSION >= 6
1215  vtk->AllocateScalars(this->ImageToVTKScalarType(), 1);
1216 #else
1217  vtk->SetScalarType(this->ImageToVTKScalarType());
1218  vtk->AllocateScalars();
1219 #endif
1220  const int nvox = _attr._x * _attr._y * _attr._z;
1221  VoxelType *ptr2 = reinterpret_cast<VoxelType *>(vtk->GetScalarPointer());
1222  for (int i = 0; i < nvox; ++i) {
1223  for (int l = 0; l < _attr._t; ++l, ++ptr2) *ptr2 = Get(l * nvox);
1224  }
1225 }
1226 
1227 template <>
1228 inline void HashImage<Matrix3x3>::ImageToVTK(vtkStructuredPoints *) const
1229 {
1230  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1231 }
1232 
1233 // -----------------------------------------------------------------------------
1234 template <class Type>
1235 void HashImage<Type>::VTKToImage(vtkStructuredPoints *)
1236 {
1237  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1238 }
1239 
1240 #endif // defined(HAVE_VTK) && MIRTK_Image_WITH_VTK
1241 // =============================================================================
1242 // I/O
1243 // =============================================================================
1244 
1245 // -----------------------------------------------------------------------------
1246 template <class VoxelType>
1247 void HashImage<VoxelType>::Read(const char *fname)
1248 {
1249  // Read image
1250  GenericImage<VoxelType> img(fname);
1251  Initialize(img.Attributes());
1252  CopyFrom(img);
1253 }
1254 
1255 template <> inline void HashImage<float3x3>::Read(const char *)
1256 {
1257  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=float3x3");
1258 }
1259 
1260 template <> inline void HashImage<double3x3>::Read(const char *)
1261 {
1262  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=double3x3");
1263 }
1264 
1265 // -----------------------------------------------------------------------------
1266 template <class VoxelType>
1267 void HashImage<VoxelType>::Write(const char *fname) const
1268 {
1269  string name(fname);
1270  if (Extension(fname).empty()) name += MIRTK_Image_DEFAULT_EXT;
1271  UniquePtr<ImageWriter> writer(ImageWriter::New(name.c_str()));
1272  GenericImage<VoxelType> img=this->ToGenericImage();
1273  writer->Input(&img);
1274  writer->Run();
1275 }
1276 
1277 template <> inline void HashImage<float3x3>::Write(const char *) const
1278 {
1279  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=float3x3");
1280 }
1281 
1282 template <> inline void HashImage<double3x3>::Write(const char *) const
1283 {
1284  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented for VoxelType=double3x3");
1285 }
1286 
1287 // -----------------------------------------------------------------------------
1288 template <class VoxelType>
1290 {
1291  GenericImage<VoxelType> dense_image;
1292  this->CopyTo(dense_image);
1293  return dense_image;
1294 }
1295 
1296 // -----------------------------------------------------------------------------
1297 template <class VoxelType> template <class VoxelType2>
1299 {
1300  this->CopyTo(image);
1301 }
1302 
1303 
1304 } // namespace mirtk
1305 
1306 #endif // MIRTK_HashImage_HXX
double _dt
Voxel t-dimensions (in ms)
int _NumberOfVoxels
Total number of voxels.
Definition: BaseImage.h:102
double _xaxis[3]
Direction of x-axis.
bool HasBackgroundValue() const
Whether a background value has been set.
Definition: BaseImage.h:1425
void Print(ostream &, Indent=0) const
Print attributes.
double GetBackgroundValueAsDouble() const
Get background value.
Definition: BaseImage.h:1413
HashImage & operator/=(ScalarType)
Divide by scalar.
Definition: HashImage.hxx:808
BinaryImage * _mask
Foreground mask.
Definition: BaseImage.h:111
virtual void ReflectZ(bool modify_axes=false)
Reflect image along z.
Definition: HashImage.hxx:1074
void PutBackgroundValueAsDouble(double)
Put background value.
Definition: BaseImage.h:1394
static ImageWriter * New(const char *)
virtual void SwapYT(bool modify_axes=true)
Swap y and t axis.
Definition: HashImage.hxx:1185
void CopyFrom(const BaseImage &)
Copy image data from other image of same size.
Definition: HashImage.hxx:238
const ImageAttributes & Attributes() const
Gets the image attributes.
Definition: BaseImage.h:856
~HashImage()
Destructor.
Definition: HashImage.hxx:164
void Put(int, VoxelType)
Function for pixel put access.
Definition: HashImage.h:483
void PutAttributes(const ImageAttributes &)
Puts attributes of image.
virtual void FlipYT(bool modify_origin=false)
Flip y and t axis, always also swaps voxel size.
Definition: HashImage.hxx:1142
HashImage operator+(const HashImage &) const
Add images.
Definition: HashImage.hxx:826
void Put(int, VoxelType)
Function for pixel put access.
Definition: GenericImage.h:545
HashImage operator*(const HashImage &) const
Multiply images voxel-wise.
Definition: HashImage.hxx:844
BaseImage()
Default constructor.
void PutMinMax(VoxelType, VoxelType)
Linearly rescale intensities.
Definition: HashImage.hxx:1000
double _torigin
Image t-origin (in ms)
virtual void FlipZT(bool modify_origin=false)
Flip z and t axis, always also swaps voxel size.
Definition: HashImage.hxx:1149
int _y
Image y-dimension (in voxels)
virtual void GetAsVector(Vector &, int) const
Function for pixel get access as double.
Definition: BaseImage.h:1321
void Clear()
Clear an image.
Definition: HashImage.hxx:171
HashImage GetFrame(int, int=-1) const
Get time instance (i.e., frame) or channel of image.
Definition: HashImage.hxx:648
const ImageAttributes & GetImageAttributes() const
Definition: BaseImage.h:1735
virtual void ReflectX(bool modify_axes=false)
Reflect image along x.
Definition: HashImage.hxx:1032
BinaryImage * GetMask(bool=false)
Get foreground mask (optionally, take over ownership)
Definition: BaseImage.h:1369
double _xorigin
Image x-origin (in mm)
double _bg
Background value - may also be NaN for floating point images.
Definition: BaseImage.h:123
bool IsForeground(int) const
Whether voxel is within foreground without index-out-of-bounds check.
Definition: BaseImage.h:1455
void PutOrigin(const Point &)
Image origin put access.
Definition: BaseImage.h:1025
HashImage & operator*=(ScalarType)
Multiply by scalar.
Definition: HashImage.hxx:791
virtual void SwapYZ(bool modify_axes=true)
Swap y and z axis.
Definition: HashImage.hxx:1171
virtual void FlipXY(bool modify_origin=false)
Flip x and y axis, always also swaps voxel size.
Definition: HashImage.hxx:1114
virtual void SwapXT(bool modify_axes=true)
Swap x and t axis.
Definition: HashImage.hxx:1178
HashImage operator/(const HashImage &) const
Divide images voxel-wise.
Definition: HashImage.hxx:853
void Delete(Type *&p)
Delete object.
Definition: Deallocate.h:28
ImageAttributes _attr
Image attributes.
Definition: BaseImage.h:99
HashImage()
Default constructor.
Definition: HashImage.hxx:70
void AllocateImage()
Allocate image memory.
Definition: HashImage.hxx:59
VoxelType Get(int) const
Function for pixel get access.
Definition: HashImage.h:550
void GetMinMax(VoxelType &, VoxelType &) const
Minimum and maximum pixel values get accessor.
Definition: HashImage.hxx:949
virtual void SwapXZ(bool modify_axes=true)
Swap x and z axis.
Definition: HashImage.hxx:1164
Definition: IOConfig.h:41
virtual void FlipXT(bool modify_origin=false)
Flip x and t axis, always also swaps voxel size.
Definition: HashImage.hxx:1135
void ImageToWorld(double &, double &) const
Image to world coordinate conversion with two doubles.
Definition: BaseImage.h:1180
int _z
Image z-dimension (in voxels)
double _dz
Voxel z-dimensions (in mm)
HashImage & operator-=(ScalarType)
Subtract scalar.
Definition: HashImage.hxx:778
bool OwnsMask() const
Definition: BaseImage.h:1388
virtual void Read(const char *)
Read image from file.
Definition: HashImage.hxx:1247
int _t
Image t-dimension (in voxels)
virtual void ReflectY(bool modify_axes=false)
Reflect image along y.
Definition: HashImage.hxx:1053
void UpdateMatrix()
Update coordinate transformation.
double _zorigin
Image z-origin (in mm)
virtual void FlipXZ(bool modify_origin=false)
Flip x and z axis, always also swaps voxel size.
Definition: HashImage.hxx:1121
HashImage GetRegion(int, int) const
Get image consisting of specified 2D slice.
Definition: HashImage.hxx:441
virtual void FlipYZ(bool modify_origin=false)
Flip y and z axis, always also swaps voxel size.
Definition: HashImage.hxx:1128
double ImageToTime(double) const
Image to time coordinate conversion.
Definition: BaseImage.h:1256
bool operator==(const HashImage< TVoxel2 > &) const
double VoxelType
Definition: BaseImage.h:770
double _zaxis[3]
Direction of z-axis.
HashImage & operator+=(ScalarType)
Add scalar.
Definition: HashImage.hxx:765
void Throw(ErrorType err, const char *func, Args... args) const
Definition: Object.h:166
double _yorigin
Image y-origin (in mm)
GenericImage< BinaryPixel > BinaryImage
Binary image as used for masks (0: off, otherwise: on)
Definition: BaseImage.h:52
double _dy
Voxel y-dimensions (in mm)
void CopyTo(GenericImage< TVoxel2 > &) const
Copy image data to GenericImage.
virtual void ReflectT(bool modify_axes=false)
Reflect image along t.
Definition: HashImage.hxx:1095
virtual void PutBackgroundValueAsDouble(double, bool)
Put background value.
Definition: HashImage.hxx:902
string Extension(const char *, ExtensionMode=EXT_Default)
Get file name extension in lower case incl. leading dot (&#39;.&#39;)
virtual void Initialize()
Initialize a previously allocated image.
Definition: HashImage.hxx:191
virtual void SwapZT(bool modify_axes=true)
Swap z and t axis.
Definition: HashImage.hxx:1192
VoxelType Get(int) const
Function for pixel get access.
Definition: GenericImage.h:573
virtual void Initialize()
Initialize a previously allocated image.
HashImage & operator=(VoxelType)
Assign constant value to each voxel.
Definition: HashImage.hxx:324
virtual void SwapXY(bool modify_axes=true)
Swap x and y axis.
Definition: HashImage.hxx:1157
int _x
Image x-dimension (in voxels)
bool _bgSet
Whether a background value was set.
Definition: BaseImage.h:126
HashImage operator-(const HashImage &) const
Subtract images.
Definition: HashImage.hxx:835
TVoxel VoxelType
Voxel type.
Definition: HashImage.h:49
double _dx
Voxel x-dimensions (in mm)
virtual void Write(const char *) const
Write image to file.
Definition: HashImage.hxx:1267
virtual BaseImage * Copy() const
Create copy of this image.
Definition: HashImage.hxx:185
double _yaxis[3]
Direction of y-axis.