| Header | Description |
|---|---|
| Project | VHLibOptimal |
| Description | C++17 library for shape contour detection and image outline recognition |
| Current Version | 0.7.5-beta (2026) |
| Development started | 2006 |
| Major C++17 rewrite | started in early 2026 |
| Author | V01G04A81 / Viktor Glebov |
| License | MIT |
| Source code | https://github.com/vigatron/vhliboptimal |
A high-performance C++17 library for fast shape contour detection and image outline recognition using optimized grid-based scanning.

Historical reference: The 2016 FPGA-based stereo vision system that proved the algorithm’s real-time viability on dual-camera setups.
The core algorithm, originally developed in 2006, received a complete modern C++17 rewrite in 2026. This version brings a clean object-oriented interface for single-camera Single Board Computer setups while preserving two decades of embedded efficiency lessons.
vhliboptimal is a high-performance C++ library for fast shape contour detection and image outline recognition.
Originally developed in plain C (starting in 2006) for commercial embedded projects on ARM and AVR platforms.
Later evolved through an FPGA-accelerated era (2016).
It has been completely modernized in 2026 with a clean object-oriented C++ interface while preserving its efficiency-focused philosophy.
It uses an optimized grid-based approach: the image is divided into a configurable Cells Matrix, and connectivity is tracked using compact BitFields.
This design delivers excellent performance with very low memory and CPU usage, making it ideal for embedded systems and real-time applications.
Unlike general-purpose computer vision frameworks such as OpenCV, vhliboptimal focuses exclusively on contour extraction and therefore remains lightweight and easy to integrate.
It excels at processing binary or high-contrast images and gracefully handles small gaps and noise thanks to tunable parameters.
srcimgidThe examples below demonstrate how vhliboptimal is utilized within a real-world road sign recognition application.
In this specific pipeline, the library is responsible exclusively for the high-speed, deterministic extraction of shape contours and internal spans from pre-processed frames. The extracted geometric data is then passed to a higher-level classification module.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note: Original image processed at 1080p (contains > 2000 character objects). Only positions and sizes are extracted — content is not recognized.
The vhliboptimal library has deep roots in real-world embedded computer vision, evolving from extreme hardware constraints to modern software efficiency.
The algorithm originated as a raster-to-vector engine for 8-bit AVR microcontrollers, initially tasked with recognizing character contours and geometric shapes on tiny 128x64 B&W displays. To handle image processing under severe memory constraints, the system utilized 32KB of external SRAM accessed via a multiplexed bus (74HC573 + ALE). The core engineering challenge was overcoming the performance bottleneck of this external memory bus.
The grid-based BitField architecture was specifically designed during this period to minimize external bus accesses, keeping the heavy pathfinding logic strictly within the MCU’s fast internal RAM. It was successfully tested on LPC2148 and AT91SAM7X256 platforms.
As tasks grew more complex, the algorithm was scaled and integrated into a dual-camera stereo vision system based on a Xilinx Spartan-6 FPGA + SDRAM, paired with an STM32F7 microcontroller.
The library has been completely redesigned and rewritten from the ground up in modern C++17.
cellsize, and scene complexity). This makes it highly suitable for edge-AI, robotics, and automated sorting tasks on widely available commodity hardware.It preserves the original philosophy of extreme efficiency born on 8-bit microcontrollers nearly 20 years ago, now running efficiently on general-purpose CPUs with AVX2 optimizations where available.
vhlibplatform — a lightweight cross-platform layer providing base primitive types, assertions, error handling, and system abstractions.cellsize typically 8-16px for real-time SBC profiles). Fine image details smaller than the configured cell size will be intentionally lost to preserve CPU cycles.⚠️ Best Practices for Optimal Results
The algorithm was originally proven on pristine, uncompressed RAW video streams. When using modern compressed sources (e.g., MJPEG/MP4 webcams on SBCs), compression artifacts and blurring can degrade contour accuracy.Recommendation: For best results, apply a lightweight pre-processing step (e.g., hardware-accelerated thresholding, sharpening, or edge-enhancement) before passing the frame to
vhliboptimal, or tuneminColorValandspccntto be more tolerant of digital noise.
Or:
stspan 8 bytesVHOptimalFigure 16 bytes| Parameter | Example #1 | Example #2 | Example #3 | Example #4 |
|---|---|---|---|---|
| Maximum number of figures | 128 | 128 | 128 | 128 |
| Cell size | 8 px | 4 px | 2 px | 1 px |
| Resolution | 800×600 | 800×600 | 800×600 | 800×600 |
| Cells per frame | 100×75 | 200×150 | 400×300 | 800×600 |
| Bitmask (bits) | 7500 | 30000 | 120000 | 480000 |
| Bitmask (bytes) | 938 | 3750 | 15000 | 60000 |
| ×2 bitmasks (Global + Local) | 1876 | 7500 | 30000 | 120000 |
| Memory (Worst case) | 60000 bytes | 240000 bytes | 960000 bytes | 3840000 bytes |
| Memory (Typical) | 16000 bytes | 64000 bytes | 240000 bytes | 960000 bytes |
| +128 figures × 16 | 2048 bytes | 2048 bytes | 2048 bytes | 2048 bytes |
The library operates completely abstracted from raw graphic decoders or UI frameworks (like OpenCV or stb_image). It processes data streams through an abstract coordinate grid:
CellsMatrix: Manages the spatial geometry of the grid. Images are analyzed in configurable blocks (cellsize), decreasing overall data dimensionality.BitField: A packed bit array tracking filled/empty cells. The algorithm utilizes a dual-bitmask architecture: a global mask for the entire frame (from which figures are extracted) and a local mask dedicated to tracking the traversal state of the specific figure currently being processed. This eliminates the need for heavy graph data structures and keeps memory access highly predictable.VHOptimalFigure: Encapsulates a single extracted shape, containing its bounding box, sorted sequential contours, and analytical span strings.src/vhliboptimalstructs.hpp)stConfig — Scanning parameters (image boundaries, grid cell size, color thresholding tolerance minColorVal, and spccnt which defines the maximum consecutive empty cells allowed before breaking a span).strect — Bounding box structure representation (x1, y1 to x2, y2).stspan — Horizontal/vertical segments representing the continuous boundaries of a shape.The library is completely decoupled from image sources and result processing.
1. CallbackGetSrcPxls — Fetch source image pixels
/**
* CallbackGetSrcPxls - Read a horizontal line of pixels from source image
*
* @param userData User context pointer (passed through from Setup)
* @param dstptr Destination buffer to fill
* @param bytescnt Number of bytes to read
* @param srcid Source image ID
* @param srcx Starting X coordinate
* @param srcy Starting Y coordinate
*/
typedef void (*CallbackGetSrcPxls)(void *userData, uint8_t *dstptr,
uint16_t bytescnt, uint16_t srcid,
uint16_t srcx, uint16_t srcy);
2. CallbackBorder — Process figure border (contour)
/**
* CallbackBorder - Called during border tracing of a detected shape
*
* @param userData User context pointer
* @param cmd Command: cmdStart / cmdMove / cmdStop
* @param dirh Horizontal direction
* @param dirv Vertical direction
* @param cellx Cell X coordinate
* @param celly Cell Y coordinate
* @param imgx Image X coordinate (pixels)
* @param imgy Image Y coordinate (pixels)
*/
typedef void (*CallbackBorder)(void *userData, uint8_t cmd, uint8_t dirh,
uint8_t dirv, uint16_t cellx, uint16_t celly,
uint16_t imgx, uint16_t imgy);
3. CallbackContent — Process horizontal spans inside the figure
/**
* CallbackContent - Called for each horizontal span inside the object
*
* @param userData User context pointer
* @param cell1 Left / Top cell index
* @param cell2 Right / Bottom cell index
* @param dir Direction 0: LR 1: UD
*/
typedef void (*CallbackContent)(void *userData, uint32_t cell1, uint32_t cell2, uint8_t dir);
#include <iostream>
#include "vhliboptimal.hpp"
namespace vhliboptimal {
// Callback to fetch pixels from your framebuffer/camera
void MyGetPixels(void* userData, uint8_t* dstptr, uint16_t bytescnt,
uint16_t srcid, uint16_t srcx, uint16_t srcy) {
// TODO: Fill dstptr with real image data
// Example (dummy):
// std::memset(dstptr, 0, bytescnt); // all black
}
// Callback for shape border tracing
void MyBorderCallback(void* userData, uint8_t cmd, uint8_t dirh, uint8_t dirv,
uint16_t cellx, uint16_t celly, uint16_t imgx, uint16_t imgy) {
std::cout << "Border [cmd=" << (int)cmd
<< ", dir=" << (int)dirh << "/" << (int)dirv
<< "] cell(" << cellx << "," << celly
<< ") px(" << imgx << "," << imgy << ")\n";
}
// Callback for internal content spans
void MyContentCallback(void* userData, uint32_t cell1, uint32_t cell2, uint8_t dir) {
std::cout << "Content span: cells " << cell1 << " to " << cell2 << "\n";
}
} // namespace vhliboptimal
int main() {
using namespace vhliboptimal;
VHLibOptimal detector;
// 1. Configuration
stConfig cfg;
cfg.imageWidth = 800;
cfg.imageHeight = 600;
cfg.cellsize = 8; // Grid cell size in pixels
cfg.spccnt = 2; // Max consecutive empty cells (noise tolerance)
cfg.minColorVal = 128; // Brightness threshold
cfg.min_obj_width = 32;
cfg.min_obj_height = 32;
cfg.max_obj_width = 256;
cfg.max_obj_height = 256;
cfg.loglevel = vhliboptimal::LOG_LEVEL_BASE;
// 2. Setup with callbacks
verr result = detector.Setup(cfg,
MyGetPixels,
MyBorderCallback,
MyContentCallback);
if (result != vok) {
std::cerr << "Setup failed!" << std::endl;
return -1;
}
// 3. Run processing
result = detector.Run(0); // srcimgid = 0 (you can use multiple IDs)
if (result == vok) {
std::cout << "Scan completed successfully!\n";
std::cout << "Objects found: " << detector.GetObjectsCount() << "\n";
for (size_t i = 0; i < detector.GetObjectsCount(); ++i) {
const VHOptimalFigure& fig = detector.GetObject(i);
std::cout << " Figure " << i
<< ": " << fig.SpansCount() << " spans, "
<< "rect (" << fig.PosCells().x1 << ","
<< fig.PosCells().y1 << ") - ("
<< fig.PosCells().x2 << ","
<< fig.PosCells().y2 << ")\n";
}
}
return 0;
}
You might wonder: How does the modern C++ version compare to the 2016 FPGA implementation?
The answer lies in the fundamental difference between hardware pipelines and software execution when dealing with unpredictable branching during contour tracing.
Tracing irregular shapes creates chaotic control flow. Branch mispredictions (incurring a 15–25 cycle penalty on modern cores) and data-dependent bitwise operations on dynamic BitField indices create significant pipeline stalls. SIMD (AVX2/NEON) helps a lot during the initial grid scanning, but is nearly useless in the extraction and tracing phase.
The 2016 Spartan-6 implementation used a hardware Finite State Machine (FSM) and dedicated Block RAM (BRAM), evaluating neighbor states instantly with minimal latency and perfect determinism. Even running at a modest ~166 MHz, it achieved outstanding efficiency in the core loop.
The FPGA version utilized massive hardware parallelism, processing bitfields instantly via dedicated BRAM. The original FPGA implementation demonstrated that the algorithm maps efficiently to hardware because of its regular grid-based data flow and compact BitField representation.
The modern C++ implementation preserves the same memory-efficient architecture while targeting commodity CPUs and SBCs. However, transitioning to modern C++ on general-purpose CPUs introduces critical microarchitectural differences (cache hierarchy, memory walls, and heavy dependency on branch prediction).
While pure FPS on a 2022 laptop or an ARM SBC might currently seem lower than the dedicated 2016 hardware pipeline, the trade-off shifts the value to extreme maintainability, rapid integration, and deployment on low-cost single-board computers (like Orange Pi/Raspberry Pi) without requiring expensive custom FPGA tooling.
Thanks to aggressive grid downsampling, careful BitField design, and raw CPU clock speeds, the C++ version delivers practical real-time performance (depending on CPU, resolution, and scene complexity) on affordable SBCs.
It preserves the original philosophy of extreme efficiency born on 8-bit microcontrollers nearly 20 years ago, now running efficiently on general-purpose CPUs with AVX2 optimizations where available. While the 2016 FPGA version remains superior in raw tracing latency and absolute timing predictability, the 2026 rewrite brings that hard-earned efficiency to the modern software edge.
Test and benchmark project: vhliboptimal_test
A surviving header (.h) file of this original plain C implementation is preserved as a historical reference at electrolviv/optimal.
© 2006 – 2026 V01G04A81 / Viktor Glebov