跳到主要内容

推理

每次一张图。连续帧循环调用 darra_session_infer_image。阻塞调用,耗时随 Provider / 硬件而定。不承诺硬实时——PLC 侧按架构在扫描周期外进程 / 线程调用。

同一会话可并发调用(底层运行时会话线程安全;解密明文窗口由 SDK 内部串行管理);吞吐扩展推荐每线程一个会话。

相关页面

darra_session_infer_image()

int32_t darra_session_infer_image(darra_session* session,
const uint8_t* image_bytes,
size_t len,
const darra_image_desc* desc,
char** out_results_json);

对一张图片跑推理,结果输出 JSON。连续帧请循环调用本函数。

参数:

  • session (darra_session*) — 已打开的会话
  • image_bytes (const uint8_t*) — AUTO/ENCODED = 编码文件字节流;裸缓冲 = 像素内存
  • len (size_t) — 字节长度。裸缓冲必须 ≥ stride*height(stride 为 0 时按 format 紧凑宽度计:RGB888/BGR888=width*3,GRAY8=width*1,RGBA8888=width*4
  • desc (const darra_image_desc*) — 图像描述;desc->size 必填 sizeof(darra_image_desc)
  • out_results_json (char**) — 结果 JSON,SDK 分配,用完 darra_string_free

返回值:

  • int32_tDARRA_OK 成功

典型错误:DARRA_IO_DENIED(裸缓冲指针不可读)/ DARRA_INTERNAL(参数契约违反:裸缓冲缺宽高、len 不足、desc->size 未填、NULL 句柄/出参)。

相关结构:

typedef enum darra_image_format {
DARRA_IMAGE_AUTO = 0, /* 按字节魔数自嗅探 JPG/PNG/BMP。裸缓冲禁止用 AUTO */
DARRA_IMAGE_ENCODED = 1, /* 显式已编码字节流(JPG/PNG/BMP);行为同 AUTO */
DARRA_IMAGE_RGB888 = 2, /* 裸缓冲 RGB 三通道 8bit,须给宽高 */
DARRA_IMAGE_BGR888 = 3, /* 裸缓冲 BGR 三通道 8bit,须给宽高 */
DARRA_IMAGE_GRAY8 = 4, /* 裸缓冲单通道 8bit 灰度,须给宽高 */
DARRA_IMAGE_RGBA8888 = 5 /* 裸缓冲 RGBA 四通道 8bit,须给宽高 */
} darra_image_format;

typedef struct darra_image_desc {
uint32_t size;
darra_image_format format;
uint32_t width;
uint32_t height;
uint32_t stride;
} darra_image_desc;
  • 调用方填 desc->size = sizeof(darra_image_desc)
  • format = AUTO/ENCODEDwidth / height / stride 忽略(填 0)。
  • format = RGB888/BGR888/GRAY8/RGBA8888width / height 必填(>0),缺宽高 = DARRA_INTERNAL(调用方 bug,不崩溃)。
  • stride = 每行字节数,0 表示紧凑排列:RGB888/BGR888 → width*3;GRAY8 → width*1;RGBA8888 → width*4
  • 裸缓冲禁止用 AUTO(嗅探不出通道序)。

示例:

/* 编码图,按魔数自嗅探 JPG/PNG/BMP */
darra_image_desc desc;
memset(&desc, 0, sizeof(desc));
desc.size = sizeof(desc);
desc.format = DARRA_IMAGE_AUTO;

char* results = NULL;
int32_t rc = darra_session_infer_image(s, jpeg_bytes, jpeg_len, &desc, &results);
if (rc == DARRA_OK) {
puts(results);
darra_string_free(results);
}
/* 裸缓冲,相机原生 BGR */
darra_image_desc desc;
memset(&desc, 0, sizeof(desc));
desc.size = sizeof(desc);
desc.format = DARRA_IMAGE_BGR888;
desc.width = 1920;
desc.height = 1080;
desc.stride = 0;

char* results = NULL;
int32_t rc = darra_session_infer_image(s, frame, (size_t)1920 * 1080 * 3, &desc, &results);
if (rc == DARRA_OK) {
puts(results);
darra_string_free(results);
}
/* 裸缓冲,GRAY8 灰度;RGBA8888 则 format=DARRA_IMAGE_RGBA8888,len=width*height*4 */
darra_image_desc desc;
memset(&desc, 0, sizeof(desc));
desc.size = sizeof(desc);
desc.format = DARRA_IMAGE_GRAY8;
desc.width = 1920;
desc.height = 1080;
desc.stride = 0;

char* results = NULL;
int32_t rc = darra_session_infer_image(s, gray, (size_t)1920 * 1080, &desc, &results);
if (rc == DARRA_OK) {
darra_string_free(results);
}
/* 连续帧:循环调用,不要每张图重新 open */
for (;;) {
/* 取下一帧到 frame / frame_len */
char* results = NULL;
int32_t rc = darra_session_infer_image(s, frame, frame_len, &desc, &results);
if (rc != DARRA_OK) break;
/* 消费 results */
darra_string_free(results);
}

推理结果 envelope 字段恒定;results 元素随 task 而变:

{
"schema": 1,
"task": "detect",
"provider": "onnx-cuda",
"elapsedMs": 3.2,
"image": { "width": 1920, "height": 1080 },
"results": [ { "label": "scratch", "score": 0.93, "box": [120, 40, 36, 18] } ]
}
  • envelope:schema / task / provider / elapsedMs / image / results
  • results 元素:
    • detect{label, score, box:[x,y,w,h]}
    • classify{label, score} top-k 按分降序
    • segment{label, score, maskRle}
    • 其余 task 的逐元素 schema 随对应 Provider 落地,本契约只承诺 envelope
  • 结果坐标基于 image 字段(解码后、送入模型前的尺寸);裸缓冲输入时等于 desc 的宽高。
  • 永不包含模型明文、密钥等任何敏感字节。

上例中的数值只说明字段形态,不是承诺的延迟或检测结果。

完整示例

场景:一台刚装完系统的客户机。装齐环境 → 打开加密模型 → 读元信息 → 推理一张图片 → 干净退出。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "darra_ai.h"

static int fail(const char* where, int32_t rc) {
darra_error_t err; err.size = sizeof(err);
if (darra_last_error(&err) == DARRA_OK) {
fprintf(stderr, "%s 失败 rc=%d(无错误细节)\n", where, rc);
} else {
fprintf(stderr, "%s 失败 [%d] %s\n建议: %s\n", where, err.code, err.message, err.hint);
}
return (int)rc;
}

static void on_progress(float percent, const char* stage, void* user) {
(void)user;
printf("\r环境准备 [%-8s] %5.1f%% ", stage, percent);
fflush(stdout);
}

static uint8_t* read_file(const char* path, size_t* out_len) {
FILE* f = fopen(path, "rb");
if (!f) return NULL;
fseek(f, 0, SEEK_END); long n = ftell(f); fseek(f, 0, SEEK_SET);
if (n <= 0) { fclose(f); return NULL; }
uint8_t* buf = (uint8_t*)malloc((size_t)n);
if (buf && fread(buf, 1, (size_t)n, f) != (size_t)n) { free(buf); buf = NULL; }
fclose(f);
if (buf) *out_len = (size_t)n;
return buf;
}

int main(void) {
int32_t rc;
darra_session* session = NULL;
char* meta = NULL;
char* results = NULL;
uint8_t* image = NULL;
int exit_code = 1;

if (DARRA_VERSION_DECODE_MAJOR(darra_version()) != DARRA_VERSION_MAJOR) {
fprintf(stderr, "ABI 不匹配,库版本 = %s\n", darra_version_string());
return 1;
}

rc = darra_runtime_ensure(NULL, NULL, on_progress, NULL);
printf("\n");
if (rc != DARRA_OK) return fail("darra_runtime_ensure", rc);

rc = darra_session_open("model.darmodel", "model.darmkey", NULL, NULL, &session);
if (rc != DARRA_OK) return fail("darra_session_open", rc);

rc = darra_session_meta_json(session, &meta);
if (rc != DARRA_OK) { fail("darra_session_meta_json", rc); goto cleanup; }
printf("[meta] %s\n", meta);

{
size_t image_len = 0;
image = read_file("photo.jpg", &image_len);
if (!image) { fprintf(stderr, "读图片失败\n"); goto cleanup; }

darra_image_desc desc;
memset(&desc, 0, sizeof(desc));
desc.size = sizeof(desc);
desc.format = DARRA_IMAGE_AUTO;

rc = darra_session_infer_image(session, image, image_len, &desc, &results);
if (rc != DARRA_OK) { fail("darra_session_infer_image", rc); goto cleanup; }
printf("[results] %s\n", results);
}

exit_code = 0;

cleanup:
free(image);
if (results) darra_string_free(results);
if (meta) darra_string_free(meta);
darra_session_close(session);
return exit_code;
}

要点:

  1. ABI 核对先行,装错库不往下走;
  2. darra_runtime_ensure 幂等——已装好就是秒过,可每次启动都调;
  3. 所有 char* 出参一律 darra_string_free,调用方自己 malloc 的自己 free
  4. 任何一步失败,darra_last_errorhint 就是给最终用户的修复建议(见 错误码)。