N-dimensional buffer images

Include:
  • <mln/core/image/ndbuffer_image.hpp> for ndbuffer_image

  • <mln/core/image/ndimage.hpp> for ndimage<T>

  • <mln/core/image/ndimage_fwd.hpp> for forward declarations.

N-dimensional buffer images __ndbuffer_image are the most common image types that stores elements within a buffer.

Memory layout and memory management

__ndbuffer_image supports strided access (this is necessary for border management and clipping operations) but ensures that elemnents of a row are contiguous.

__ndbuffer_image can own the buffer or can borrow data from an external buffer (see __ndbuffer_image::from_buffer()). In both case __ndbuffer_image has reference semantics on the owned buffer. It means that copying the image results in a shallow copy. The memory is automatically freed when the last reference goes out.

Dynamic vs Static image and Type-erasure

While the type of the element T and the number of dimension pdim are known at compile-time, __ndbuffer_image supports partial type and dimension erasure.

T

pdim

Type alias

Description

void

dynamic = -1

:cpp:any:ndbuffer_image

Full type-erased

T

1

:cpp:any:image1d\<T> <image1d>

1d image type

T

2

:cpp:any:image2d\<T> <image2d>

2d image type

T

3

:cpp:any:image3d\<T> <image3d>

3d image type

T

N

:cpp:any:ndimage\<T, N> <ndimage>

nd image type

using ndbuffer_image = __ndbuffer_image<void, dynamic>
template<class T>
using image1d = __ndbuffer_image<T, 1>
template<class T>
using image2d = __ndbuffer_image<T, 2>
template<class T>
using image3d = __ndbuffer_image<T, 3>
template<class T, int N>
using ndimage = __ndbuffer_image<T, N>

Border management

FIXME. to be documented

Overview of the n-dimensional image API

Overview of the n-dimensional image API

__ndbuffer_image<void, dynamic>

__ndbuffer_image<T, N>

Constructors

__ndbuffer_image()
__ndbuffer_image(sample_type_id sample_type, ConstBoxRef domain, const image_build_params& = {})
__ndbuffer_image(sample_type_id sample_type, int width, const image_build_params &params = {})
__ndbuffer_image(sample_type_id sample_type, int width, int height, const image_build_params &params = {})
__ndbuffer_image(sample_type_id sample_type, int width, int height, int depth, const image_build_params &params = {})
__ndbuffer_image(const __ndbuffer_image &other, const image_build_params&)
template<class T>
__ndbuffer_image(std::initializer_list<T>)
template<class T>
__ndbuffer_image(std::initializer_list<std::initializer_list<T>>)
template<class T>
__ndbuffer_image(std::initializer_list<std::initializer_list<std::initializer_list<T>>>)
template<class T, int N>
class __ndbuffer_image

Constructors from external sources

static ndbuffer_image from_buffer(std::byte *buffer, sample_type_id sample_type, int dim, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)
static ndbuffer_image from_buffer(std::byte *buffer, sample_type_id sample_type, int dim, const int topleft[], const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)
static ndbuffer_image from_buffer(T *buffer, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)

Resizing

void resize(const __ndbuffer_image &other, image_build_params params)
void resize(sample_type_id sample_type, int width, const image_build_params& = {})
void resize(sample_type_id sample_type, int width, int height, const image_build_params& = {})
void resize(sample_type_id sample_type, int width, int height, int depth, const image_build_params& = {})
void resize(sample_type_id sample_type, ConstBoxRef domain, const image_build_params& = {})
void resize(const __ndbuffer_image &other, image_build_params params)

Geometry information

int pdim() const noexcept
int width() const noexcept
int height() const noexcept
int depth() const noexcept
int size(int dim = 0) const noexcept
int border() const noexcept
Box domain() const noexcept
int pdim() const noexcept
int width() const noexcept
int height() const noexcept
int depth() const noexcept
int size(int dim = 0) const noexcept
int border() const noexcept
ndbox<N> domain() const noexcept

Data & Layout information

sample_type_id sample_type() const noexcept
std::byte *buffer() const noexcept
std::ptrdiff_t byte_stride(int dim = 1) const noexcept
std::ptrdiff_t stride(int dim = 1) const noexcept
index_type index_of_point(ConstPointRef p) const noexcept
point_type point_at_index(index_type i) const noexcept
index_type delta_index(ConstPointRef p) const noexcept
sample_type_id sample_type() const noexcept
T *buffer() const noexcept
std::ptrdiff_t byte_stride(int dim = 1) const noexcept
std::ptrdiff_t stride(int dim = 1) const noexcept
index_type index_of_point(ndpoint<N> p) const noexcept
ndpoint<N> point_at_index(index_type i) const noexcept
index_type delta_index(ndpoint<N> p) const noexcept

Data accessors

const void *operator()(ConstPointRef p) const noexcept
void *operator()(ConstPointRef p) noexcept
const void *at(ConstPointRef p) const noexcept
void *at(ConstPointRef p) noexcept
const void *operator[](index_type i) const noexcept
void *operator[](index_type i) noexcept
const T &operator()(ndpoint<N> p) const noexcept
const T &at(ndpoint<N> p) const noexcept
const T &operator[](index_type i) const noexcept

Slicing & clipping operations

ndbuffer_image clip(ConstBoxRef roi) const
ndbuffer_image row(int y) const
ndbuffer_image slice(int z) const
__ndbuffer_image clip(ndbox<N> roi) const
[[when N = 2]] image1d<T> row(int y) const noexcept
[[when N = 3]] image2d<T> slice(int z) const noexcept

Casting operators

template<class T, int N>
const __ndbuffer_image *cast_to() const
template<class T, int N>
__ndbuffer_image *cast_to()

Implicitely convertible to ndbuffer_image

Iteration facilities

auto values() const
auto pixels() const

API Reference of the dynamic N-dimensional buffer images (ndbuffer_image)

template<>
class __ndbuffer_image<void, dynamic>

Type definitions

using point_type = Point
using value_type = void*
using index_type = int
using domain_type = Box

Constructors

__ndbuffer_image()
__ndbuffer_image(sample_type_id sample_type, ConstBoxRef domain, const image_build_params& = {})
__ndbuffer_image(sample_type_id sample_type, int width, const image_build_params &params = {})
__ndbuffer_image(sample_type_id sample_type, int width, int height, const image_build_params &params = {})
__ndbuffer_image(sample_type_id sample_type, int width, int height, int depth, const image_build_params &params = {})
__ndbuffer_image(const __ndbuffer_image &other, const image_build_params&)
template<class T>
__ndbuffer_image(std::initializer_list<T>)
template<class T>
__ndbuffer_image(std::initializer_list<std::initializer_list<T>>)
template<class T>
__ndbuffer_image(std::initializer_list<std::initializer_list<std::initializer_list<T>>>)

Construction from external buffers

static ndbuffer_image from_buffer(std::byte *buffer, sample_type_id sample_type, int dim, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)
static ndbuffer_image from_buffer(std::byte *buffer, sample_type_id sample_type, int dim, const int topleft[], const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)

Resizing facilities

void resize(const __ndbuffer_image &other, image_build_params params)
void resize(sample_type_id sample_type, int width, const image_build_params& = {})
void resize(sample_type_id sample_type, int width, int height, const image_build_params& = {})
void resize(sample_type_id sample_type, int width, int height, int depth, const image_build_params& = {})
void resize(sample_type_id sample_type, ConstBoxRef domain, const image_build_params& = {})

Geometry information

int pdim() const noexcept
int width() const noexcept
int height() const noexcept
int depth() const noexcept
int size(int dim = 0) const noexcept
int border() const noexcept
Box domain() const noexcept

Data and layout information

sample_type_id sample_type() const noexcept
std::byte *buffer() const noexcept
std::ptrdiff_t byte_stride(int dim = 1) const noexcept
std::ptrdiff_t stride(int dim = 1) const noexcept
index_type index_of_point(ConstPointRef p) const noexcept
point_type point_at_index(index_type i) const noexcept
index_type delta_index(ConstPointRef p) const noexcept

Data accessors

const void *operator()(ConstPointRef p) const noexcept
void *operator()(ConstPointRef p) noexcept
const void *at(ConstPointRef p) const noexcept
void *at(ConstPointRef p) noexcept
const void *operator[](index_type i) const noexcept
void *operator[](index_type i) noexcept

Slicing & clipping operations

ndbuffer_image clip(ConstBoxRef roi) const
ndbuffer_image row(int y) const
ndbuffer_image slice(int z) const

Casting operators

template<class T, int N>
const __ndbuffer_image *cast_to() const
template<class T, int N>
__ndbuffer_image *cast_to()

Constructors

__ndbuffer_image()

Creates a empty image

__ndbuffer_image(sample_type_id sample_type, ConstBoxRef domain, const image_build_params& = {})
__ndbuffer_image(sample_type_id sample_type, int width, const image_build_params &params = {})
__ndbuffer_image(sample_type_id sample_type, int width, int height, const image_build_params &params = {})
__ndbuffer_image(sample_type_id sample_type, int width, int height, int depth, const image_build_params &params = {})

Creates an image of dimensions given by domain with the given sample_type. The overloads are provided for convenience:

  1. Creates a 1d image of the given width

  2. Creates a 2d image of size width × height

  3. Creates a 3d image of size width × height × depth

By default, the memory is left default-initialized. The optional params parameter can be used to provide advanced initialization information:

  • params.init_value can be used to value-initialize the buffer

  • params.border can be used to allocate the image with a given border size.

// Create a 3d image of size (width=2, height=3, depth=4) with type uint8_t and default border width (3)
// and random values
ndbuffer_image a(sample_type_id::UINT8, 2, 3, 4);


// Create a 2d image of size (width=5, height=5) with type uint16_t and border width = 5px
// with values set to zero.
image_build_params params;
params.init_value = uint16_t{0};
params.border = 5
ndbuffer_image b(sample_type_id::UINT16, 5, 5, params);
__ndbuffer_image(const __ndbuffer_image &other, const image_build_params&)

Initialization constructor

template<class T>
__ndbuffer_image(std::initializer_list<T>)
template<class T>
__ndbuffer_image(std::initializer_list<std::initializer_list<T>>)
template<class T>
__ndbuffer_image(std::initializer_list<std::initializer_list<std::initializer_list<T>>>)

Constructor from initializer lists (1d, 2d or 3d images).:

mln::ndbuffer_image f = {{1,2,3}, {4,5,6}};
// Extents: (width=3 x height=2) of type: INT32

mln::ndbuffer_image g = { {{1.f,2.f,3.f}, {4.f,5.f,6.f}}, {{7.f,8.f,9.f}, {10.f,11.f,12.f}} };
// Extents (width=3 x height=2 x depth=2) of type FLOAT

Construction from external buffers

static ndbuffer_image from_buffer(std::byte *buffer, sample_type_id sample_type, int dim, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)
static ndbuffer_image from_buffer(std::byte *buffer, sample_type_id sample_type, int dim, const int topleft[], const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)

Constructs an image using an external buffer.

Parameters:
  • buffer – Pointer to the buffer

  • sample_type – Type of elements

  • dim – Number of dimensions

  • topleft – Pointer to an array of dim elements holding the coordinates of the top-left corner (x, y, z, …) In (1), it is assumed to be (0, 0, 0,…)

  • sizes – Pointer to an array of dim elements holding the sizes of the image (width, height, depth, …)

  • byte_strides (optional) – Pointer to an array of dim elements holding the strides between consecutive elements in each dimension (in bytes). If NULL, strides are computed assuming the data are stored contiguously.

  • copy (optional) – If true, a copy of the buffer is done and managed internally. Otherwise, the buffer is not copied and the user is responsible for its destruction.

Resizing facilities

void resize(const __ndbuffer_image &other, image_build_params params)
void resize(sample_type_id sample_type, int width, const image_build_params& = {})
void resize(sample_type_id sample_type, int width, int height, const image_build_params& = {})
void resize(sample_type_id sample_type, int width, int height, int depth, const image_build_params& = {})
void resize(sample_type_id sample_type, ConstBoxRef domain, const image_build_params& = {})

See the corresponding contructors. These functions allow an image to be default-constructed and resized afterward.

Note

A new buffer is allocated. If a buffer was already attached to the image and this is the last reference, the memory is reclaimed.

Geometry information

int pdim() const noexcept

Get the number of dimensions of the image

int width() const noexcept

Get the width of the image (0 if empty)

int height() const noexcept

Get the height of the image (0 if empty). Returns 1 if the image is 1D.

int depth() const noexcept

Get the depth of the image (0 if empty). Returns 1 if the image is 1D or 2D.

int size(int dim = 0) const noexcept

Get the number of elements in the given dimension (0 if empty). Returns 1 if dim >= pdim().

int border() const noexcept

Get the size of the border.

Box domain() const noexcept

Get the domain of the image.

Data and layout information

sample_type_id sample_type() const noexcept

Get the sample type of the data.

std::byte *buffer() const noexcept

Get a pointer to first element (in the domain).

std::ptrdiff_t byte_stride(int dim = 1) const noexcept

Get the stride (in bytes) between two consecutive elements in the given dim.

std::ptrdiff_t stride(int dim = 1) const noexcept

Get the stride (in number of elements) between two consecutive elements in the given dim.

index_type index_of_point(ConstPointRef p) const noexcept

Get the linear index (offset in the buffer) of multi-dimensional point.

point_type point_at_index(index_type i) const noexcept

Get the point corresponding to the given index.

index_type delta_index(ConstPointRef p) const noexcept

Get the linear index offset for the given point.

Slicing & clipping operations

ndbuffer_image slice(int z) const

Return the slice at coordinate z in the 3th dimension.

Except:

std::runtime_error if y in invalid or dim() != 3.

ndbuffer_image row(int y) const

Return the row at coordinate y in the 2nd dimension.

Except:

std::runtime_error if y in invalid or dim() != 2.

ndbuffer_image clip(ConstBoxRef roi) const

Return the image restricted to the ROI roi. roi must be included in the domain.

Except:

std::runtime_error if domain().includes(roi) is false or dimensions mismatch.

Data accessors

const void *operator()(ConstPointRef p) const noexcept
void *operator()(ConstPointRef p) noexcept

Returns a pointer to the element at p.

Precondition: this->domain().has(p)

const void *at(ConstPointRef p) const noexcept
void *at(ConstPointRef p) noexcept

Returns a pointer to the element at p. p can be in the extension.

Precondition: p belongs to the extended domain.

const void *operator[](index_type i) const noexcept
void *operator[](index_type i) noexcept

Returns a pointer to the element at index i.

Precondition: i must be a valid index.

Casting operators

template<class T, int N>
const __ndbuffer_image *cast_to() const
template<class T, int N>
__ndbuffer_image *cast_to()

Down-cast (or trans-cast) to the requested n-dimensional image type. Returns nullptr if the requested types do not match the dynamic type information.

// Create a 3d image of size (width=2, height=3, depth=4) with type uint8_t and default border width (3)
// and random values
ndbuffer_image a(sample_type_id::UINT8, 2, 3, 4);

image3d<uint8_t>* b1 = a.template cast_to<uint8_t, 3>(); // Ok
image2d<uint8_t>* b2 = a.template cast_to<uint8_t, 2>(); // Fails (null pointer returned)

API Reference of the static N-dimensional buffer images (ndimage<T, N>)

template<class T, int N>
class __ndbuffer_image

Type definitions

using point_type = ndpoint<N>
using value_type = T
using index_type = int
using domain_type = ndbox<N>
type pixel_type
type const_pixel_type

Constructors

template<class T, int N>
class __ndbuffer_image
__ndbuffer_image()
__ndbuffer_image(ndbox<N> domain, const image_build_params& = {})
[[when N = 1]] __ndbuffer_image(int width, const image_build_params &params = {})
[[when N = 2]] __ndbuffer_image(int width, int height, const image_build_params &params = {})
[[when N = 3]] __ndbuffer_image(int width, int height, int depth, const image_build_params &params = {})
__ndbuffer_image(const __ndbuffer_image &other, const image_build_params&)
[[when N = 1]] __ndbuffer_image(std::initializer_list<T>)
[[when N = 2]] __ndbuffer_image(std::initializer_list<std::initializer_list<T>>)
[[when N = 3]] __ndbuffer_image(std::initializer_list<std::initializer_list<std::initializer_list<T>>>)

Construction from external buffers

static ndbuffer_image from_buffer(T *buffer, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)
static ndbuffer_image from_buffer(T *buffer, const int topleft[], const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)

Resizing facilities

void resize(const __ndbuffer_image &other, image_build_params params)
void resize(int width, const image_build_params& = {})
void resize(int width, int height, const image_build_params& = {})
void resize(int width, int height, int depth, const image_build_params& = {})
void resize(ConstBoxRef domain, const image_build_params& = {})

Geometry information

int pdim() const noexcept
int width() const noexcept
int height() const noexcept
int depth() const noexcept
int size(int dim = 0) const noexcept
int border() const noexcept
ndbox<N> domain() const noexcept

Data and layout information

sample_type_id sample_type() const noexcept
T *buffer() const noexcept
std::ptrdiff_t byte_stride(int dim = 1) const noexcept
std::ptrdiff_t stride(int dim = 1) const noexcept
index_type index_of_point(ndpoint<N> p) const noexcept
ndpoint<N> point_at_index(index_type i) const noexcept
index_type delta_index(ndpoint<N> p) const noexcept

Data accessors

const T &operator()(ndpoint<N> p) const noexcept
T &operator()(ndpoint<N> p) noexcept
const T &at(ndpoint<N> p) const noexcept
T &at(ndpoint<N> p) noexcept
const T &operator[](index_type i) const noexcept
T &operator[](index_type i) noexcept

Slicing & clipping operations

__ndbuffer_image clip(ndbox<N> roi) const
[[when N = 2]] image1d<T> row(int y) const noexcept
[[when N = 3]] image2d<T> slice(int z) const noexcept

Casting operators

Implcitely convertible to ndbuffer_image.

Iteration

auto values() const
auto values()
auto pixels() const
auto pixels()

Constructors

__ndbuffer_image()

Creates a empty N-d image with sample type T

__ndbuffer_image(ndbox<N> domain, const image_build_params& = {})
[[when N = 1]] __ndbuffer_image(int width, const image_build_params &params = {})
[[when N = 2]] __ndbuffer_image(int width, int height, const image_build_params &params = {})
[[when N = 3]] __ndbuffer_image(int width, int height, int depth, const image_build_params &params = {})

Creates an image of dimensions given by domain with value type given by T. The overloads are provided for convenience and availability depends on N:

  1. When N = 1 Creates a 1d image of the given width

  2. When N = 2 Creates a 2d image of size width × height

  3. When N = 3 Creates a 3d image of size width × height × depth

By default, the memory is left default-initialized. The optional params parameter can be used to provide advanced initialization information:

  • params.init_value can be used to value-initialize the buffer

  • params.border can be used to allocate the image with a given border size.

// Create a 3d image of size (width=2, height=3, depth=4) with type uint8_t and default border width (3)
// and random values
image3d<uint8_t> a(2, 3, 4);


// Create a 2d image of size (width=5, height=5) with type uint16_t and border width = 5px
// with values set to zero.
image_build_params params;
params.init_value = uint16_t{0};
params.border = 5
image2d<uint16_t> b(5, 5, params);
__ndbuffer_image(const __ndbuffer_image &other, const image_build_params&)

Initialization constructor

[[when N = 1]] __ndbuffer_image(std::initializer_list<T>)
[[when N = 2]] __ndbuffer_image(std::initializer_list<std::initializer_list<T>>)
[[when N = 3]] __ndbuffer_image(std::initializer_list<std::initializer_list<std::initializer_list<T>>>)

Constructor from initializer lists. Availability depends on N.

image2d<int> = {{1,2,3}, {4,5,6}};
// Extents: (width=3 x height=2) of type: INT32

image3d<float> g = { {{1.f,2.f,3.f}, {4.f,5.f,6.f}}, {{7.f,8.f,9.f}, {10.f,11.f,12.f}} };
// Extents (width=3 x height=2 x depth=2) of type FLOAT

Construction from external buffers

static ndbuffer_image from_buffer(T *buffer, const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)
static ndbuffer_image from_buffer(T *buffer, const int topleft[], const int sizes[], const std::ptrdiff_t byte_strides[] = nullptr, bool copy = false)

Constructs an image using an external buffer.

Parameters:
  • buffer – Pointer to the buffer

  • topleft – Pointer to an array of dim elements holding the coordinates of the top-left corner (x, y, z, …) In (1), it is assumed to be (0, 0, 0,…)

  • sizes – Pointer to an array of dim elements holding the sizes of the image (width, height, depth, …)

  • byte_strides (optional) – Pointer to an array of dim elements holding the strides between consecutive elements in each dimension (in bytes). If NULL, strides are computed assuming the data are stored contiguously.

  • copy (optional) – If true, a copy of the buffer is done and managed internally. Otherwise, the buffer is not copied and the user is responsible for its destruction.

Resizing facilities

void resize(const __ndbuffer_image &other, image_build_params params)
void resize(int width, const image_build_params& = {})
void resize(int width, int height, const image_build_params& = {})
void resize(int width, int height, int depth, const image_build_params& = {})
void resize(ConstBoxRef domain, const image_build_params& = {})

See the corresponding contructors. These functions allow an image to be default-constructed and resized afterward.

Note

A new buffer is allocated. If a buffer was already attached to the image and this is the last reference, the memory is reclaimed.

Geometry information

int pdim() const noexcept

Get the number of dimensions of the image

int width() const noexcept

Get the width of the image.

int height() const noexcept

Get the height of the image. Returns 1 if the image is 1D.

int depth() const noexcept

Get the depth of the image. Returns 1 if the image is 1D or 2D.

int size(int dim = 0) const noexcept

Get the number of elements in the given dimension. Returns 1 if dim >= pdim().

int border() const noexcept

Get the size of the border.

ndbox<N> domain() const noexcept

Get the domain of the image.

Data and layout information

sample_type_id sample_type() const noexcept

Get the sample type of the data.

T *buffer() const noexcept

Get a pointer to first element (in the domain).

std::ptrdiff_t byte_stride(int dim = 1) const noexcept

Get the stride (in bytes) between two consecutive elements in the given dim.

std::ptrdiff_t stride(int dim = 1) const noexcept

Get the stride (in number of elements) between two consecutive elements in the given dim.

index_type index_of_point(ndpoint<N> p) const noexcept

Get the linear index (offset in the buffer) of multi-dimensional point.

ndpoint<N> point_at_index(index_type i) const noexcept

Get the point corresponding to the given index.

index_type delta_index(ndpoint<N> p) const noexcept

Get the linear index offset for the given point.

Slicing & clipping operations

[[when N = 3]] image2d<T> slice(int z) const noexcept

Return the slice at coordinate z in the 3th dimension.

exceptions: std::runtime_error if z is invalid

[[when N = 2]] image1d<T> row(int y) const noexcept

Return the row at coordinate y in the 2nd dimension.

exceptions: std::runtime_error if y is invalid

__ndbuffer_image clip(ndbox<N> roi) const

Return the image restricted to the ROI roi. roi must be included in the domain.

Except:

std::runtime_error if domain().includes(roi) is false or dimensions mismatch.

Data accessors

const T &operator()(ndpoint<N> p) const noexcept
T &operator()(ndpoint<N> p) noexcept

Returns a reference to the element at p.

Precondition: this->domain().has(p)

const T &at(ndpoint<N> p) const noexcept
T &at(ndpoint<N> p) noexcept

Returns a reference to the element at p. p can be in the extension.

Precondition: p belongs to the extended domain.

const T &operator[](index_type i) const noexcept
T &operator[](index_type i) noexcept

Returns a reference to the element at index i.

Precondition: i must be a valid index.

Iteration

auto values() const
auto values()

Returns a range to iterate on image values.

auto pixels() const
auto pixels()

Return a range to iterate on image pixels.