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
352 {
353 return TImageNeighborhoodPixelAccessPolicy{
355 };
356 }
357
358 template <typename TPixelAccessParameter>
359 TImageNeighborhoodPixelAccessPolicy
360 CreatePixelAccessPolicy(const TPixelAccessParameter pixelAccessParameter) const
361 {
362 static_assert(std::is_same_v<TPixelAccessParameter, OptionalPixelAccessParameterType>,
363 "This helper function should only be used for OptionalPixelAccessParameterType!");
364 static_assert(!std::is_same_v<TPixelAccessParameter, EmptyPixelAccessParameter>,
365 "EmptyPixelAccessParameter indicates that there is no pixel access parameter specified!");
366 return TImageNeighborhoodPixelAccessPolicy{
368 };
369 }
370
371 public:
372 // Types conforming the iterator requirements of the C++ standard library:
373 using difference_type = ptrdiff_t;
377 using iterator_category = std::random_access_iterator_tag;
378
379
388 QualifiedIterator() = default;
389
391 template <bool VIsArgumentConst, typename = std::enable_if_t<VIsConst && !VIsArgumentConst>>
393 : m_ImageBufferPointer{ arg.m_ImageBufferPointer }
394 ,
395 // Note: Use parentheses instead of curly braces to initialize data members,
396 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
397 m_ImageSize(arg.m_ImageSize)
398 , m_OffsetTable(arg.m_OffsetTable)
399 , m_NeighborhoodAccessor(arg.m_NeighborhoodAccessor)
400 , m_OptionalPixelAccessParameter(arg.m_OptionalPixelAccessParameter)
401 , m_RelativeLocation(arg.m_RelativeLocation)
402 , m_CurrentOffset{ arg.m_CurrentOffset }
403 {}
409 operator*() const noexcept
410 {
412 }
418 operator++() noexcept
419 {
420 assert(m_CurrentOffset != nullptr);
422 return *this;
423 }
430 operator++(int) noexcept
431 {
432 auto result = *this;
433 ++(*this);
434 return result;
435 }
441 operator--() noexcept
442 {
443 assert(m_CurrentOffset != nullptr);
445 return *this;
446 }
453 operator--(int) noexcept
454 {
455 auto result = *this;
456 --(*this);
457 return result;
458 }
465 friend bool
466 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
467 {
468 assert(lhs.m_ImageBufferPointer == rhs.m_ImageBufferPointer);
469 assert(lhs.m_ImageSize == rhs.m_ImageSize);
470 assert(lhs.m_OffsetTable == rhs.m_OffsetTable);
473 return lhs.m_CurrentOffset == rhs.m_CurrentOffset;
474 }
475
476
478 friend bool
479 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
480 {
481 // Implemented just like the corresponding std::rel_ops operator.
482 return !(lhs == rhs);
483 }
484
485
487 friend bool
488 operator<(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
489 {
490 assert(lhs.m_ImageBufferPointer == rhs.m_ImageBufferPointer);
491 assert(lhs.m_ImageSize == rhs.m_ImageSize);
492 assert(lhs.m_OffsetTable == rhs.m_OffsetTable);
495 return lhs.m_CurrentOffset < rhs.m_CurrentOffset;
496 }
497
498
500 friend bool
501 operator>(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
502 {
503 // Implemented just like the corresponding std::rel_ops operator.
504 return rhs < lhs;
505 }
506
507
509 friend bool
510 operator<=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
511 {
512 // Implemented just like the corresponding std::rel_ops operator.
513 return !(rhs < lhs);
514 }
515
516
518 friend bool
519 operator>=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
520 {
521 // Implemented just like the corresponding std::rel_ops operator.
522 return !(lhs < rhs);
523 }
524
525
527 friend QualifiedIterator &
529 {
530 it.m_CurrentOffset += n;
531 return it;
532 }
536 friend QualifiedIterator &
538 {
539 it += (-n);
540 return it;
541 }
545 friend difference_type
546 operator-(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
547 {
548 assert(lhs.m_ImageBufferPointer == rhs.m_ImageBufferPointer);
549 assert(lhs.m_ImageSize == rhs.m_ImageSize);
550 assert(lhs.m_OffsetTable == rhs.m_OffsetTable);
553 return lhs.m_CurrentOffset - rhs.m_CurrentOffset;
554 }
555
556
558 friend QualifiedIterator
560 {
561 return it += n;
562 }
563
564
566 friend QualifiedIterator
568 {
569 return it += n;
570 }
571
572
574 friend QualifiedIterator
576 {
577 return it += (-n);
578 }
579
580
583 operator[](const difference_type n) const noexcept
584 {
585 return *(*this + n);
586 }
587 };
590 static constexpr bool IsImageTypeConst = std::is_const_v<TImage>;
591
592 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
593
594
595 // Just the data from itk::ImageRegion (not the virtual table)
597 {
600
601 RegionData() noexcept = default;
602
603 explicit RegionData(const ImageRegionType & imageRegion)
604 : m_Index(imageRegion.GetIndex())
605 , m_Size(imageRegion.GetSize())
606 {}
607 };
608
609
610 void
611 SubtractIndex(IndexType & index1, const IndexType & index2)
612 {
613 for (unsigned int i = 0; i < ImageDimension; ++i)
614 {
615 index1[i] -= index2[i];
616 }
617 }
618
619 // ShapedImageNeighborhoodRange data members (strictly private):
620
621 // Pointer to the buffer of the image.
623
624 // Index and size of the buffered image region.
626
627 // A copy of the offset table of the image.
629
631
632 // Index (pixel coordinates) of the location of the neighborhood relative
633 // to the origin of the image. Typically it is the location of the
634 // center pixel of the neighborhood. It may be outside the image boundaries.
636
637 // The offsets relative to m_RelativeLocation that specify the neighborhood shape.
638 const OffsetType * m_ShapeOffsets{ nullptr };
639
640 // The number of neighborhood pixels.
642
644
645public:
648 using reverse_iterator = std::reverse_iterator<iterator>;
649 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
650
657
666 const IndexType & location,
667 const OffsetType * const shapeOffsets,
668 const size_t numberOfNeigborhoodPixels,
669 const OptionalPixelAccessParameterType optionalPixelAccessParameter = {})
670 : m_ImageBufferPointer{ image.ImageType::GetBufferPointer() }
671 ,
672 // Note: Use parentheses instead of curly braces to initialize data members,
673 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
674 // and "excess elements in struct initializer".
675 m_BufferedRegionData(image.ImageType::GetBufferedRegion())
676 , m_NeighborhoodAccessor(image.GetNeighborhoodAccessor())
677 , m_RelativeLocation(location)
678 , m_ShapeOffsets{ shapeOffsets }
679 , m_NumberOfNeighborhoodPixels{ numberOfNeigborhoodPixels }
680 , m_OptionalPixelAccessParameter(optionalPixelAccessParameter)
681 {
682 const OffsetValueType * const offsetTable = image.GetOffsetTable();
683 assert(offsetTable != nullptr);
686 std::copy_n(offsetTable, ImageDimension, m_OffsetTable.begin());
687
690 }
691
701 template <typename TContainerOfOffsets>
703 const IndexType & location,
704 const TContainerOfOffsets & shapeOffsets,
705 const OptionalPixelAccessParameterType optionalPixelAccessParameter = {})
707 location,
708 std::data(shapeOffsets),
709 std::size(shapeOffsets),
710 optionalPixelAccessParameter }
711 {}
716 begin() const noexcept
717 {
720 }
721
724 end() const noexcept
725 {
733 }
734
738 cbegin() const noexcept
739 {
740 return this->begin();
741 }
742
745 cend() const noexcept
746 {
747 return this->end();
748 }
749
752 rbegin() const noexcept
753 {
754 return reverse_iterator(this->end());
755 }
756
759 rend() const noexcept
760 {
761 return reverse_iterator(this->begin());
762 }
763
766 crbegin() const noexcept
767 {
768 return this->rbegin();
769 }
770
773 crend() const noexcept
774 {
775 return this->rend();
776 }
777
778
780 size_t
781 size() const noexcept
782 {
784 }
785
786
788 bool
789 empty() const noexcept
790 {
792 }
793
794
801 operator[](const size_t n) const noexcept
802 {
803 assert(n < this->size());
804 assert(n <= static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()));
807 return this->begin()[static_cast<ptrdiff_t>(n)];
808 }
809
810
814 void
815 SetLocation(const IndexType & location) noexcept
816 {
817 m_RelativeLocation = location;
819 }
820};
823} // namespace itk
824
825#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