TensorPool, Image & PointCloud API

HORUS provides zero-copy shared memory pools for large data: camera frames, lidar scans, and neural network tensors. Data lives in a pre-allocated SHM region and is passed between nodes by reference -- no serialization, no copies.

#include <horus/pool.hpp>

Architecture

The pool system has four classes arranged in a hierarchy:

ClassPurpose
TensorPoolManages a shared memory region with fixed-size slots
TensorRaw N-dimensional array allocated from a pool
ImageCamera frame with width, height, and pixel encoding
PointCloudLidar scan with per-point fields (XYZ, intensity, color)

Image and PointCloud are convenience wrappers over pool-backed memory. When you publish any pool-backed type on a topic, subscribers get a pointer into the same SHM region -- zero copies.


TensorPool

A fixed-size shared memory region divided into allocation slots.

Constructor

horus::TensorPool pool(
    uint32_t pool_id,         // unique pool identifier
    size_t   pool_size_bytes, // total SHM region size
    size_t   max_slots        // maximum concurrent allocations
);

Parameters

NameTypeDescription
pool_iduint32_tUnique identifier for this pool. Must not collide with other pools in the same system.
pool_size_bytessize_tTotal size of the SHM-backed memory region in bytes.
max_slotssize_tMaximum number of tensors/images/point clouds that can be allocated simultaneously.

Example

// 16 MB pool with up to 64 concurrent allocations
auto pool = horus::TensorPool(1, 16 * 1024 * 1024, 64);

stats()

Returns current pool utilization.

TensorPool::Stats stats() const;

Returns a Stats struct:

FieldTypeDescription
allocatedsize_tNumber of active allocations
used_bytessize_tBytes currently in use
free_bytessize_tBytes available for allocation
auto s = pool.stats();
horus::log::info("pool", ("used: " + std::to_string(s.used_bytes) +
    " free: " + std::to_string(s.free_bytes)).c_str());

Ownership and Validity

TensorPool is move-only -- copy construction and copy assignment are deleted. Use explicit operator bool() to check if the pool handle is valid:

auto pool2 = std::move(pool);  // OK -- transfers ownership
if (!pool2) {
    horus::log::error("init", "Failed to create tensor pool");
}

Tensor

A raw N-dimensional array allocated from a TensorPool.

Constructor

horus::Tensor tensor(
    const TensorPool& pool,     // pool to allocate from
    const uint64_t*   shape,    // dimension sizes array
    size_t            ndim,     // number of dimensions
    Dtype             dtype     // element data type
);

Parameters

NameTypeDescription
poolconst TensorPool&Pool to allocate from. Must remain valid for the tensor's lifetime.
shapeconst uint64_t*Array of dimension sizes. Length must equal ndim.
ndimsize_tNumber of dimensions (rank of the tensor).
dtypeDtypeElement data type. See Dtype enum below.

Methods

MethodReturnDescription
data()uint8_t*Raw pointer to tensor memory. Cast based on dtype.
nbytes()uint64_tTotal size in bytes (product of dimensions * element size).
release()voidReturns the slot to the pool early. Called automatically on destruction.

Dtype Enum

Element data types for tensors.

enum class Dtype : uint8_t {
    F32,   // 32-bit float
    F64,   // 64-bit float
    U8,    // unsigned 8-bit integer
    I32,   // signed 32-bit integer
};
VariantSizeUse Case
Dtype::F324 bytesNeural network weights, sensor readings
Dtype::F648 bytesHigh-precision computation
Dtype::U81 byteImage pixels, raw byte buffers
Dtype::I324 bytesInteger indices, counters

Image

A camera frame with width, height, and pixel encoding, backed by pool memory.

Constructor

horus::Image img(
    const TensorPool& pool,
    uint32_t          width,
    uint32_t          height,
    Encoding          enc = Encoding::Rgb8  // optional, defaults to RGB8
);

Parameters

NameTypeDescription
poolconst TensorPool&Pool to allocate from.
widthuint32_tImage width in pixels.
heightuint32_tImage height in pixels.
encEncodingPixel encoding format. Defaults to Encoding::Rgb8.

Methods

MethodReturn TypeDescription
width()uint32_tImage width in pixels
height()uint32_tImage height in pixels
data_size()size_tTotal image data size in bytes (width * height * bytes_per_pixel)

Encoding Enum

Pixel encoding formats for images.

enum class Encoding : uint8_t {
    Rgb8,    // 3 bytes per pixel: red, green, blue
    Rgba8,   // 4 bytes per pixel: red, green, blue, alpha
    Gray8,   // 1 byte per pixel: grayscale
    Bgr8,    // 3 bytes per pixel: blue, green, red (OpenCV default)
};
VariantBytes/PixelUse Case
Encoding::Rgb83Standard color images
Encoding::Rgba84Images with transparency
Encoding::Gray81Depth maps, IR images, edge detection output
Encoding::Bgr83OpenCV-native format, avoids channel swap

PointCloud

A lidar scan or 3D point set, backed by pool memory.

Constructor

horus::PointCloud pc(
    const TensorPool& pool,
    uint32_t          num_points,
    uint32_t          fields_per_point
);

Parameters

NameTypeDescription
poolconst TensorPool&Pool to allocate from.
num_pointsuint32_tNumber of points in the cloud.
fields_per_pointuint32_tFloats per point: 3 = XYZ, 4 = XYZI, 6 = XYZRGB.

Methods

MethodReturn TypeDescription
num_points()uint64_tNumber of points in the cloud
fields_per_point()uint32_tNumber of float fields per point

Common Field Layouts

FieldsLayoutUse Case
3X, Y, ZBasic geometry
4X, Y, Z, IntensityLidar with reflectance
6X, Y, Z, R, G, BColored point cloud

Example: Camera Pipeline

A camera node that captures frames and publishes them over a zero-copy topic.

#include <horus/node.hpp>
#include <horus/pool.hpp>

auto pool = horus::TensorPool(1, 32 * 1024 * 1024, 32);
auto cam_topic = horus::Topic<horus::Image>("camera.rgb");

// Inside tick():
auto frame = horus::Image(pool, 1280, 720, horus::Encoding::Rgb8);
if (frame) {
    // Fill frame data from hardware driver...
    // data_size() = 1280 * 720 * 3 = 2,764,800 bytes
    cam_topic.send(std::move(frame));
    // Subscriber receives a pointer into the same SHM -- zero copies
}

Example: Neural Network Tensor

#include <horus/pool.hpp>

auto pool = horus::TensorPool(2, 64 * 1024 * 1024, 16);

// Allocate a [1, 3, 224, 224] input tensor for a vision model
uint64_t shape[] = {1, 3, 224, 224};
auto input = horus::Tensor(pool, shape, 4, horus::Dtype::F32);

if (input) {
    float* data = reinterpret_cast<float*>(input.data());
    // Fill with preprocessed image data...
    // nbytes() = 1 * 3 * 224 * 224 * 4 = 602,112 bytes
}

Pool Sizing Guidelines

WorkloadPool SizeMax SlotsRationale
Single 720p camera16 MB8~2.7 MB per frame, triple-buffered with headroom
Stereo 1080p cameras64 MB16~6.2 MB per frame, two cameras, pipeline depth
16-beam lidar8 MB16~120 KB per scan at 30K points
NN inference batch64 MB16Depends on model input/output sizes

Overallocating pool size is safe -- unused SHM is not committed to physical memory on Linux. Underallocating max_slots causes allocation failures when the pipeline is full.