推理
推理失败时模型不会被关掉,SDK 只把错误写进 last_error,phase 仍然是 OPENED。
快速开始
char* json = NULL;
if (darra_model_infer_file(h, "photo.jpg", &json) == 0) printf("%s\n", json);
if (json) darra_string_free(json);
| 类别 | 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| 推理 | darra_model_infer_file / _ex | 函数 | 只写 | 对磁盘上的图片文件推理,结果写成 JSON 返回 |
| darra_model_infer | 函数 | 只写 | 按文件路径推理的统一入口 | |
| darra_model_infer_bytes | 函数 | 只写 | 直接喂图片字节,格式自动识别(AUTO) | |
| darra_model_infer_buffer / _ex | 函数 | 只写 | 喂内存里的像素缓冲推理,结果写成 JSON 返回 | |
| darra_model_infer_image / _ex | 函数 | 只写 | 跟 infer_buffer 参数含义完全一样 | |
| darra_model_infer_tensors | 函数 | 只写 | 喂张量推理,返回输出张量(用完调 darra_tensor_free 释放) |
方法
darra_model_infer_file() / darra_model_infer_file_ex()
DARRA_API int32_t darra_model_infer_file(darra_model* m,
const char* image_path,
char** out_results_json);
DARRA_API int32_t darra_model_infer_file_ex(darra_model* m,
const char* image_path,
const double* thresholds,
size_t threshold_count,
char** out_results_json);
对磁盘上的单张图片(jpg/png/bmp)做推理,返回 DARRA_OK(0) 表示成功,结果写进 *out_results_json;失败时看 darra_model_last_error。结果 JSON 是堆上的字符串,必须调 darra_string_free 释放。
参数:
m(darra_model*) — 已经打开的模型句柄image_path(const char*) — 图片文件路径(UTF-8)thresholds(const double*) — 这次调用要用的分数下限表,只在_ex版本有。按类别下标给值,范围[0,1]。传 NULL 表示用default_thresholdsthreshold_count(size_t) — 表里有几个元素(_ex用),要跟class_count对得上out_results_json(char**) — 成功时把结果 JSON 的地址写到这里。失败时这个指针不会被改动
/* out_results_json 返回的 JSON 是堆上的字符串,用完必须调 darra_string_free 释放。 */
/* 外层字段固定这几项: */
/* schema:int 契约版本号;task:string 任务短名,拿不到就写 null */
/* provider:string 本次实际用的 Provider;elapsedMs:double 本次耗时(毫秒) */
/* image:{width,height} 图片解码后、送进模型前的尺寸 */
/* results[] 里每个元素的字段随 task 和 Provider 不同: */
/* detect: label/class_id/score/box:[x,y,w,h],有的还带 polygon */
/* classify: label/class_id/score(没有 box) */
/* pose: detect 的四个键 + keypoints:[[x,y,conf],...] */
/* obb: detect 的四个键 + angle */
/* segment(ONNX 系): detect 的四个键 + mask/mask_width/mask_height */
/* segment(paddle 系): maskRle:{size:[H,W],values:int[],counts:int[]} */
/* ocr 检测: {label:"text",score,box,polygon};ocr 识别: {text,score} */
/* anomaly 分数图: anomalyScore+anomaly_width/anomaly_height */
/* anomaly 图像级: 只有 score */
/* depth: depth+depth_width/depth_height(这三个键要么都有,要么都没有) */
/* embedding: embedding+embeddingDim(这两个键要么都有,要么都没有) */
/* class_id 是类别身份的权威值(就是类别表里的下标)。要归类请用 class_id,不要靠 label 反推 */
/* 坐标跟 image 用的是同一个坐标空间 */
示例:
char* json = NULL;
int32_t rc = darra_model_infer_file(m, "a.jpg", &json);
if (rc == DARRA_OK) {
printf("%s\n", json);
darra_string_free(json); /* 结果 JSON 必须释放 */
} else {
printf("infer failed %d: %s\n", rc, darra_model_last_error(m));
}
darra_model_infer()
DARRA_API int32_t darra_model_infer(darra_model* h, const char* image_path, char** out_results_json);
按文件路径推理的统一入口,含义、参数和错误都跟 darra_model_infer_file 一样。
参数: h / image_path / out_results_json。都跟 darra_model_infer_file 一样。
char* json = NULL;
if (darra_model_infer(h, "a.jpg", &json) == DARRA_OK) { puts(json); darra_string_free(json); }
darra_model_infer_bytes()
DARRA_API int32_t darra_model_infer_bytes(darra_model* h,
const uint8_t* bytes,
size_t len,
char** out_results_json);
按字节推理的统一入口,不用填 desc。
参数: h (darra_model*) — 已经打开的模型句柄。bytes (const uint8_t*) — 图片的编码字节。
char* json = NULL;
if (darra_model_infer_bytes(h, jpg, jpg_len, &json) == DARRA_OK) { puts(json); darra_string_free(json); }
darra_model_infer_buffer() / darra_model_infer_buffer_ex()
DARRA_API int32_t darra_model_infer_buffer(darra_model* m,
const uint8_t* data,
size_t len,
const darra_image_desc* desc,
char** out_results_json);
DARRA_API int32_t darra_model_infer_buffer_ex(darra_model* m,
const uint8_t* data,
size_t len,
const darra_image_desc* desc,
const double* thresholds,
size_t threshold_count,
char** out_results_json);
直接对内存里的图像缓冲做推理,不经过文件读写。
参数:
m(darra_model*) — 已经打开的模型句柄data(const uint8_t*) — 图像数据。内存归调用方持有,函数不负责释放len(size_t) — 数据的字节长度desc(const darra_image_desc*) — 图像描述(size/format/width/height/stride)。thresholds(const double*) — 这次调用要用的分数下限表(只在_ex版本有)。传 NULL 表示用default_thresholds,这点跟infer_file_ex一样threshold_count(size_t) — 表里有几个元素(_ex用),要跟class_count对得上out_results_json(char**) — 成功时结果 JSON 的地址写到这里
返回 DARRA_OK(0) 表示成功,结果 JSON 用 darra_string_free 释放。
结果 JSON 的外层字段,跟 infer_file 那一节写的一样。results 里每个元素的字段也都跟 infer_file 那一节写的一样。
示例:
darra_image_desc desc = {0};
desc.size = sizeof(desc);
desc.format = DARRA_IMAGE_RGB888; /* 裸缓冲必须显式给格式 */
desc.width = 640;
desc.height = 480;
char* json = NULL;
if (darra_model_infer_buffer(m, pixels, len, &desc, &json) == DARRA_OK) {
printf("%s\n", json);
darra_string_free(json);
}
format 传 DARRA_IMAGE_AUTO 时自动识别图片格式。
darra_model_infer_image() / darra_model_infer_image_ex()
DARRA_API int32_t darra_model_infer_image(darra_model* m,
const uint8_t* data,
size_t len,
const darra_image_desc* desc,
char** out_results_json);
DARRA_API int32_t darra_model_infer_image_ex(darra_model* m,
const uint8_t* data,
size_t len,
const darra_image_desc* desc,
const double* thresholds,
size_t threshold_count,
char** out_results_json);
darra_model_infer_buffer / _ex 换了个名字的版本。参数和含义完全一样。
参数: 同 darra_model_infer_buffer / _ex。
char* json = NULL;
if (darra_model_infer_image(m, pixels, len, &desc, &json) == DARRA_OK) { puts(json); darra_string_free(json); }
darra_model_infer_tensors()
DARRA_API int32_t darra_model_infer_tensors(darra_model* h,
const darra_tensor_t* inputs,
size_t input_count,
darra_tensor_t** out_tensors,
size_t* out_count);
张量推理,支持多个输入和多个输出。
参数: h 是已经打开的模型句柄。inputs / input_count 是输入张量数组和它的个数。
darra_tensor_t in = {0};
in.size = (uint32_t)sizeof(in);
darra_tensor_t* outs = NULL; size_t n = 0;
if (darra_model_infer_tensors(h, &in, 1, &outs, &n) == DARRA_OK) { /* ... */ darra_tensor_free(outs, n); }
基础用法
批量
顺序跑多张图就是一个循环,每轮拿到的 JSON 都要释放:
for (;;) {
rc = darra_model_infer_file(h, path, &json);
if (rc != 0) break;
darra_string_free(json);
json = NULL;
}
darra_model_close(h);
阈值
default_thresholds 是这个实例的默认阈值表。下标是类别序号,值是分数下限。
double def[2] = {0.5, 0.8};
cfg.default_thresholds = def; /* 实例默认 */
cfg.default_thresholds_count = 2;
double one[1] = {0.9};
rc = darra_model_infer_file_ex(h, "a.jpg", one, 1, &json); /* 这个阈值只覆盖这一次调用 */
如果传的值超出范围,或者表的长度跟 class_count 对不上,调用会直接失败。
并发推理
并发用池:cfg.workers 设大于 1。池入口 darra_pool_submit / darra_pool_wait。
空闲机实测(197,det.onnx,3 轮中位):
- 单任务基线:1×(约 0.2s)
- 池
workers=2双投:两任务同时完成,各约 1–1.5 倍单任务 - 多实例 2–4 个:总吞吐约等于串行(0.88–0.94×) 并发收益随机器负载变化。
darra_model_submit() / darra_model_wait()
DARRA_API int32_t darra_model_submit(darra_model* h, const uint8_t* data, size_t len,
const darra_image_desc* desc_or_null, uint64_t* out_ticket);
DARRA_API int32_t darra_model_wait(darra_model* h, uint64_t ticket, char** out_results_json);
异步提交,wait 取结果。那次推理失败,wait 原样带回失败。
示例:
uint64_t ticket = 0;
if (darra_model_submit(h, jpg, jpg_len, NULL, &ticket) == DARRA_OK) {
char* json = NULL;
if (darra_model_wait(h, ticket, &json) == DARRA_OK) { puts(json); darra_string_free(json); }
}
darra_pool_submit / darra_pool_wait
int32_t darra_pool_submit(darra_pool* pool, const uint8_t* image_bytes, size_t len,
const darra_image_desc* desc, uint64_t* out_ticket);
int32_t darra_pool_wait(darra_pool* pool, uint64_t ticket, char** out_results_json);
提交成功 *out_ticket 大于 0,之后可释放缓冲区。wait 等到结果出来。
示例:
uint64_t t = 0;
darra_pool_submit(pool, jpeg, len, &desc, &t);
char* json = NULL;
if (darra_pool_wait(pool, t, &json) == DARRA_OK) { puts(json); darra_string_free(json); }
槽与份额
每次推理占 1 个槽。
DARRA_API void darra_sched_set_gpu_slots(int32_t gpu_device, int32_t slots);
这个函数限制一张 GPU 上同时在跑的推理张数。slots 填 0 表示不限制。
示例:
darra_sched_set_gpu_slots(0, 4); /* 卡 0 最多同时跑 4 个推理 */
日志出口
进程级日志回调。级别 0 是 ERROR,1 是 WARN,2 是 INFO,3 是 DEBUG。
typedef void (*darra_model_log_fn)(int level, const char* msg, void* user);
DARRA_API int32_t darra_global_set_log_callback(darra_model_log_fn cb, void* user_or_null);
后注册的会覆盖先注册的,cb 传 NULL 表示注销。msg 只在回调执行期间有效,如果想留着以后用,要先拷贝一份。
示例:
darra_global_set_log_callback(my_log, NULL); /* 注销传 NULL */
推理结果
推理结果的 JSON 外层字段是固定的。schema / task / provider。
- detect →
{label, class_id, score, box:[x,y,w,h]}。有的还另带polygon - classify →
{label, class_id, score}(没有 box) - anomaly 有两种形态。分数图是
{anomalyScore, anomaly_width, anomaly_height}。按行存,长度等于宽×高。图像级只带score - pose →
{label, class_id, score, box}。keypoints是[[x,y,conf],...] - obb →
{label, class_id, score, box, angle} - ocr 有两种形态。det 是
{label:"text", score, box, polygon}。不带 class_id。rec 是{text, score} - depth →
{depth, depth_width, depth_height}。embedding →{embedding, embeddingDim}。每组里的键要么都有要么都没有 - segment 按 Provider 分两种。ONNX 系返回
{label, class_id, score, box}加三个掩码键。mask/mask_width/mask_height - Paddle 系返回
maskRle:{size:[H,W], values, counts}。是整张类别图的游程编码(sum(counts)==H*W,H、W 按模型输出的尺寸算) onnx-directml/trt-native这两种不出掩码- 遇到不认识的键就忽略。
task/image拿不到就写null,不编造