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 itkImageRegion_h 29 #define itkImageRegion_h 30 31 #include "itkRegion.h" 32 33 #include "itkSize.h" 34 #include "itkContinuousIndex.h" 35 #include "itkMath.h" 36 37 namespace itk 38 { 39 // Forward declaration of ImageBase so it can be declared a friend 40 // (needed for PrintSelf mechanism) 41 template< unsigned int VImageDimension > 42 class ITK_TEMPLATE_EXPORT ImageBase; 43 44 /** \class ImageRegion 45 * \brief An image region represents a structured region of data. 46 * 47 * ImageRegion is an class that represents some structured portion or 48 * piece of an Image. The ImageRegion is represented with an index and 49 * a size in each of the n-dimensions of the image. (The index is the 50 * corner of the image, the size is the lengths of the image in each of 51 * the topological directions.) 52 * 53 * \sa Region 54 * \sa Index 55 * \sa Size 56 * \sa MeshRegion 57 * 58 * \ingroup ImageObjects 59 * \ingroup ITKCommon 60 * 61 * \wiki 62 * \wikiexample{Images/ImageRegion,An object which holds the index (start) and size of a region of an image} 63 * \wikiexample{SimpleOperations/RegionIntersection,Determine if one region is fully inside another region} 64 * \wikiexample{SimpleOperations/PixelInsideRegion,Determine if a pixel is inside of a region} 65 * \wikiexample{SimpleOperations/RegionOverlap,Determine the overlap of two regions} 66 * \endwiki 67 */ 68 template< unsigned int VImageDimension > 69 class ITK_TEMPLATE_EXPORT ImageRegion final: public Region 70 { 71 public: 72 /** Standard class type aliases. */ 73 using Self = ImageRegion; 74 using Superclass = Region; 75 76 /** Standard part of all itk objects. */ 77 itkTypeMacro(ImageRegion, Region); 78 79 /** Dimension of the image available at compile time. */ 80 static constexpr unsigned int ImageDimension = VImageDimension; 81 82 /** Dimension one lower than the image unless the image is one dimensional 83 in which case the SliceDimension is also one dimensional. */ 84 static constexpr unsigned int SliceDimension = ImageDimension - ( ImageDimension > 1 ); 85 86 /** Dimension of the image available at run time. */ GetImageDimension()87 static unsigned int GetImageDimension() 88 { return ImageDimension; } 89 90 /** Index type alias support An index is used to access pixel values. */ 91 using IndexType = Index< Self::ImageDimension >; 92 using IndexValueType = typename IndexType::IndexValueType; 93 using OffsetType = typename IndexType::OffsetType; 94 using OffsetValueType = typename OffsetType::OffsetValueType; 95 typedef IndexValueType IndexValueArrayType[ImageDimension]; 96 typedef OffsetValueType OffsetTableType[ImageDimension+1]; 97 98 /** Size type alias support A size is used to define region bounds. */ 99 using SizeType = Size< Self::ImageDimension >; 100 using SizeValueType = typename SizeType::SizeValueType; 101 102 /** Slice region type alias. SliceRegion is one dimension less than Self. */ 103 using SliceRegion = ImageRegion< Self::SliceDimension >; 104 105 /** Return the region type. Images are described with structured regions. */ GetRegionType()106 typename Superclass::RegionType GetRegionType() const override 107 { return Superclass::ITK_STRUCTURED_REGION; } 108 109 /** Constructor. ImageRegion is a lightweight object that is not reference 110 * counted, so the constructor is public. Its two data members are filled 111 * with zeros (using C++11 default member initializers). */ 112 ImageRegion() ITK_NOEXCEPT = default; 113 114 /** Destructor. ImageRegion is a lightweight object that is not reference 115 * counted, so the destructor is public. */ 116 ~ImageRegion() override = default; 117 118 /** Copy constructor. ImageRegion is a lightweight object that is not 119 * reference counted, so the copy constructor is public. */ 120 ImageRegion(const Self & ) ITK_NOEXCEPT = default; 121 122 /** Constructor that takes an index and size. ImageRegion is a lightweight 123 * object that is not reference counted, so this constructor is public. */ ImageRegion(const IndexType & index,const SizeType & size)124 ImageRegion(const IndexType & index, const SizeType & size) ITK_NOEXCEPT 125 : 126 // Note: Use parentheses instead of curly braces to initialize data members, 127 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..." 128 m_Index(index), 129 m_Size(size) 130 { 131 } 132 133 /** Constructor that takes a size and assumes an index of zeros. ImageRegion 134 * is lightweight object that is not reference counted so this constructor 135 * is public. */ ImageRegion(const SizeType & size)136 ImageRegion(const SizeType & size) ITK_NOEXCEPT 137 : 138 m_Size(size) 139 { 140 // Note: m_Index is initialized by its C++11 default member initializer. 141 } 142 143 /** operator=. ImageRegion is a lightweight object that is not reference 144 * counted, so operator= is public. */ 145 Self& operator=(const Self & ) ITK_NOEXCEPT = default; 146 147 /** Set the index defining the corner of the region. */ SetIndex(const IndexType & index)148 void SetIndex(const IndexType & index) 149 { m_Index = index; } 150 151 /** Get index defining the corner of the region. */ GetIndex()152 const IndexType & GetIndex() const { return m_Index; } GetModifiableIndex()153 IndexType & GetModifiableIndex() { return m_Index; } 154 155 /** Set the size of the region. This plus the index determines the 156 * rectangular shape, or extent, of the region. */ SetSize(const SizeType & size)157 void SetSize(const SizeType & size) 158 { m_Size = size; } 159 160 /** Get the size of the region. */ GetSize()161 const SizeType & GetSize() const { return m_Size; } GetModifiableSize()162 SizeType & GetModifiableSize() { return m_Size; } 163 164 /** Convenience methods to get and set the size of the particular dimension i. 165 */ SetSize(unsigned int i,SizeValueType sze)166 void SetSize(unsigned int i, SizeValueType sze) 167 { m_Size[i] = sze; } GetSize(unsigned int i)168 SizeValueType GetSize(unsigned int i) const 169 { return m_Size[i]; } 170 171 /** Convenience methods to get and set the index of the particular dimension 172 i. */ SetIndex(unsigned int i,IndexValueType sze)173 void SetIndex(unsigned int i, IndexValueType sze) 174 { m_Index[i] = sze; } GetIndex(unsigned int i)175 IndexValueType GetIndex(unsigned int i) const 176 { return m_Index[i]; } 177 178 /** Get index defining the upper corner of the region. */ 179 IndexType GetUpperIndex() const; 180 181 /** Modify the Size of the ImageRegion so that the provided index will be the upper corner index. */ 182 void SetUpperIndex( const IndexType & idx ); 183 184 /** Compute an offset table based on the Size. */ 185 void ComputeOffsetTable(OffsetTableType offsetTable) const; 186 187 /** Compare two regions. */ 188 bool 189 operator==(const Self & region) const ITK_NOEXCEPT 190 { 191 return (m_Index == region.m_Index) && (m_Size == region.m_Size); 192 } 193 194 /** Compare two regions. */ 195 bool 196 operator!=(const Self & region) const ITK_NOEXCEPT 197 { 198 return !(*this == region); 199 } 200 201 /** Test if an index is inside */ 202 bool IsInside(const IndexType & index)203 IsInside(const IndexType & index) const 204 { 205 for ( unsigned int i = 0; i < ImageDimension; i++ ) 206 { 207 if ( index[i] < m_Index[i] ) 208 { 209 return false; 210 } 211 if ( index[i] >= ( m_Index[i] + static_cast< IndexValueType >( m_Size[i] ) ) ) 212 { 213 return false; 214 } 215 } 216 return true; 217 } 218 219 /** Test if a continuous index is inside the region. 220 * We take into account the fact that each voxel has its 221 * center at the integer coordinate and extends half way 222 * to the next integer coordinate. */ 223 template< typename TCoordRepType > 224 bool IsInside(const ContinuousIndex<TCoordRepType,VImageDimension> & index)225 IsInside(const ContinuousIndex< TCoordRepType, VImageDimension > & index) const 226 { 227 for ( unsigned int i = 0; i < ImageDimension; i++ ) 228 { 229 if ( Math::RoundHalfIntegerUp< IndexValueType >(index[i]) < static_cast< IndexValueType >( m_Index[i] ) ) 230 { 231 return false; 232 } 233 // bound is the last valid pixel location 234 const auto bound = static_cast< TCoordRepType >( 235 m_Index[i] + m_Size[i] - 0.5 ); 236 237 /* Note for NaN: test using negation of a positive test in order 238 * to always evaluate to true (and thus return false) when index[i] 239 * is NaN. The cast above to integer via RoundHalfIntegerUp will cast 240 * NaN into a platform-dependent value (large negative, -1 or large 241 * positive, empirically). Thus this test here is relied on 242 * to 'catch' NaN's. */ 243 if ( ! (index[i] <= bound) ) 244 { 245 return false; 246 } 247 } 248 return true; 249 } 250 251 /** Test if a region (the argument) is completely inside of this region. If 252 * the region that is passed as argument to this method, has a size of value 253 * zero, then it will not be considered to be inside of the current region, 254 * even its starting index is inside. */ 255 bool IsInside(const Self & region)256 IsInside(const Self & region) const 257 { 258 IndexType beginCorner = region.GetIndex(); 259 260 if ( !this->IsInside(beginCorner) ) 261 { 262 return false; 263 } 264 IndexType endCorner; 265 const SizeType & size = region.GetSize(); 266 for ( unsigned int i = 0; i < ImageDimension; i++ ) 267 { 268 endCorner[i] = beginCorner[i] + static_cast< OffsetValueType >( size[i] ) - 1; 269 } 270 if ( !this->IsInside(endCorner) ) 271 { 272 return false; 273 } 274 return true; 275 } 276 277 /** Get the number of pixels contained in this region. This just 278 * multiplies the size components. */ 279 SizeValueType GetNumberOfPixels() const; 280 281 /** Pad an image region by the specified radius. Region can be padded 282 * uniformly in all dimensions or can be padded by different amounts 283 * in each dimension. */ 284 void PadByRadius(OffsetValueType radius); 285 286 void PadByRadius(const IndexValueArrayType radius); 287 288 void PadByRadius(const SizeType & radius); 289 290 /** Shrink an image region by the specified radius. The region can be shrunk 291 * uniformly in all dimension or can be shink by different amounts in each 292 * direction. If the shink operation fails because the radius is too large, 293 * this method returns false. */ 294 bool ShrinkByRadius(OffsetValueType radius); 295 296 bool ShrinkByRadius(const IndexValueArrayType radius); 297 298 bool ShrinkByRadius(const SizeType & radius); 299 300 /** Crop a region by another region. If this region is outside of the 301 * crop, this method returns false and does not modify the 302 * region. Otherwise, this method returns true and the region is 303 * modified to reflect the crop. */ 304 bool Crop(const Self & region); 305 306 /** Slice a region, producing a region that is one dimension lower 307 * than the current region. Parameter "dim" specifies which dimension 308 * to remove. */ 309 SliceRegion Slice(const unsigned int dim) const; 310 311 protected: 312 /** Methods invoked by Print() to print information about the object 313 * including superclasses. Typically not called by the user (use Print() 314 * instead) but used in the hierarchical print process to combine the 315 * output of several classes. */ 316 void PrintSelf(std::ostream & os, Indent indent) const override; 317 318 private: 319 IndexType m_Index = {{0}}; 320 SizeType m_Size = {{0}}; 321 322 /** Friends of ImageRegion */ 323 friend class ImageBase< VImageDimension >; 324 }; 325 326 template< unsigned int VImageDimension > 327 std::ostream & operator<<(std::ostream & os, const ImageRegion< VImageDimension > & region); 328 } // end namespace itk 329 330 #ifndef ITK_MANUAL_INSTANTIATION 331 #include "itkImageRegion.hxx" 332 #endif 333 334 #endif 335