/* 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 #include #include #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 \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; }