Common Vision Blox 15.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Friends Modules Pages
Image Pixel Access in C++

In CVB C++, there are multiple ways to access pixel data:

Fast Linear Access

When an image is stored in a contiguous memory layout, pixels can be accessed most efficiently through array access, which allows for direct memory access without any gaps between rows. To achieve this optimal access pattern, it is recommended to use array access whenever possible, as demonstrated in the following code example:

#include <cvb/image.hpp>
#include <cvb/image_plane.hpp>
// Create a mono image.
using PixelType = std::uint16_t;
int width = 16, height = 4;
auto image = Cvb::Image::Create(width, height, 1, Cvb::DataType::FromNativeType<PixelType>()); // (1)
// Get array access on contiguous image planes.
auto arrayAccess = Cvb::ArrayAccess::FromPlane(image->Plane(0)); // (2)
if (arrayAccess.Valid()) // (3)
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
PixelType *pPixel = reinterpret_cast<PixelType *>(arrayAccess(x, y)); // (4)
}
}
}
static ArrayAccess FromPlane(const PLANE_T &plane) noexcept
static DataType FromNativeType() noexcept
static std::unique_ptr< Image > Create(Size2D< int > size, int numPlanes=1, DataType dataType=DataType::Int8BppUnsigned())

(1) A monochrome 16-bit unsigned image is created. For monochrome images, the Create function generates an image with a contiguous layout.
(2) Array access is obtained for the first (contiguous) image plane.
(3) If the array access object is valid (i.e., array access was successful), proceed with pixel access.
(4) arrayAccess(x, y) returns a void pointer to the pixel. Cast it to the correct type.

If array access is not available, the next best option is to use linear access:

// Get linear access to the image plane.
Cvb::LinearAccessData linearAccess;
if (image->Plane(0).TryLinearAccess(linearAccess))
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
PixelType *pPixel = reinterpret_cast<PixelType *>(linearAccess(x, y));
}
}
}

If neither array access nor linear access is possible, the last resort is to use the slowest method: accessing the image via VPAT.

General Access with VPAT

When neither array access nor linear access is available, the next option is to access the image through the slower method: VPAT-based access, as described in VPAT Memory Layout.

auto vpat = image->Plane(0).Vpat(); // (1)
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
PixelType *pPixel = reinterpret_cast<PixelType *>(vpat(x, y)); // (2)
}
}

(1) Obtain VPA table.
(2) vpat(x, y) returns a void pointer to the pixel. Cast it to the correct type.

Other Access Methods

Pixel Access Using Iterators

CVB provides iterators for each access type, allowing you to iterate over pixel data efficiently. The following code snippet demonstrates how to use iterators with different access methods:

// Get pixel access via iterators.
std::uint8_t *pBase = nullptr;
Cvb::LinearAccessData linearAccess;
if (image->Plane(0).TryContiguousAccess(pBase)) // (1)
{
for (auto it = image->Plane(0).BeginContiguous<PixelType>(); it != image->Plane(0).EndContiguous<PixelType>(); it++)
PixelType value = *it;
}
else if (image->Plane(0).TryLinearAccess(linearAccess)) // (2)
{
for (auto it = image->Plane(0).BeginLinear<PixelType>(); it != image->Plane(0).EndLinear<PixelType>(); it++)
PixelType value = *it;
}
else // (3)
{
for (auto it = image->Plane(0).BeginVpat<PixelType>(); it != image->Plane(0).EndVpat<PixelType>(); it++)
PixelType value = *it;
}

(1) First, attempt to obtain the most efficient contiguous access and use iterators to traverse the pixels in contiguous memory.
(2) If contiguous access is unavailable, attempt linear access and use iterators for linear iteration.
(3) If both fast access methods fail, iterators can be used for VPAT access, the slowest method.

Flexible and Fast Pixel Access with Cvb::Visit

In practice, your code may need to support different data types and memory layouts. To minimize the overhead of handling these variations, CVB++ provides modern C++ infrastructure that enables you to write algorithms only once. The most efficient access pattern (contiguous > linear > vpat) is automatically selected. This can be achieved using Cvb::Visit(), which provides an efficient and convenient way to access images and point clouds.

Note
This approach is described in detail in section Efficiently Writing Image and Point Cloud Algorithms Using Visit.

The following example demonstrates a simple case of visiting a single image plane using a lambda function. More advanced examples, including the use of function objects and simultaneous access to multiple planes, can be found in Efficiently write image and point cloud algorithms using Visit.

#include <cvb/block.hpp>
auto image = ...;
// pixel access using a lambda function and Cvb::Visit()
Cvb::Visit([](auto block)
{
// loop over whole image
for (int y = 0; y < block.Height(); ++y) {
for (int x = 0; x < block.Width(); ++x) {
block(x, y) /= 2; // divide pixel value by 2
}
}
}
, image->Plane(0));

Cvb::Vist takes one or more image planes as input, along with a lambda function or a function object that defines the operation to be performed on each image pixel. The only requirement is that the lambda function must be able to handle a Cvb::Block object.