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 #ifndef itkConstantBoundaryImageNeighborhoodPixelAccessPolicy_h
20 #define itkConstantBoundaryImageNeighborhoodPixelAccessPolicy_h
21 
22 #include "itkIndex.h"
23 #include "itkOffset.h"
24 #include "itkSize.h"
25 
26 namespace itk
27 {
28 namespace Experimental
29 {
30 
31 /**
32  * \class ConstantBoundaryImageNeighborhoodPixelAccessPolicy
33  * ImageNeighborhoodPixelAccessPolicy class for ShapedImageNeighborhoodRange.
34  * Allows getting and setting the value of a pixel, located in a specified
35  * neighborhood location, at a specified offset. Uses a constant as value
36  * for pixels outside the image border.
37  *
38  * \see ShapedNeighborhoodIterator
39  * \see ConstantBoundaryCondition
40  * \ingroup ImageIterators
41  * \ingroup ITKCommon
42  */
43 template <typename TImage>
44 class ConstantBoundaryImageNeighborhoodPixelAccessPolicy final
45 {
46 private:
47   using NeighborhoodAccessorFunctorType = typename TImage::NeighborhoodAccessorFunctorType;
48   using PixelType = typename TImage::PixelType;
49   using InternalPixelType = typename TImage::InternalPixelType;
50 
51   using ImageDimensionType = typename TImage::ImageDimensionType;
52   static constexpr ImageDimensionType ImageDimension = TImage::ImageDimension;
53 
54   using IndexType = Index<ImageDimension>;
55   using OffsetType = Offset<ImageDimension>;
56   using ImageSizeType = Size<ImageDimension>;
57   using ImageSizeValueType = SizeValueType;
58 
59   // Index value to the image buffer, indexing the current pixel. -1 is used to indicate out-of-bounds.
60   const IndexValueType m_PixelIndexValue;
61 
62   // A reference to the accessor of the image.
63   const NeighborhoodAccessorFunctorType& m_NeighborhoodAccessor;
64 
65   // The constant whose value is returned a pixel value outside the image is queried.
66   const PixelType m_Constant;
67 
68 
69   // Private helper function. Tells whether the pixel at 'pixelIndex' is inside the image.
IsInside(const IndexType & pixelIndex,const ImageSizeType & imageSize)70   static bool IsInside(
71     const IndexType& pixelIndex,
72     const ImageSizeType& imageSize) ITK_NOEXCEPT
73   {
74     bool result = true;
75 
76     for (ImageDimensionType i = 0; i < ImageDimension; ++i)
77     {
78       const IndexValueType indexValue = pixelIndex[i];
79 
80       // Note: Do not 'quickly' break or return out of the for-loop when the
81       // result is false! For performance reasons (loop unrolling, etc.) it
82       // appears preferable to complete the for-loop iteration in this case!
83       result = result &&
84         (indexValue >= 0) &&
85         (static_cast<ImageSizeValueType>(indexValue) < imageSize[i]);
86     }
87     return result;
88   }
89 
90 
91   // Private helper function. Calculates and returns the index value of the
92   // current pixel within the image buffer.
CalculatePixelIndexValue(const OffsetType & offsetTable,const IndexType & pixelIndex)93   static IndexValueType CalculatePixelIndexValue(
94     const OffsetType& offsetTable,
95     const IndexType& pixelIndex) ITK_NOEXCEPT
96   {
97     IndexValueType result = 0;
98 
99     for (ImageDimensionType i = 0; i < ImageDimension; ++i)
100     {
101       result += pixelIndex[i] * offsetTable[i];
102     }
103     return result;
104   }
105 
106 public:
107   /** This type is necessary to tell the ShapedImageNeighborhoodRange that the
108    * constructor accepts a pixel value as (optional) extra parameter. */
109   using PixelAccessParameterType = PixelType;
110 
111   // Deleted member functions:
112   ConstantBoundaryImageNeighborhoodPixelAccessPolicy() = delete;
113   ConstantBoundaryImageNeighborhoodPixelAccessPolicy& operator=(const ConstantBoundaryImageNeighborhoodPixelAccessPolicy&) = delete;
114 
115   // Explicitly-defaulted functions:
116   ~ConstantBoundaryImageNeighborhoodPixelAccessPolicy() = default;
117   ConstantBoundaryImageNeighborhoodPixelAccessPolicy(
118     const ConstantBoundaryImageNeighborhoodPixelAccessPolicy&) = default;
119 
120   /** Constructor called directly by the pixel proxy of
121    * ShapedImageNeighborhoodRange. */
122   ConstantBoundaryImageNeighborhoodPixelAccessPolicy(
123     const ImageSizeType& imageSize,
124     const OffsetType& offsetTable,
125     const NeighborhoodAccessorFunctorType& neighborhoodAccessor,
126     const IndexType& pixelIndex,
127     const PixelType constant = {}) ITK_NOEXCEPT
128     :
129   m_PixelIndexValue
130   {
131     IsInside(pixelIndex, imageSize) ? CalculatePixelIndexValue(offsetTable, pixelIndex) : -1
132   },
133   m_NeighborhoodAccessor(neighborhoodAccessor),
134   m_Constant{constant}
135   {
136   }
137 
138 
139   /** Retrieves the pixel value from the image buffer, at the current
140    * index. When the index is out of bounds, it returns the constant
141    * value specified during construction. */
GetPixelValue(const InternalPixelType * const imageBufferPointer)142   PixelType GetPixelValue(const InternalPixelType* const imageBufferPointer) const ITK_NOEXCEPT
143   {
144     return (m_PixelIndexValue < 0) ?
145       m_Constant :
146       m_NeighborhoodAccessor.Get(imageBufferPointer + m_PixelIndexValue);
147   }
148 
149   /** Sets the value of the image buffer at the current index value to the
150    * specified value.  */
SetPixelValue(InternalPixelType * const imageBufferPointer,const PixelType & pixelValue)151   void SetPixelValue(InternalPixelType* const imageBufferPointer, const PixelType& pixelValue) const ITK_NOEXCEPT
152   {
153     if (m_PixelIndexValue >= 0)
154     {
155       m_NeighborhoodAccessor.Set(imageBufferPointer + m_PixelIndexValue, pixelValue);
156     }
157   }
158 };
159 
160 } // namespace Experimental
161 } // namespace itk
162 
163 #endif
164