Analyze your Composite
When receiving a composite from a camera, its content may not be immediately known. Therefore, you should analyze the composite first:
#include <iostream>
#include <cvb/composite.hpp>
#include <cvb/point_cloud.hpp>
if (composite->
Purpose() == Cvb::CompositePurpose::PointCloud)
std::cout << "Purpose of composite is PointCloud.\n";
for (
int k = 0; k < composite->
ItemCount(); k++)
{
auto compositeVariant = composite->
ItemAt(k);
{
std::cout << "ItemAt(" << k << ") is a PlaneEnum.\n";
for (int i = 0; i < item->PlaneCount(); i++)
{
if (item->Plane(i)->Role() == Cvb::PlaneRole::CoordCartesian_X)
std::cout << " Plane(" << i << ") contains X component.\n";
else if (item->Plane(i)->Role() == Cvb::PlaneRole::CoordCartesian_Y)
std::cout << " Plane(" << i << ") contains Y component.\n";
else if (item->Plane(i)->Role() == Cvb::PlaneRole::CoordCartesian_Z)
std::cout << " Plane(" << i << ") contains Z component.\n";
}
}
{
std::cout << "ItemAt(" << k << ") is a Plane.\n";
if (item->Role() == Cvb::PlaneRole::PixConfidence)
std::cout << " Plane is a confidence plane.\n";
}
std::cout << "ItemAt(" << k << ") is an Image.\n";
std::cout << "ItemAt(" << k << ") is a PFNCBuffer.\n";
std::cout << "ItemAt(" << k << ") is a Buffer.\n";
std::cout << "ItemAt(" << k << ") is a Handle.\n";
}
CompositeVariant ItemAt(int index) const
int ItemCount() const noexcept
CompositePurpose Purpose() const noexcept
const variant_alternative_t< I, variant< TS... > > & get(const variant< TS... > &var)
bool holds_alternative(const variant< TS... > &var) noexcept
using (var composite = ...)
{
Console.WriteLine("Purpose of composite is PointCloud");
for (int k = 0; k < composite.Count; k++)
{
var item = composite[k];
{
Console.WriteLine("Item[" + k + "] is a PlaneEnum.");
{
Console.WriteLine(" Plane(" + i + ") contains X component.");
Console.WriteLine(" Plane(" + i + ") contains Y component.");
Console.WriteLine(" Plane(" + i + ") contains Z component.");
}
}
{
Console.WriteLine("Item[" + k + "] is a Plane.");
Console.WriteLine(" Plane is a confidence plane.");
}
Console.WriteLine("Item[" + k + "] is an Image.");
Console.WriteLine("Item[" + k + "] is a PfncBuffer.");
Console.WriteLine("Item[" + k + "] is an IBuffer.");
else
Console.WriteLine("Item[" + k + "] is a Handle.");
}
}
(1) The composite's purpose is checked. When working with 3D area scan cameras, it should be Cvb::CompositePurpose::PointCloud
.
(2) All composite items are iterated over in a loop and retrieved.
(3) A Cvb::PlaneEnumerator
item contains the X, Y, and Z planes.
(4) All planes are iterated over in a loop and their roles are checked.
(5) The confidence plane may be part of a Cvb::PlaneEnumerator
or a separate Cvb::Plane
.
(6) In order to verify, if the plane is a confidence plane the plane's role is checked.
(7) Composites may include additional data, such as images, stored as Cvb::Image
items.
(8)-(10) Other types of data can be stored in more generic structures like Cvb::PFNCBuffer
, Cvb::Buffer
, or Cvb::HandleOnly
.
After analyzing the composite, you will understand what data it contains and determine the appropriate approach for accessing it. If you only need access to X, Y, Z, confidence, and possibly image values, the best approach is to convert the Cvb::Composite
to a Cvb::PointCloud
, which provides the easiest way to access the data and outlined in section Convert a Composite to a Point Cloud.
If your composite contains additional data beyond those mentioned above, you will need to access the data in a generic way.
Convert a Composite to a Point Cloud
- Note
- To take advantage of the more convenient methods described in the section Access to Simple Point Clouds, it is recommended to convert a Composite into a Point Cloud whenever possible, as outlined in this section.
If you only need access to the X, Y, Z, and optional confidence values, you can simply convert the Cvb::Composite
into a Cvb::PointCloud
:
static std::shared_ptr< T > FromComposite(CompositePtr object)
static PointCloud FromComposite(Composite obj)
If you also need to access additional data via Cvb::PointCloud
such as images, you must first convert them into individual planes and append them to the composite, as shown below:
std::cout << "Initial number of planes: " << cloud->NumPoints() << "\n";
int idx = ...;
std::cout << "Number of planes: " << cloud->NumPoints() << "\n";
void InsertItemAt(int index, const CompositeVariant &item)
static PlanePtr FromImagePlane(const ImagePlane &imagePlane, PlaneRole role=PlaneRole::Undefined)
Console.WriteLine("Initial number of planes: " + cloud.Planes.Count);
int idx = 2;
var rgbImage = composite[idx] as
Image;
composite.Insert(composite.Count, rPlane);
composite.Insert(composite.Count, gPlane);
composite.Insert(composite.Count, bPlane);
Console.WriteLine("Number of planes: " + cloud.Planes.Count);
static Plane FromImagePlane(ImagePlane imagePlane, PlaneRole role)
(1) Set the correct index for the RGB image item. This can be determined by analyzing the composite.
(2) Retrieve Cvb::Image
item from the composite.
(3) Convert Cvb::ImagePlane
objects to Cvb::Plane
objects.
(4) Append the planes to the composite. Note, that the underlying buffer is not copied.
(5) The Cvb::PointCloud
now contains three additional planes compared to its initial state.
For streaming 3D point clouds that include additional data and converting them to Cvb::PointCloud
, refer to the example Point Cloud Acquisition.
Generic Access to Composite
If, after analyzing your composite, you find that it contains additional data beyond what was covered in the previous section, you need to access it in a more generic way. This can be done using the base pointer, increments, and the number of elements of an item. These parameters are available as member variables for planes in Cvb::PlaneEnumerator
and for Cvb::Plane
, Cvb::Image
, and Cvb::PFNCBuffer
items. They can be retrieved as follows:
auto item = ...;
auto dataType = item->DataType();
auto pBase = item->BasePtr();
auto rank = item->Rank();
auto xInc = item->Increment(0);
auto xLen = item->Length(0);
auto yInc = item->Increment(1);
auto yLen = item->Length(1);
var item = ...;
var dataType = item.DataType;
var pBase = (byte*)item.BasePtr;
var rank = item.Rank;
var xInc = (int)item.GetIncrement(0);
var xLen = (int)item.GetLength(0);
var yInc = (int)item.GetIncrement(1);
var yLen = (int)item.GetLength(1);
(1) Retrieve item. It must be either a Cvb::Plane
, Cvb::Image
, of Cvb::PFNCBuffer
.
(2) Get the data type, which is needed to correctly cast the accessed values.
(3) Retrieve base pointer to item.
(4) Get the rank of the item. Cvb::Image
and Cvb::DensePointCloud
typically have a rank of 2, whereas Cvb::SparsePointCloud
has a rank of 1.
(5) Retrieve X-axis increment.
(6) Get the number of elements along the X-axis.
(7) If rank==2
, retrieve the Y-axis increment and length as well.
Once these parameters are obtained, the data can be accessed as follows:
using Type = float;
assert(dataType.Matches<Type>());
for (int y = 0; y < yLen; y++)
{
auto *pLine = pBase + y * yInc;
for (int x = 0; x < xLen; x++)
{
auto *pPoint = pLine + x * xInc;
auto point = *reinterpret_cast<T *>(pPoint);
}
}
unsafe
{
if (!dataType.IsFloat)
Console.WriteLine("Values of composite item are not float.");
for (int y = 0; y < yLen; y++)
{
var pLine = pBase + y * yInc;
for (int x = 0; x < xLen; x++)
{
var pValue = pLine + x * xInc;
var value = *(float*)pValue;
Console.WriteLine(x + "," + y + ": " + value);
}
}
}
(1) Use the appropriate Type
for the accessed values.
(2) Ensure that Type
matches the data type of the item.
(3) Loop through all elements along the Y dimension (only if rank==2
).
(4) Get a pointer to next row.
(5) Loop through all elements along the X dimension.
(6) Get a pointer to next element.
(7) Cast the value to the appropriate type.
Note, that if rank==1
, only the inner loop over X-axis is required.
Custom data formats that cannot be represented by standard CVB classes such as Cvb::Image
or Cvb::PointCloud
can be converted to a Cvb::PFNCBuffer
. This process is outlined in the section Reinterpreting Images as PFNC Buffer.
- Note
- There are more convenient methods for accessing images, which are recommended. For details, see sections Image Pixel Access in C++ Image Pixel Access in .NET.
Examples and Further Reading
Point Cloud Stream
Composite Stream
Image Pixel Access in C++
Image Pixel Access in .NET
Code Example (C++): Point Cloud Acquisition
Code Example (C++, .NET): Reinterpreting Images as PFNC Buffer