100 lines
4.0 KiB
C
100 lines
4.0 KiB
C
/* Minimal downstream consumer of libstereo_bolt (C ABI only).
|
|
*
|
|
* This demo uses the PRODUCTION interface: raw IN-MEMORY frames handed to
|
|
* sb_process_bolt_module_buffers(). The library never receives a file path.
|
|
*
|
|
* To stand in for your camera SDK (which gives you Mono8 frames in RAM), it
|
|
* reads headerless raw Mono8 files (exactly width*height bytes) with plain
|
|
* fread() — no OpenCV, no image decoder. In production you skip the file and
|
|
* pass the camera buffer pointer directly.
|
|
*
|
|
* Make a .raw from a frame: just write the W*H grayscale bytes to disk
|
|
* (e.g. fwrite(mat.data, 1, W*H, f)) — no encoding.
|
|
*
|
|
* A convenience file-path entry (sb_process_bolt_module_files, reads .bmp/
|
|
* .tiff/.png) also exists for offline testing — see stereo_bolt/c_api.h.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "stereo_bolt/c_api.h"
|
|
|
|
static uint8_t* read_raw_mono8(const char* path, size_t nbytes) {
|
|
FILE* f = fopen(path, "rb");
|
|
if (!f) { fprintf(stderr, "cannot open %s\n", path); return NULL; }
|
|
uint8_t* buf = (uint8_t*)malloc(nbytes);
|
|
const size_t got = buf ? fread(buf, 1, nbytes, f) : 0;
|
|
fclose(f);
|
|
if (!buf || got != nbytes) {
|
|
fprintf(stderr, "%s: expected %zu bytes (W*H Mono8), got %zu\n", path, nbytes, got);
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 7) {
|
|
fprintf(stderr, "usage: %s <config.yaml> <left.raw> <right.raw> <width> <height> <expected_count>\n",
|
|
argv[0]);
|
|
fprintf(stderr, " left/right .raw = headerless Mono8, width*height bytes (a dumped camera frame).\n");
|
|
fprintf(stderr, " Exercises the in-memory interface sb_process_bolt_module_buffers (no file path\n");
|
|
fprintf(stderr, " reaches the library). width/height must equal config image.width/height.\n");
|
|
return 2;
|
|
}
|
|
const char* cfg = argv[1];
|
|
const char* lpath = argv[2];
|
|
const char* rpath = argv[3];
|
|
const int W = atoi(argv[4]);
|
|
const int H = atoi(argv[5]);
|
|
const int expected = atoi(argv[6]);
|
|
const size_t nbytes = (size_t)W * (size_t)H;
|
|
|
|
/* Obtain pixels in RAM (here from a .raw; in production from your camera SDK). */
|
|
uint8_t* L = read_raw_mono8(lpath, nbytes);
|
|
uint8_t* R = read_raw_mono8(rpath, nbytes);
|
|
if (!L || !R) { free(L); free(R); return 1; }
|
|
|
|
StereoBoltCtx* ctx = sb_create(cfg); /* load config / calib / RKNN model — ONCE */
|
|
if (!ctx) {
|
|
fprintf(stderr, "sb_create failed: %s\n", sb_last_error(NULL));
|
|
free(L); free(R);
|
|
return 1;
|
|
}
|
|
|
|
/* PRODUCTION call: raw in-memory frames straight to the library.
|
|
channels=1 (Mono8), stride=0 (tightly packed, W bytes per row). */
|
|
StereoBoltModuleResultC out;
|
|
const sb_status_t st = sb_process_bolt_module_buffers(
|
|
ctx, L, W, H, 0, R, W, H, 0, /*channels=*/1, expected, &out);
|
|
|
|
if (st != SB_OK && st != SB_ERR_ALGORITHM_REJECTED) {
|
|
fprintf(stderr, "process failed (%d): %s\n", (int)st, sb_last_error(ctx));
|
|
sb_free_bolt_module_result(&out);
|
|
sb_destroy(ctx);
|
|
free(L); free(R);
|
|
return 1;
|
|
}
|
|
|
|
if (out.success) {
|
|
printf("success: bolts=%d distances=%d plane_rms=%.3f\n",
|
|
out.data.n_bolts, out.data.n_adjacent_distances, out.data.ground_plane.rms_mm);
|
|
for (int i = 0; i < out.data.n_bolts; ++i) {
|
|
const StereoBoltModuleBoltC* b = &out.data.bolts[i];
|
|
printf(" bolt %d: height=%.3f mm top=(%.1f,%.1f,%.1f)\n",
|
|
b->bolt_id, b->height_mm, b->top_xyz.x, b->top_xyz.y, b->top_xyz.z);
|
|
}
|
|
} else {
|
|
printf("rejected: reason=%s L_rois=%d R_rois=%d pairs=%d\n",
|
|
out.failure.reason, out.failure.n_left_rois,
|
|
out.failure.n_right_rois, out.failure.n_pairs);
|
|
}
|
|
|
|
const int rc = out.success ? 0 : 3;
|
|
sb_free_bolt_module_result(&out);
|
|
sb_destroy(ctx); /* ONCE, on exit */
|
|
free(L); free(R);
|
|
return rc;
|
|
}
|