ITK  6.0.0
Insight Toolkit
itkShapedImageNeighborhoodRange.h
Go to the documentation of this file.
1/*=========================================================================
2 *
3 * Copyright NumFOCUS
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 * https://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 itkShapedImageNeighborhoodRange_h
20#define itkShapedImageNeighborhoodRange_h
21
22#include <algorithm> // For copy_n.
23#include <cassert>
24#include <cstddef> // For ptrdiff_t.
25#include <iterator> // For random_access_iterator_tag.
26#include <limits>
27#include <type_traits> // For conditional and is_const.
28
29#include "itkIndex.h"
30#include "itkSize.h"
32
33namespace itk
34{
35
90template <typename TImage,
91 typename TImageNeighborhoodPixelAccessPolicy = ZeroFluxNeumannImageNeighborhoodPixelAccessPolicy<TImage>>
93{
94private:
95 // Empty struct, used internally to denote that there is no pixel access parameter specified.
97 {};
98
99
100 // Helper class to estimate whether the policy has nested type PixelAccessParameterType.
102 {
103 private:
104 // The Test function has two overloads whose return type is different.
105 // One of the overloads is only available for overload resolution when
106 // the policy T has a nested type PixelAccessParameterType (using SFINAE).
107
108 template <typename T>
109 static int
110 Test(typename T::PixelAccessParameterType *);
111
112 template <typename T>
113 static void
114 Test(...);
115
116 public:
117 // This constant tells whether the policy has a PixelAccessParameterType:
118 static constexpr bool HasPixelAccessParameterType =
119 !std::is_same_v<decltype(Test<TImageNeighborhoodPixelAccessPolicy>(nullptr)),
120 decltype(Test<TImageNeighborhoodPixelAccessPolicy>())>;
121 };
122
123
124 template <typename TPolicy, bool VPolicyHasPixelAccessParameterType = CheckPolicy::HasPixelAccessParameterType>
126 {
127 using Type = typename TPolicy::PixelAccessParameterType;
128 };
129
130 // Specialization for when the policy does not have PixelAccessParameterType.
131 template <typename TPolicy>
132 struct OptionalPixelAccessParameter<TPolicy, false>
133 {
135 };
136
137
138 using ImageType = TImage;
139 using ImageDimensionType = typename TImage::ImageDimensionType;
143 using PixelType = typename TImage::PixelType;
144 using InternalPixelType = typename TImage::InternalPixelType;
145 using NeighborhoodAccessorFunctorType = typename TImage::NeighborhoodAccessorFunctorType;
146 static constexpr ImageDimensionType ImageDimension = TImage::ImageDimension;
147 using IndexType = typename TImage::IndexType;
152
153
154 // PixelProxy: internal class that aims to act like a reference to a pixel:
155 // It acts either like 'PixelType &' or like 'const PixelType &', depending
156 // on its boolean template argument, VIsConst.
157 // The proxy retrieves the pixel value using a ImageNeighborhoodPixelAccessPolicy.
158 // Note: the extra TDummy argument aims to fix AppleClang 6.0.0.6000056 error
159 // "explicit specialization of 'PixelProxy'"and GCC 5.4.0 error "explicit
160 // specialization in non-namespace scope".
161 template <bool VIsConst, typename TDummy = void>
163 {};
164
165 // PixelProxy specialization for const pixel types:
166 // acts like 'const PixelType &'
167 template <typename TDummy>
168 class PixelProxy<true, TDummy> final
169 {
170 private:
171 // Pointer to the buffer of the image. Should not be null.
173
174 // Pixel access policy.
175 const TImageNeighborhoodPixelAccessPolicy m_PixelAccessPolicy;
176
177 public:
178 // Deleted member functions:
179 PixelProxy() = delete;
180 PixelProxy &
181 operator=(const PixelProxy &) = delete;
182
183 // Explicitly-defaulted member functions:
184 PixelProxy(const PixelProxy &) noexcept = default;
185 ~PixelProxy() = default;
186
187 // Constructor, called directly by operator*() of the iterator class.
188 PixelProxy(const InternalPixelType * const imageBufferPointer,
189 const TImageNeighborhoodPixelAccessPolicy & pixelAccessPolicy) noexcept
190 : m_ImageBufferPointer{ imageBufferPointer }
191 , m_PixelAccessPolicy{ pixelAccessPolicy }
192 {}
193
194 // Allows implicit conversion from non-const to const proxy.
195 PixelProxy(const PixelProxy<false> & pixelProxy) noexcept
196 : m_ImageBufferPointer{ pixelProxy.m_ImageBufferPointer }
197 , m_PixelAccessPolicy{ pixelProxy.m_PixelAccessPolicy }
198 {}
199
200 // Conversion operator.
201 operator PixelType() const noexcept { return m_PixelAccessPolicy.GetPixelValue(m_ImageBufferPointer); }
202 };
203
204
205 // PixelProxy specialization for non-const pixel types:
206 // acts like 'PixelType &'.
207 template <typename TDummy>
208 class PixelProxy<false, TDummy> final
209 {
210 private:
211 // The const proxy is a friend, to ease implementing conversion from
212 // a non-const proxy to a const proxy.
213 friend class PixelProxy<true>;
214
215 // Pointer to the buffer of the image. Should not be null.
217
218 // Pixel access policy.
219 const TImageNeighborhoodPixelAccessPolicy m_PixelAccessPolicy;
220
221 public:
222 // Deleted member functions:
223 PixelProxy() = delete;
224
225 // Explicitly-defaulted member functions:
226 ~PixelProxy() = default;
227 PixelProxy(const PixelProxy &) noexcept = default;
228
229 // Constructor, called directly by operator*() of the iterator class.
230 PixelProxy(InternalPixelType * const imageBufferPointer,
231 const TImageNeighborhoodPixelAccessPolicy & pixelAccessPolicy) noexcept
232 : m_ImageBufferPointer{ imageBufferPointer }
233 , m_PixelAccessPolicy{ pixelAccessPolicy }
234 {}
235
236 // Conversion operator.
237 operator PixelType() const noexcept { return m_PixelAccessPolicy.GetPixelValue(m_ImageBufferPointer); }
238
239 // Operator to assign a pixel value to the proxy.
240 PixelProxy &
241 operator=(const PixelType & pixelValue) noexcept
242 {
243 m_PixelAccessPolicy.SetPixelValue(m_ImageBufferPointer, pixelValue);
244 return *this;
245 }
246
247 // Copy-assignment operator.
248 PixelProxy &
249 operator=(const PixelProxy & pixelProxy) noexcept
250 {
251 // Note that this assignment operator only copies the pixel value.
252 // That is the normal behavior when a reference is assigned to another.
253 const PixelType pixelValue = pixelProxy;
254 *this = pixelValue;
255 return *this;
256 }
257
258
259 friend void
260 swap(PixelProxy lhs, PixelProxy rhs) noexcept
261 {
262 const auto lhsPixelValue = lhs.m_PixelAccessPolicy.GetPixelValue(lhs.m_ImageBufferPointer);
263 const auto rhsPixelValue = rhs.m_PixelAccessPolicy.GetPixelValue(rhs.m_ImageBufferPointer);
264
265 // Swap only the pixel values, not the image buffer pointers!
266 lhs.m_PixelAccessPolicy.SetPixelValue(lhs.m_ImageBufferPointer, rhsPixelValue);
267 rhs.m_PixelAccessPolicy.SetPixelValue(rhs.m_ImageBufferPointer, lhsPixelValue);
268 }
269 };
270
271
284 template <bool VIsConst>
286 {
287 private:
288 // Const and non-const iterators are friends, in order to implement the
289 // constructor that allow conversion from non-const to const iterator.
290 friend class QualifiedIterator<!VIsConst>;
291
292 // ShapedImageNeighborhoodRange is a friend, as it should be the only one that can
293 // directly use the private constructor of the iterator.
295
296 // Image type class that is either 'const' or non-const qualified, depending on QualifiedIterator and TImage.
297 using QualifiedImageType = std::conditional_t<VIsConst, const ImageType, ImageType>;
298
299 static constexpr bool IsImageTypeConst = std::is_const_v<QualifiedImageType>;
300
301 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
302
303 // Pixel type class that is either 'const' or non-const qualified, depending on QualifiedImageType.
304 using QualifiedPixelType = std::conditional_t<IsImageTypeConst, const PixelType, PixelType>;
305
306 // Pointer to the buffer of the image. Only null when the iterator is default-constructed.
308
309 // Image size.
311
312 // A copy of the offset table of the image.
314
315 // The accessor of the image.
317
319
320 // The pixel coordinates of the location of the neighborhood, relative to
321 // the index of the first pixel of the buffered region. Note that this
322 // location does not have to be within buffered region. It may also be
323 // outside the image.
325
326 const OffsetType * m_CurrentOffset = nullptr;
327
328 // Private constructor, used to create the begin and the end iterator of a range.
329 // Only used by its friend class ShapedImageNeighborhoodRange.
331 const ImageSizeType & imageSize,
332 const OffsetType & offsetTable,
333 const NeighborhoodAccessorFunctorType & neighborhoodAccessor,
334 const OptionalPixelAccessParameterType optionalPixelAccessParameter,
335 const IndexType & relativeLocation,
336 const OffsetType * const offset) noexcept
337 : m_ImageBufferPointer{ imageBufferPointer }
338 ,
339 // Note: Use parentheses instead of curly braces to initialize data members,
340 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
341 m_ImageSize(imageSize)
342 , m_OffsetTable(offsetTable)
343 , m_NeighborhoodAccessor(neighborhoodAccessor)
344 , m_OptionalPixelAccessParameter(optionalPixelAccessParameter)
345 , m_RelativeLocation(relativeLocation)
346 , m_CurrentOffset{ offset }
347 {}
348
349
350 TImageNeighborhoodPixelAccessPolicy CreatePixelAccessPolicy(EmptyPixelAccessParameter) const
351 {
352 return TImageNeighborhoodPixelAccessPolicy{
354 };
355 }
356
357 template <typename TPixelAccessParameter>
358 TImageNeighborhoodPixelAccessPolicy
359 CreatePixelAccessPolicy(const TPixelAccessParameter pixelAccessParameter) const
360 {
361 static_assert(std::is_same_v<TPixelAccessParameter, OptionalPixelAccessParameterType>,
362 "This helper function should only be used for OptionalPixelAccessParameterType!");
363 static_assert(!std::is_same_v<TPixelAccessParameter, EmptyPixelAccessParameter>,
364 "EmptyPixelAccessParameter indicates that there is no pixel access parameter specified!");
365 return TImageNeighborhoodPixelAccessPolicy{
367 };
368 }
369
370 public:
371 // Types conforming the iterator requirements of the C++ standard library:
372 using difference_type = ptrdiff_t;
376 using iterator_category = std::random_access_iterator_tag;
377
378
387 QualifiedIterator() = default;
388
390 template <bool VIsArgumentConst, typename = std::enable_if_t<VIsConst && !VIsArgumentConst>>
392 : m_ImageBufferPointer{ arg.m_ImageBufferPointer }
393 ,
394 // Note: Use parentheses instead of curly braces to initialize data members,
395 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
396 m_ImageSize(arg.m_ImageSize)
397 , m_OffsetTable(arg.m_OffsetTable)
398 , m_NeighborhoodAccessor(arg.m_NeighborhoodAccessor)
399 , m_OptionalPixelAccessParameter(arg.m_OptionalPixelAccessParameter)
400 , m_RelativeLocation(arg.m_RelativeLocation)
401 , m_CurrentOffset{ arg.m_CurrentOffset }
402 {}
407 reference operator*() const noexcept
408 {
410 }
416 operator++() noexcept
417 {
418 assert(m_CurrentOffset != nullptr);
420 return *this;
421 }
428 operator++(int) noexcept
429 {
430 auto result = *this;
431 ++(*this);
432 return result;
433 }
439 operator--() noexcept
440 {
441 assert(m_CurrentOffset != nullptr);
443 return *this;
444 }
451 operator--(int) noexcept
452 {
453 auto result = *this;
454 --(*this);
455 return result;
456 }
463 friend bool
464 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
465 {
466 assert(lhs.m_ImageBufferPointer == rhs.m_ImageBufferPointer);
467 assert(lhs.m_ImageSize == rhs.m_ImageSize);
468 assert(lhs.m_OffsetTable == rhs.m_OffsetTable);
471 return lhs.m_CurrentOffset == rhs.m_CurrentOffset;
472 }
473
474
476 friend bool
477 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
478 {
479 // Implemented just like the corresponding std::rel_ops operator.
480 return !(lhs == rhs);
481 }
482
483
485 friend bool
486 operator<(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
487 {
488 assert(lhs.m_ImageBufferPointer == rhs.m_ImageBufferPointer);
489 assert(lhs.m_ImageSize == rhs.m_ImageSize);
490 assert(lhs.m_OffsetTable == rhs.m_OffsetTable);
493 return lhs.m_CurrentOffset < rhs.m_CurrentOffset;
494 }
495
496
498 friend bool
499 operator>(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
500 {
501 // Implemented just like the corresponding std::rel_ops operator.
502 return rhs < lhs;
503 }
504
505
507 friend bool
508 operator<=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
509 {
510 // Implemented just like the corresponding std::rel_ops operator.
511 return !(rhs < lhs);
512 }
513
514
516 friend bool
517 operator>=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
518 {
519 // Implemented just like the corresponding std::rel_ops operator.
520 return !(lhs < rhs);
521 }
522
523
525 friend QualifiedIterator &
527 {
528 it.m_CurrentOffset += n;
529 return it;
530 }
534 friend QualifiedIterator &
536 {
537 it += (-n);
538 return it;
539 }
543 friend difference_type
544 operator-(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
545 {
546 assert(lhs.m_ImageBufferPointer == rhs.m_ImageBufferPointer);
547 assert(lhs.m_ImageSize == rhs.m_ImageSize);
548 assert(lhs.m_OffsetTable == rhs.m_OffsetTable);
551 return lhs.m_CurrentOffset - rhs.m_CurrentOffset;
552 }
553
554
556 friend QualifiedIterator
558 {
559 return it += n;
560 }
561
562
564 friend QualifiedIterator
566 {
567 return it += n;
568 }
569
570
572 friend QualifiedIterator
574 {
575 return it += (-n);
576 }
577
578
580 reference operator[](const difference_type n) const noexcept { return *(*this + n); }
581 };
582
583 static constexpr bool IsImageTypeConst = std::is_const_v<TImage>;
584
585 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
586
587
588 // Just the data from itk::ImageRegion (not the virtual table)
590 {
593
594 RegionData() noexcept = default;
595
596 explicit RegionData(const ImageRegionType & imageRegion)
597 : m_Index(imageRegion.GetIndex())
598 , m_Size(imageRegion.GetSize())
599 {}
600 };
601
602
603 void
604 SubtractIndex(IndexType & index1, const IndexType & index2)
605 {
606 for (unsigned int i = 0; i < ImageDimension; ++i)
607 {
608 index1[i] -= index2[i];
609 }
610 }
611
612 // ShapedImageNeighborhoodRange data members (strictly private):
613
614 // Pointer to the buffer of the image.
616
617 // Index and size of the buffered image region.
619
620 // A copy of the offset table of the image.
622
624
625 // Index (pixel coordinates) of the location of the neighborhood relative
626 // to the origin of the image. Typically it is the location of the
627 // center pixel of the neighborhood. It may be outside the image boundaries.
629
630 // The offsets relative to m_RelativeLocation that specify the neighborhood shape.
631 const OffsetType * m_ShapeOffsets{ nullptr };
632
633 // The number of neighborhood pixels.
635
637
638public:
641 using reverse_iterator = std::reverse_iterator<iterator>;
642 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
643
650
659 const IndexType & location,
660 const OffsetType * const shapeOffsets,
661 const size_t numberOfNeigborhoodPixels,
662 const OptionalPixelAccessParameterType optionalPixelAccessParameter = {})
663 : m_ImageBufferPointer{ image.ImageType::GetBufferPointer() }
664 ,
665 // Note: Use parentheses instead of curly braces to initialize data members,
666 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
667 // and "excess elements in struct initializer".
668 m_BufferedRegionData(image.ImageType::GetBufferedRegion())
669 , m_NeighborhoodAccessor(image.GetNeighborhoodAccessor())
670 , m_RelativeLocation(location)
671 , m_ShapeOffsets{ shapeOffsets }
672 , m_NumberOfNeighborhoodPixels{ numberOfNeigborhoodPixels }
673 , m_OptionalPixelAccessParameter(optionalPixelAccessParameter)
674 {
675 const OffsetValueType * const offsetTable = image.GetOffsetTable();
676 assert(offsetTable != nullptr);
679 std::copy_n(offsetTable, ImageDimension, m_OffsetTable.begin());
680
683 }
684
694 template <typename TContainerOfOffsets>
696 const IndexType & location,
697 const TContainerOfOffsets & shapeOffsets,
698 const OptionalPixelAccessParameterType optionalPixelAccessParameter = {})
700 location,
701 std::data(shapeOffsets),
702 std::size(shapeOffsets),
703 optionalPixelAccessParameter }
704 {}
709 begin() const noexcept
710 {
713 }
714
717 end() const noexcept
718 {
726 }
727
731 cbegin() const noexcept
732 {
733 return this->begin();
734 }
735
738 cend() const noexcept
739 {
740 return this->end();
741 }
742
745 rbegin() const noexcept
746 {
747 return reverse_iterator(this->end());
748 }
749
752 rend() const noexcept
753 {
754 return reverse_iterator(this->begin());
755 }
756
759 crbegin() const noexcept
760 {
761 return this->rbegin();
762 }
763
766 crend() const noexcept
767 {
768 return this->rend();
769 }
770
771
773 size_t
774 size() const noexcept
775 {
777 }
778
779
781 bool
782 empty() const noexcept
783 {
785 }
786
787
793 typename QualifiedIterator<false>::reference operator[](const size_t n) const noexcept
794 {
795 assert(n < this->size());
796 assert(n <= static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()));
799 return this->begin()[static_cast<ptrdiff_t>(n)];
800 }
801
802
806 void
807 SetLocation(const IndexType & location) noexcept
808 {
809 m_RelativeLocation = location;
811 }
812};
815} // namespace itk
816
817#endif
static int Test(typename T::PixelAccessParameterType *)
PixelProxy(InternalPixelType *const imageBufferPointer, const TImageNeighborhoodPixelAccessPolicy &pixelAccessPolicy) noexcept
PixelProxy & operator=(const PixelProxy &)=delete
PixelProxy(const InternalPixelType *const imageBufferPointer, const TImageNeighborhoodPixelAccessPolicy &pixelAccessPolicy) noexcept
friend difference_type operator-(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
QualifiedIterator(QualifiedInternalPixelType *const imageBufferPointer, const ImageSizeType &imageSize, const OffsetType &offsetTable, const NeighborhoodAccessorFunctorType &neighborhoodAccessor, const OptionalPixelAccessParameterType optionalPixelAccessParameter, const IndexType &relativeLocation, const OffsetType *const offset) noexcept
friend QualifiedIterator & operator-=(QualifiedIterator &it, const difference_type n) noexcept
friend bool operator!=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
friend QualifiedIterator operator+(const difference_type n, QualifiedIterator it) noexcept
friend QualifiedIterator & operator+=(QualifiedIterator &it, const difference_type n) noexcept
friend QualifiedIterator operator-(QualifiedIterator it, const difference_type n) noexcept
std::conditional_t< VIsConst, const ImageType, ImageType > QualifiedImageType
std::conditional_t< IsImageTypeConst, const PixelType, PixelType > QualifiedPixelType
friend bool operator==(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
TImageNeighborhoodPixelAccessPolicy CreatePixelAccessPolicy(EmptyPixelAccessParameter) const
QualifiedIterator(const QualifiedIterator< VIsArgumentConst > &arg) noexcept
friend bool operator<=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
friend QualifiedIterator operator+(QualifiedIterator it, const difference_type n) noexcept
friend bool operator<(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
TImageNeighborhoodPixelAccessPolicy CreatePixelAccessPolicy(const TPixelAccessParameter pixelAccessParameter) const
friend bool operator>=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
reference operator[](const difference_type n) const noexcept
friend bool operator>(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
std::conditional_t< IsImageTypeConst, const InternalPixelType, InternalPixelType > QualifiedInternalPixelType
QualifiedIterator< IsImageTypeConst > iterator
typename TImage::InternalPixelType InternalPixelType
std::reverse_iterator< iterator > reverse_iterator
typename TImage::ImageDimensionType ImageDimensionType
void SetLocation(const IndexType &location) noexcept
static constexpr ImageDimensionType ImageDimension
const_reverse_iterator crend() const noexcept
ShapedImageNeighborhoodRange(ImageType &image, const IndexType &location, const TContainerOfOffsets &shapeOffsets, const OptionalPixelAccessParameterType optionalPixelAccessParameter={})
reverse_iterator rbegin() const noexcept
NeighborhoodAccessorFunctorType m_NeighborhoodAccessor
typename OptionalPixelAccessParameter< TImageNeighborhoodPixelAccessPolicy >::Type OptionalPixelAccessParameterType
const_reverse_iterator crbegin() const noexcept
ShapedImageNeighborhoodRange(ImageType &image, const IndexType &location, const OffsetType *const shapeOffsets, const vcl_size_t numberOfNeigborhoodPixels, const OptionalPixelAccessParameterType optionalPixelAccessParameter={})
typename TImage::SizeValueType ImageSizeValueType
typename TImage::IndexValueType IndexValueType
void SubtractIndex(IndexType &index1, const IndexType &index2)
typename TImage::NeighborhoodAccessorFunctorType NeighborhoodAccessorFunctorType
std::conditional_t< IsImageTypeConst, const InternalPixelType, InternalPixelType > QualifiedInternalPixelType
OptionalPixelAccessParameterType m_OptionalPixelAccessParameter
std::reverse_iterator< const_iterator > const_reverse_iterator
QualifiedIterator< false >::reference operator[](const vcl_size_t n) const noexcept
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
void swap(Array< T > &a, Array< T > &b) noexcept
Definition: itkArray.h:242
long IndexValueType
Definition: itkIntTypes.h:93
unsigned long SizeValueType
Definition: itkIntTypes.h:86
long OffsetValueType
Definition: itkIntTypes.h:97
constexpr iterator begin()
Definition: itkOffset.h:316