Common Vision Blox 15.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Friends Modules Pages
Access to Simple Point Clouds in C++ and .NET

This section explains how to access data from the CVB point cloud classes in C++ and .NET:

For more details on the concept behind the CVB point cloud classes, please refer to the section CVB Point Cloud.

Accessing Point Cloud Data via Pointers

This section describes a generic approach to accessing point cloud data. However, C++ offers more convenient, flexible and recommended methods for data access, outlined in section C++: Flexible and Fast Pixel Access with Cvb::Visit.

An easy way to access point cloud values is using a pointer to a 3D point structure in C++ or an array created from an enumeration in .NET:

#include <cvb/point_cloud.hpp>
using PointType = float;
auto cloud = ...;
// Get pointer to 3D points.
Cvb::Point3D<PointType> *pPoints = nullptr; // (1)
cloud->Points(pPoints);
auto end = pPoints + cloud->NumPoints();
// Loop over all points.
for (auto it = pPoints; it != end; it++)
{
auto X = it->X(); // (2)
auto Y = it->Y();
auto Z = it->Z();
}

using (var cloud = ...)
{
// Try to get array to points.
var points = cloud.TryEnumeratePointsAs<Point3Df>().ToArray(); // (1)
// Loop over all points.
for (int i = 0; i < cloud.NumPoints; i++)
{
var X = points[i].X; // (2)
var Y = points[i].Y;
var Z = points[i].Z;
}
}

(1) The pointer to the 3D points is obtained in C++, while in .NET, the points are retrieved as an array from an enumeration.
(2) X, Y, and Z values are accessed through this pointer in C++ or via indexed access in .NET. Note that in .NET, point data can be read but not modified here.

Alternatively point clouds can be access via the base pointers and increments as demonstrated in the following example:

Cvb::PointCloud cloud = ...;
// Get number of points.
auto nPoints = cloud->NumPoints();
// Get point cloud components for accessing point cloud values.
auto components = cloud->PointComponents<Cvb::Point3D<PointType>>(); // (1)
// Get base pointers.
auto pPointX = components.BasePtrX();
auto pPointY = components.BasePtrY();
auto pPointZ = components.BasePtrZ();
// Get increments.
auto xInc = components.XInc();
auto yInc = components.YInc();
auto zInc = components.ZInc();
// Loop over all points.
for (int i = 0; i < nPoints; i++)
{
auto X = *reinterpret_cast<PointType *>(pPointX); // (2)
auto Y = *reinterpret_cast<PointType *>(pPointY);
auto Z = *reinterpret_cast<PointType *>(pPointZ);
// Increment pointer.
pPointX += xInc; // (3)
pPointY += yInc;
pPointZ += zInc;
}

using (var cloud = ...)
{
// Get number of points.
var nPoints = cloud.NumPoints;
// Get point cloud components for accessing point cloud values.
var components = cloud.PointComponents; // (1)
// Get increments.
var xInc = (int)components.X.Increment;
var yInc = (int)components.Y.Increment;
var zInc = (int)components.Z.Increment;
unsafe
{
// Get base pointers.
var pPointX = (byte*)components.X.BasePtr;
var pPointY = (byte*)components.Y.BasePtr;
var pPointZ = (byte*)components.Z.BasePtr;
// Loop over all points.
for (int i = 0; i < nPoints; i++)
{
var X = *(float*)pPointX; // (2)
var Y = *(float*)pPointY;
var Z = *(float*)pPointZ;
// Increment pointer.
pPointX += xInc; // (3)
pPointY += yInc;
pPointZ += zInc;
}
}
}

(1) The base pointers and increments for each component (in this case X, Y, and Z) are retrieved.
(2) X, Y, and Z values are accessed via these pointers and casted correctly.
(3) The pointers are incremented accordingly.

Note, that for organized (dense) point clouds you can iterate over width and height instead of the total number of points, too:

// Get width and height of organized dense point cloud.
auto width = cloud->LatticeSize().Width(); // (1)
auto height = cloud->LatticeSize().Height();
// Get point cloud components for accessing point cloud values.
auto components = cloud->PointComponents<Cvb::Point3D<float>>(); // (2)
// Get base pointers.
auto pBaseX = components.BasePtrX();
auto pBaseY = components.BasePtrY();
auto pBaseZ = components.BasePtrZ();
// Get increments.
auto xInc = components.XInc();
auto yInc = components.YInc();
auto zInc = components.ZInc();
// Loop over grid in Y direction.
for (int y = 0; y < height; y++) // (3)
{
auto pLineX = pBaseX + y * width * xInc; // (4)
auto pLineY = pBaseY + y * width * yInc;
auto pLineZ = pBaseZ + y * width * zInc;
// Loop over grid in X direction.
for (int x = 0; x < width; x++)
{
auto pPointX = pLineX + x * xInc; // (5)
auto pPointY = pLineY + x * yInc;
auto pPointZ = pLineZ + x * zInc;
auto X = *reinterpret_cast<PointType *>(pPointX); // (6)
auto Y = *reinterpret_cast<PointType *>(pPointY);
auto Z = *reinterpret_cast<PointType *>(pPointZ);
}
}

using (DensePointCloud cloud = ...)
{
// Get width and height of organized dense point cloud.
var width = cloud.LatticeSize.Width; // (1)
var height = cloud.LatticeSize.Height;
// Get point cloud components for accessing point cloud values.
var components = cloud.PointComponents; // (2)
// Get increments.
var xInc = (int)components.X.Increment;
var yInc = (int)components.Y.Increment;
var zInc = (int)components.Z.Increment;
unsafe
{
// Get base pointers.
var pBaseX = (byte*)components.X.BasePtr;
var pBaseY = (byte*)components.Y.BasePtr;
var pBaseZ = (byte*)components.Z.BasePtr;
// Loop over grid in Y direction.
for (int y = 0; y < height; y++) // (3)
{
var pLineX = pBaseX + y * width * xInc; // (4)
var pLineY = pBaseY + y * width * yInc;
var pLineZ = pBaseZ + y * width * zInc;
// Loop over grid in X direction.
for (int x = 0; x < width; x++)
{
var pPointX = pLineX + x * xInc; // (5)
var pPointY = pLineY + x * yInc;
var pPointZ = pLineZ + x * zInc;
var X = *(float*)pPointX; // (6)
var Y = *(float*)pPointY;
var Z = *(float*)pPointZ;
}
}
}
}
ComponentsPointer3D PointComponents

(1) Get width and height of dense point cloud.
(2) The base pointers and increments for each component (in this case X, Y, and Z) are retrieved.
(3) Loop over grid of cloud.
(4) Get pointer to next line.
(5) Get pointer to next element.
(6) X, Y, and Z values are accessed via these pointers and casted correctly.

C++: Flexible and Fast Pixel Access with Cvb::Visit

The Cvb::Visit function provides the fastest and most flexible way to access point cloud data. It allows you to write algorithms only once independently of the data type and memory layout.

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

The following example demonstrates how to process a simple point cloud using a lambda function. More advanced examples, including the use of function objects and simultaneous access to additional planes, can be found in Efficiently Write Image and Point Cloud Algorithms Using Visit.

#include <cvb/point_cloud.hpp>
#include <cvb/block.hpp>
auto cloud = ...;
// Pixel access using a lamda 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)
{
auto X = block(x, y).X();
auto Y = block(x, y).Y();
auto Z = block(x, y).Z();
}
}
},
*cloud);

Examples and Further Reading

Point Cloud Concept
Point Cloud Stream
Code Example (C++): Point Cloud Acquisition