template<typename Types>
dip::JointImageIterator class

An iterator to iterate over all pixels of multiple images.

The images must have the same sizes except along the processing dimension. It behaves similarly to dip::ImageIterator with the following differences:

  • This iterator is not dereferenceable and has no [] operator. The reason is that it points at multiple pixels at the same time (that is, one pixel in each image). Instead, use the Sample<N> method to obtain a reference to a sample of the pixel in image N.

  • The GetLineIterator, Pointer and Offset methods are templated also, requiring a template parameter N as in Offset<N>.

  • The Optimize method sorts image dimensions to optimize looping over the first image. The iterator will be most efficient if all images share dimension ordering.

The first image in the set must be forged. Other images can be empty, but dereferencing them will lead to undefined behavior.

Note that, within templated code, calling the Sample<N> and similar templated methods requires specifying that the method is a template:

template< typename TPI >
void Function( ... ) {
   JointImageIterator< TPI, bin > it( { in, mask } );
   do {
      if( it.template Sample< 1 >() ) {   // Note `template` on this line
          it.template Sample< 0 >() = 0;  // Note `template` on this line
      }
   } while( ++it );
}

There exist aliases InXxx for Xxx<0>, and OutXxx for Xxx<1>, where Xxx is Sample, Pointer or Offset. In() is an alias for Sample<0>() and Out() is an alias for Sample<1>().

Note that when an image is stripped or reforged, all its iterators are invalidated.

Constructors, destructors, assignment and conversion operators

JointImageIterator()
Default constructor yields an invalid iterator that cannot be dereferenced, and is equivalent to an end iterator.
JointImageIterator(dip::ImageConstRefArray const& images, dip::uint procDim = std::numeric_limits::max()) explicit
To construct a useful iterator, provide N images (N equal to the number of template parameters), and optionally a processing dimension.

Aliases

using iterator_category = std::forward_iterator_tag
Iterator category
template<dip::uint I>
using value_type = typename std::tuple_element<I, std::tuple<Types...>>::type
The data type of the sample, obtained when dereferencing the iterator
template<dip::uint I>
using reference = value_type<I>&
The type of a reference to a sample
template<dip::uint I>
using pointer = value_type<I>*
The type of a pointer to a sample

Functions

void swap(JointImageIterator<Types...>& other)
Swap
template<dip::uint I>
auto Sample(dip::uint index) const -> reference<I>
Index into image tensor for image I
auto InSample(dip::uint index) const -> reference<0>
Index into image tensor for image 0.
auto OutSample(dip::uint index) const -> reference<1>
Index into image tensor for image 1.
template<dip::uint I>
auto Sample() const -> reference<I>
Get first tensor element for image I.
auto In() const -> reference<0>
Get first tensor element for image 0.
auto Out() const -> reference<1>
Get first tensor element for image 1.
template<dip::uint I>
auto begin() const -> SampleIterator<value_type<I>>
Get an iterator over the tensor for the current pixel of image I
template<dip::uint I>
auto end() const -> SampleIterator<value_type<I>>
Get an end iterator over the tensor for the current pixel of image I
template<dip::uint I>
auto cbegin() const -> ConstSampleIterator<value_type<I>>
Get a const iterator over the tensor for the current pixel of image I
template<dip::uint I>
auto cend() const -> ConstSampleIterator<value_type<I>>
Get an end const iterator over the tensor for the current pixel of image I
template<dip::uint I>
auto GetLineIterator() const -> LineIterator<value_type<I>>
Get an iterator over the current line of image I
template<dip::uint I>
auto GetConstLineIterator() const -> ConstLineIterator<value_type<I>>
Get a const iterator over the current line of image I
auto IsAtEnd() const -> bool
Test to see if the iterator reached past the last pixel
auto Coordinates() const -> dip::UnsignedArray const&
Return the current coordinates
auto SetCoordinates(dip::UnsignedArray coords) -> JointImageIterator<Types...>&
Set the iterator to point at a different location in the image
auto Sizes() const -> dip::UnsignedArray const&
Return the sizes of the images we’re iterating over.
auto ProcessingDimensionSize() const -> dip::uint
Return the size along the processing dimension.
template<dip::uint I>
auto Strides() const -> dip::IntegerArray const&
Return the strides used to iterate over the image I.
template<dip::uint I>
auto ProcessingDimensionStride() const -> dip::sint
Return the stride along the processing dimension.
auto IsOnEdge() const -> bool
Return true if the iterator points at a pixel on the edge of the image.
template<dip::uint I>
auto Pointer() const -> pointer<I>
Return the current pointer for image I
auto InPointer() const -> pointer<0>
Return the current pointer for image 0.
auto OutPointer() const -> pointer<1>
Return the current pointer for image 1.
template<dip::uint I>
auto Offset() const -> dip::sint
Return the current offset for image I
auto InOffset() const -> dip::sint
Index into image tensor for image 0.
auto OutOffset() const -> dip::sint
Index into image tensor for image 1.
auto Index() const -> dip::uint
Return the current index, which is computed: this function is not trivial
auto HasProcessingDimension() const -> bool
True if the processing dimension is set
auto ProcessingDimension() const -> dip::uint
Return the processing dimension, the direction of the lines over which the iterator iterates.
auto Reset() -> JointImageIterator<Types...>&
Reset the iterator to the first pixel in the image (as it was when first created)
auto Optimize(dip::uint n = 0) -> JointImageIterator<Types...>&
Optimizes the order in which the iterator visits the image pixels.
auto OptimizeAndFlatten(dip::uint n = 0) -> JointImageIterator<Types...>&
Like Optimize, but additionally folds dimensions together where possible (flattens the image, so that the iterator has fewer dimensions to work with). The processing dimension is not affected.

Operators

auto operator++() -> JointImageIterator<Types...>&
Pre-increment
auto operator++(int ) -> JointImageIterator<Types...>
Post-increment
template<typename OtherTypes>
auto operator==(JointImageIterator<OtherTypes...> const& other) const -> bool
Equality comparison, is equal if the two iterators have the same coordinates. It is possible to compare JointImageIterators with different images and different types.
template<typename OtherTypes>
auto operator!=(JointImageIterator<OtherTypes...> const& other) const -> bool
Inequality comparison
auto operator bool() const -> bool explicit
Test to see if the iterator is still pointing at a pixel

Function documentation

template<typename Types>
bool IsOnEdge() const

Return true if the iterator points at a pixel on the edge of the image.

If there is a processing dimension, then the iterator always points at an edge pixel; in this case only returns true if all pixels on the line are edge pixels (i.e. the first and last pixel of the line are not counted).

template<typename Types>
dip::uint ProcessingDimension() const

Return the processing dimension, the direction of the lines over which the iterator iterates.

If the return value is larger or equal to the dimensionality (i.e. not one of the image dimensions), then there is no processing dimension.

template<typename Types>
JointImageIterator<Types...>& Optimize(dip::uint n = 0)

Optimizes the order in which the iterator visits the image pixels.

The iterator internally reorders and flips image dimensions to change the linear index to match the storage order of the first image (see dip::Image::StandardizeStrides), or image n if a parameter is given. If the image’s strides were not normal, this will significantly increase the speed of reading or writing to the image. Expanded singleton dimensions are eliminated only if the dimension is expanded in all images. Additionally, singleton dimensions are ignored.

After calling this function, Coordinates and Index no longer match the input images. Do not use this method if the order of accessing pixels is relevant, or if Coordinates are needed.

Note that the processing dimension stride could change sign. Use ProcessingDimensionStride. If the processing dimension was a singleton dimension, or singleton-expanded, the iterator will no longer have a singleton dimension. In this case, HasProcessingDimension will return false.

The iterator is reset to the first pixel.