1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 /*=========================================================================
19  *
20  *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
21  *
22  *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
23  *
24  *  For complete copyright, license and disclaimer of warranty information
25  *  please refer to the NOTICE file at the top of the ITK source tree.
26  *
27  *=========================================================================*/
28 #ifndef itkImageBase_hxx
29 #define itkImageBase_hxx
30 
31 #include "itkImageBase.h"
32 
33 #include <mutex>
34 #include "itkProcessObject.h"
35 #include "itkSpatialOrientation.h"
36 #include <cstring>
37 #include "itkMath.h"
38 
39 namespace itk
40 {
41 
42 template< unsigned int VImageDimension >
43 ImageBase< VImageDimension >
ImageBase()44 ::ImageBase()
45 :
46 m_OffsetTable{}
47 {
48   m_Spacing.Fill(1.0);
49   m_Origin.Fill(0.0);
50   m_Direction.SetIdentity();
51   m_InverseDirection.SetIdentity();
52   m_IndexToPhysicalPoint.SetIdentity();
53   m_PhysicalPointToIndex.SetIdentity();
54 }
55 
56 
57 template< unsigned int VImageDimension >
58 void
59 ImageBase< VImageDimension >
Allocate(bool)60 ::Allocate(bool)
61 {
62 }
63 
64 
65 template< unsigned int VImageDimension >
66 void
67 ImageBase< VImageDimension >
Initialize()68 ::Initialize()
69 {
70   //
71   // We don't modify ourselves because the "ReleaseData" methods depend upon
72   // no modification when initialized. Otherwise BUG: 8490 will
73   // reoccur.
74   //
75   // DO NOT CALL ANY METHODS WHICH MODIFY OURSELVES
76 
77   // Call the superclass which should initialize the BufferedRegion ivar.
78   Superclass::Initialize();
79 
80   // Clear the offset table
81   memset(m_OffsetTable, 0, sizeof(m_OffsetTable));
82 
83   // Clear the BufferedRegion ivar
84   this->InitializeBufferedRegion();
85 }
86 
87 template< unsigned int VImageDimension >
88 void
89 ImageBase< VImageDimension >
SetSpacing(const SpacingType & spacing)90 ::SetSpacing(const SpacingType & spacing)
91 {
92   for ( unsigned int i = 0; i < VImageDimension; i++ )
93     {
94     if ( this->m_Spacing[i] < 0.0 )
95       {
96 #if ! defined ( ITK_LEGACY_REMOVE )
97       itkWarningMacro("Negative spacing is not supported and may result in undefined behavior. Spacing is " << this->m_Spacing);
98       break;
99 #else
100       itkExceptionMacro("Negative spacing is not allowed: Spacing is " << this->m_Spacing);
101 #endif
102       }
103     }
104 
105   itkDebugMacro("setting Spacing to " << spacing);
106   if ( this->m_Spacing != spacing )
107     {
108     this->m_Spacing = spacing;
109     this->ComputeIndexToPhysicalPointMatrices();
110     this->Modified();
111     }
112 }
113 
114 
115 template< unsigned int VImageDimension >
116 void
117 ImageBase< VImageDimension >
SetSpacing(const double spacing[VImageDimension])118 ::SetSpacing(const double spacing[VImageDimension])
119 {
120   this->InternalSetSpacing(spacing);
121 }
122 
123 
124 template< unsigned int VImageDimension >
125 void
126 ImageBase< VImageDimension >
SetSpacing(const float spacing[VImageDimension])127 ::SetSpacing(const float spacing[VImageDimension])
128 {
129   this->InternalSetSpacing(spacing);
130 }
131 
132 
133 template< unsigned int VImageDimension >
134 void
135 ImageBase< VImageDimension >
SetOrigin(const double origin[VImageDimension])136 ::SetOrigin(const double origin[VImageDimension])
137 {
138   PointType p(origin);
139 
140   this->SetOrigin(p);
141 }
142 
143 
144 template< unsigned int VImageDimension >
145 void
146 ImageBase< VImageDimension >
SetOrigin(const float origin[VImageDimension])147 ::SetOrigin(const float origin[VImageDimension])
148 {
149   Point< float, VImageDimension > of(origin);
150   PointType                       p;
151   p.CastFrom(of);
152   this->SetOrigin(p);
153 }
154 
155 
156 template< unsigned int VImageDimension >
157 void
158 ImageBase< VImageDimension >
SetDirection(const DirectionType & direction)159 ::SetDirection(const DirectionType & direction)
160 {
161   bool modified = false;
162 
163   for ( unsigned int r = 0; r < VImageDimension; r++ )
164     {
165     for ( unsigned int c = 0; c < VImageDimension; c++ )
166       {
167       if ( Math::NotExactlyEquals(m_Direction[r][c], direction[r][c]) )
168         {
169         m_Direction[r][c] = direction[r][c];
170         modified = true;
171         }
172       }
173     }
174 
175   if ( modified )
176     {
177     this->ComputeIndexToPhysicalPointMatrices();
178     this->m_InverseDirection = m_Direction.GetInverse();
179     }
180 }
181 
182 
183 template< unsigned int VImageDimension >
184 void
185 ImageBase< VImageDimension >
ComputeIndexToPhysicalPointMatrices()186 ::ComputeIndexToPhysicalPointMatrices()
187 {
188   DirectionType scale;
189 
190   for ( unsigned int i = 0; i < VImageDimension; i++ )
191     {
192     if ( this->m_Spacing[i] == 0.0 )
193       {
194       itkExceptionMacro("A spacing of 0 is not allowed: Spacing is " << this->m_Spacing);
195       }
196     scale[i][i] = this->m_Spacing[i];
197     }
198 
199   if ( vnl_determinant( this->m_Direction.GetVnlMatrix() ) == 0.0 )
200     {
201     itkExceptionMacro(<< "Bad direction, determinant is 0. Direction is " << this->m_Direction);
202     }
203 
204   this->m_IndexToPhysicalPoint = this->m_Direction * scale;
205   this->m_PhysicalPointToIndex = m_IndexToPhysicalPoint.GetInverse();
206 
207   this->Modified();
208 }
209 
210 
211 template< unsigned int VImageDimension >
212 void
213 ImageBase< VImageDimension >
ComputeOffsetTable()214 ::ComputeOffsetTable()
215 {
216   // vxl_uint_64 num=1;
217   OffsetValueType  num = 1;
218   const SizeType & bufferSize = this->GetBufferedRegion().GetSize();
219 
220   // m_OffsetTable[0] = (OffsetValueType)num;
221   m_OffsetTable[0] = num;
222   for ( unsigned int i = 0; i < VImageDimension; i++ )
223     {
224     num *= bufferSize[i];
225     // m_OffsetTable[i+1] = (OffsetValueType)num;
226     m_OffsetTable[i + 1] = num;
227     }
228   // if( num > NumericTraits<SizeValueType>::max() )
229   //   {
230   //   itkExceptionMacro(<< "Requested number of pixels (" << num
231   //     << ") is greater than the largest possible number of pixels (" <<
232   // NumericTraits<SizeValueType>::max() << ").");
233   //   }
234 }
235 
236 
237 template< unsigned int VImageDimension >
238 void
239 ImageBase< VImageDimension >
UpdateOutputInformation()240 ::UpdateOutputInformation()
241 {
242   if ( this->GetSource() )
243     {
244     this->GetSource()->UpdateOutputInformation();
245     }
246   else
247     {
248     // If we don't have a source, we should set our Image to span our
249     // buffer (by setting our LargestPossibleRegion to equal our
250     // BufferedRegion). However, if the buffer is empty, we leave the
251     // LargestPossibleRegion at its prior value.  This allows InPlace
252     // filters to overwrite their inputs safely (taking ownership of
253     // the pixel buffers), yet respond to subsequent requests for
254     // information.
255     if ( this->GetBufferedRegion().GetNumberOfPixels() > 0 )
256       {
257       this->SetLargestPossibleRegion( this->GetBufferedRegion() );
258       }
259     }
260 
261   // Now we should know what our largest possible region is. If our
262   // requested region was not set yet, (or has been set to something
263   // invalid - with no data in it ) then set it to the largest possible
264   // region.
265   if ( this->GetRequestedRegion().GetNumberOfPixels() == 0 )
266     {
267     this->SetRequestedRegionToLargestPossibleRegion();
268     }
269 }
270 
271 
272 template< unsigned int VImageDimension >
273 void
274 ImageBase< VImageDimension >
UpdateOutputData()275 ::UpdateOutputData()
276 {
277   // If the requested region does not contain any pixels then there is
278   // no reason to Update the output data. This is needed so that
279   // filters don't need to update all inputs. This occours in
280   // ImageBase as  oppose to DataObject, but cause this statement
281   // requires the specific GetNumberOfPixels methods ( as oppose to a
282   // generic Region::IsEmpty method ).
283   //
284   // Also note, the check of the largest possible region is needed so
285   // that an exception will be thrown in the process object when no
286   // input has been set. ( This part of the statement could be removed
287   // if this check happened earlier in the pipeline )
288   if ( this->GetRequestedRegion().GetNumberOfPixels() > 0
289        || this->GetLargestPossibleRegion().GetNumberOfPixels() == 0 )
290     {
291     this->Superclass::UpdateOutputData();
292     }
293 }
294 
295 
296 template< unsigned int VImageDimension >
297 void
298 ImageBase< VImageDimension >
SetRequestedRegionToLargestPossibleRegion()299 ::SetRequestedRegionToLargestPossibleRegion()
300 {
301   this->SetRequestedRegion( this->GetLargestPossibleRegion() );
302 }
303 
304 
305 template< unsigned int VImageDimension >
306 void
307 ImageBase< VImageDimension >
CopyInformation(const DataObject * data)308 ::CopyInformation(const DataObject *data)
309 {
310   // Standard call to the superclass' method
311   Superclass::CopyInformation(data);
312 
313   if ( data )
314     {
315     // Attempt to cast data to an ImageBase
316     const auto * const imgData = dynamic_cast< const ImageBase< VImageDimension > * >( data );
317 
318     if ( imgData != nullptr )
319       {
320       // Copy the meta data for this data type
321       this->SetLargestPossibleRegion( imgData->GetLargestPossibleRegion() );
322       this->SetSpacing( imgData->GetSpacing() );
323       this->SetOrigin( imgData->GetOrigin() );
324       this->SetDirection( imgData->GetDirection() );
325       this->SetNumberOfComponentsPerPixel(
326         imgData->GetNumberOfComponentsPerPixel() );
327       }
328     else
329       {
330       // pointer could not be cast back down
331       itkExceptionMacro( << "itk::ImageBase::CopyInformation() cannot cast "
332                          << typeid( data ).name() << " to "
333                          << typeid( const ImageBase * ).name() );
334       }
335     }
336 }
337 
338 
339 template< unsigned int VImageDimension >
340 void
341 ImageBase< VImageDimension >
Graft(const Self * image)342 ::Graft(const Self *image)
343 {
344   if ( !image )
345     {
346     return;
347     }
348 
349   // Copy the meta-information
350   this->CopyInformation(image);
351 
352   // Copy the remaining region information. Subclasses are
353   // responsible for copying the pixel container.
354   this->SetBufferedRegion( image->GetBufferedRegion() );
355   this->SetRequestedRegion( image->GetRequestedRegion() );
356 }
357 
358 
359 template< unsigned int VImageDimension >
360 void
361 ImageBase< VImageDimension >
Graft(const DataObject * data)362 ::Graft(const DataObject *data)
363 {
364   using ImageBaseType = ImageBase< VImageDimension >;
365 
366   const auto * image = dynamic_cast< const ImageBaseType * >( data );
367 
368   if ( !image )
369     {
370     return;
371     }
372 
373   // Call Graft() with image input to actually perform the graft operation
374   this->Graft(image);
375 }
376 
377 
378 template< unsigned int VImageDimension >
379 bool
380 ImageBase< VImageDimension >
RequestedRegionIsOutsideOfTheBufferedRegion()381 ::RequestedRegionIsOutsideOfTheBufferedRegion()
382 {
383   unsigned int      i;
384   const IndexType & requestedRegionIndex = this->GetRequestedRegion().GetIndex();
385   const IndexType & bufferedRegionIndex = this->GetBufferedRegion().GetIndex();
386 
387   const SizeType & requestedRegionSize = this->GetRequestedRegion().GetSize();
388   const SizeType & bufferedRegionSize = this->GetBufferedRegion().GetSize();
389 
390   for ( i = 0; i < VImageDimension; i++ )
391     {
392     if ( ( requestedRegionIndex[i] < bufferedRegionIndex[i] )
393          || ( ( requestedRegionIndex[i] + static_cast< OffsetValueType >( requestedRegionSize[i] ) )
394               > ( bufferedRegionIndex[i] + static_cast< OffsetValueType >( bufferedRegionSize[i] ) ) ) )
395       {
396       return true;
397       }
398     }
399 
400   return false;
401 }
402 
403 
404 template< unsigned int VImageDimension >
405 bool
406 ImageBase< VImageDimension >
VerifyRequestedRegion()407 ::VerifyRequestedRegion()
408 {
409   bool         retval = true;
410   unsigned int i;
411 
412   // Is the requested region within the LargestPossibleRegion?
413   // Note that the test is indeed against the largest possible region
414   // rather than the buffered region; see DataObject::VerifyRequestedRegion.
415   const IndexType & requestedRegionIndex = this->GetRequestedRegion().GetIndex();
416   const IndexType & largestPossibleRegionIndex =
417     this->GetLargestPossibleRegion().GetIndex();
418 
419   const SizeType & requestedRegionSize = this->GetRequestedRegion().GetSize();
420   const SizeType & largestPossibleRegionSize =
421     this->GetLargestPossibleRegion().GetSize();
422 
423   for ( i = 0; i < VImageDimension; i++ )
424     {
425     if ( ( requestedRegionIndex[i] < largestPossibleRegionIndex[i] )
426          || ( ( requestedRegionIndex[i] + static_cast< OffsetValueType >( requestedRegionSize[i] ) )
427               > ( largestPossibleRegionIndex[i] + static_cast< OffsetValueType >( largestPossibleRegionSize[i] ) ) ) )
428       {
429       retval = false;
430       }
431     }
432 
433   return retval;
434 }
435 
436 
437 template< unsigned int VImageDimension >
438 void
439 ImageBase< VImageDimension >
SetBufferedRegion(const RegionType & region)440 ::SetBufferedRegion(const RegionType & region)
441 {
442   if ( m_BufferedRegion != region )
443     {
444     m_BufferedRegion = region;
445     this->ComputeOffsetTable();
446     this->Modified();
447     }
448 }
449 
450 
451 template< unsigned int VImageDimension >
452 void
453 ImageBase< VImageDimension >
InitializeBufferedRegion()454 ::InitializeBufferedRegion()
455 {
456   //
457   // We don't modify ourselves because the "ReleaseData" methods depend upon
458   // no modification when initialized.
459   //
460   // Otherwise BUG: 8490 will reoccur
461 
462   m_BufferedRegion = RegionType();
463   this->ComputeOffsetTable();
464 }
465 
466 
467 template< unsigned int VImageDimension >
468 void
469 ImageBase< VImageDimension >
SetRequestedRegion(const RegionType & region)470 ::SetRequestedRegion(const RegionType & region)
471 {
472   m_RequestedRegion = region;
473 }
474 
475 
476 template< unsigned int VImageDimension >
477 void
478 ImageBase< VImageDimension >
SetRequestedRegion(const DataObject * data)479 ::SetRequestedRegion( const DataObject *data )
480 {
481   const auto * const imgData = dynamic_cast< const ImageBase * >( data );
482 
483   if ( imgData != nullptr )
484     {
485     // only copy the RequestedRegion if the parameter object is an image
486     this->SetRequestedRegion( imgData->GetRequestedRegion() );
487     }
488 }
489 
490 
491 template< unsigned int VImageDimension >
492 void
493 ImageBase< VImageDimension >
SetLargestPossibleRegion(const RegionType & region)494 ::SetLargestPossibleRegion(const RegionType & region)
495 {
496   if ( m_LargestPossibleRegion != region )
497     {
498     m_LargestPossibleRegion = region;
499     this->Modified();
500     }
501 }
502 
503 
504 template< unsigned int VImageDimension >
505 unsigned int
506 ImageBase< VImageDimension >
GetNumberOfComponentsPerPixel() const507 ::GetNumberOfComponentsPerPixel() const
508 {
509   // Returns the number of components in the image.
510   // base implementation defaults to 1
511   return 1;
512 }
513 
514 
515 template< unsigned int VImageDimension >
516 void
517 ImageBase< VImageDimension >
SetNumberOfComponentsPerPixel(unsigned int)518 ::SetNumberOfComponentsPerPixel(unsigned int)
519 {
520   // does nothing (always 1)
521 }
522 
523 
524 template< unsigned int VImageDimension >
525 void
526 ImageBase< VImageDimension >
PrintSelf(std::ostream & os,Indent indent) const527 ::PrintSelf(std::ostream & os, Indent indent) const
528 {
529   Superclass::PrintSelf(os, indent);
530 
531   os << indent << "LargestPossibleRegion: " << std::endl;
532   this->GetLargestPossibleRegion().PrintSelf( os, indent.GetNextIndent() );
533 
534   os << indent << "BufferedRegion: " << std::endl;
535   this->GetBufferedRegion().PrintSelf( os, indent.GetNextIndent() );
536 
537   os << indent << "RequestedRegion: " << std::endl;
538   this->GetRequestedRegion().PrintSelf( os, indent.GetNextIndent() );
539 
540   os << indent << "Spacing: " << this->GetSpacing() << std::endl;
541 
542   os << indent << "Origin: " << this->GetOrigin() << std::endl;
543 
544   os << indent << "Direction: " << std::endl << this->GetDirection() << std::endl;
545 
546   os << indent << "IndexToPointMatrix: " << std::endl;
547   os << this->m_IndexToPhysicalPoint << std::endl;
548 
549   os << indent << "PointToIndexMatrix: " << std::endl;
550   os << this->m_PhysicalPointToIndex << std::endl;
551 
552   os << indent << "Inverse Direction: " << std::endl;
553   os << this->GetInverseDirection() << std::endl;
554 }
555 
556 } // end namespace itk
557 
558 #endif
559