跳到主要内容

高性能SDK套件 - C接口

使用文件

本页说明原生 C 接口:

  • 头文件:C:\dlcv\Lib\site-packages\dlcvpro_infer\include\dlcv_infer\dlcv_infer.h
  • 运行时 DLL:Sentinel 授权使用 dlcv_infer.dll,Virbox 授权使用 dlcv_infer_v.dll

OpenIVS 源码另提供 dlcv_infer_cpp/dlcv_infer_c_api.h,配合该项目构建生成的 dlcv_infer_cpp.dll 使用,属于 C/C++ 封装层的 C 接口。该接口的主要函数名以 dlcv_infer_cpp_* 开头,不能与本页的原生 C 接口混用。

接口概览

说明
  • JSON 接口返回由 DLL 分配的 const char*
  • dlcv_infer 的结果使用 dlcv_free_model_result 释放,其他 JSON 字符串结果使用 dlcv_free_result 释放。
  • 结构体接口 dlcv_infer_c 返回 DlcvCResult,结果使用 dlcv_free_model_result_c 释放。

公开头文件中的相关声明如下:

#include "dlcv_infer/dlcv_infer.h"

// JSON 接口
DLL_FUNC(const char*) dlcv_load_model(const char* config_str);
DLL_FUNC(const char*) dlcv_free_model(const char* config_str);
DLL_FUNC(const char*) dlcv_get_model_info(const char* config_str);
DLL_FUNC(const char*) dlcv_infer(const char* config_str);
DLL_FUNC(void) dlcv_free_model_result(const char* config_str);
DLL_FUNC(void) dlcv_free_result(const char* config_str);
DLL_FUNC(void) dlcv_free_all_models();

// 结构体接口
DLL_FUNC(int) dlcv_load_model_c(const char* model_path, int device_id);
DLL_FUNC(int) dlcv_free_model_c(int model_index);
DLL_FUNC(DlcvCResult) dlcv_infer_c(
int model_index,
const DlcvCImageList* image_list);
DLL_FUNC(void) dlcv_free_model_result_c(DlcvCResult* result);

// 设备相关接口
DLL_FUNC(const char*) dlcv_get_device_info();
DLL_FUNC(const char*) dlcv_get_gpu_info();
说明

这些接口按 C ABI 导出。示例为了方便构造 JSON 和读取图片,会使用 C++ 的 nlohmann::json 与 OpenCV;纯 C 程序可以使用其他 JSON 库生成相同的字符串,并传入图像 buffer 的指针地址。

内存管理

JSON 推理结果使用 dlcv_free_model_result,其他 JSON 字符串结果使用 dlcv_free_result,结构体推理结果使用 dlcv_free_model_result_c。结构体结果中的字符串、结果数组和 mask 数据由 DLL 管理,释放后不可继续访问。

加载模型

代码样例:

说明

传入 DLL 的 JSON 字符串必须是 UTF-8 编码。示例可直接使用 std::wstring 作为 json 的字段值(需包含并链接 dlcv_utils_json.hdlcv_utils_string.h),内部会把 wstring 转为 UTF-8 后再序列化。

std::wstring model_path = LR"(C:\models\det.dvt)";
int device_id = 0;

json a;
a["model_path"] = model_path;
a["device_id"] = device_id;
std::string json_str = a.dump();

const char* result = dlcv_load_model(json_str.c_str());

json result_a = json::parse(result);
dlcv_free_result(result);

int model_index = result_a["model_index"];

输入:

{
"model_path": "C:\\Users\\Administrator\\Desktop\\测试模型\\det.dvt",
"device_id": 0
}

输出:

{
"code": 0,
"message": "Successfully loaded model.",
"model_index": 0
}

模型推理

注意

彩色图像的通道顺序是 RGB

样例代码:

cv::Mat img = cv::imread(R"(C:\images\balloon.jpg)");
cv::Mat img_rgb;
cv::cvtColor(img, img_rgb, cv::COLOR_BGR2RGB);


json image_info;
image_info["width"] = img_rgb.cols;
image_info["height"] = img_rgb.rows;
image_info["channels"] = img_rgb.channels();
image_info["image_ptr"] = (uintptr_t)img_rgb.ptr();

json d;
d["model_index"] = model_index;
d["image_list"].push_back(image_info);

auto json_str = d.dump();
const char* result = dlcv_infer(json_str.c_str());
json result_d = json::parse(result);
dlcv_free_model_result(result);

model_index 是加载模型时返回的结果。

注意

img 在调用过程中,不要释放内存。

注意

C 接口需要手动调用 dlcv_free_model_result 释放结果。

输入:

{
"image_list": [
{
"channels": 3,
"height": 768,
"image_ptr": 1978309283968,
"width": 1024
}
],
"model_index": 0
}

输出:

{
"sample_results": [
{
"results": [
{
"area": 225630.0,
"bbox": [
58.85700607299805,
69.69281005859375,
517.2791023254395,
547.71923828125
],
"category_id": 0,
"category_name": "气球",
"mask": {
"height": 547,
"mask_ptr": 1737551411232,
"width": 517
},
"score": 0.9907786846160889,
"with_mask": true
}
]
}
]
}

返回结果解析

  • sample_results,列表,每个元素是一张图片的结果。
  • results,列表,每个元素是一张图片中的物体。
    • area,浮点数,物体的面积。
    • with_bbox(可选),布尔值,是否有检测框
    • bbox,列表,浮点数,物体的检测框:
      • 常见为 [x, y, w, h](左上角 + 宽高)
      • 旋转框可能为 [cx, cy, w, h, angle](中心点 + 宽高 + 角度,弧度制)
    • category_id,整数,物体的类别 ID。
    • category_name,字符串,物体的类别名称。
    • score,浮点数,物体的置信度。
    • with_mask,布尔值,是否有 mask。
    • with_angle(可选),布尔值,是否有角度信息
    • angle(可选),浮点数,物体的角度(弧度制,非旋转框一般为 -100)
    • with_mean(可选),布尔值,是否包含前景与背景均值
    • foreground_mean / background_mean(可选),浮点数,mask 前景区域与背景区域的像素均值
    • mask,对象,物体的 mask。
      • height,整数,mask 的高度。
      • mask_ptr,指针,mask 的指针。
      • width,整数,mask 的宽度。

Mask 解析

Mask 可以使用 OpenCV 直接实例化,如:

auto mask = cv::Mat(height, width, CV_8UC1, (void*)ptr).clone();

释放模型

使用 dlcv_free_model 接口释放模型。

model_index 是加载模型时返回的结果。

json b;
b["model_index"] = model_index;
json_str = b.dump();

result = dlcv_free_model(json_str.c_str());
json result_b = json::parse(result);
result_str = dlcv::utils_string::convertUtf8ToWstring(result_b.dump());
std::wcout << "result_json: " << result_str << std::endl;
dlcv_free_result(result);

输出:

{
"code": 0,
"message": "Successfully freed model."
}

释放所有模型

在整个程序退出之前,需要释放所有模型,可以手动释放,也可以直接调用 dlcv_free_all_models 接口。该接口无返回值。

dlcv_free_all_models();

结构体接口

结构体类型以 dlcv_infer/dlcv_data_type_c.h 中的 typedef 为准;dlcv_infer.h 已包含该文件。

typedef struct DlcvCImage {
long long data_ptr;
int height;
int width;
int channel;
} DlcvCImage;

typedef struct DlcvCImageList {
DlcvCImage* images;
int n;
} DlcvCImageList;

typedef struct DlcvCMask {
long long mask_ptr;
int height;
int width;
} DlcvCMask;

typedef struct DlcvCObjectResult {
int category_id;
char* category_name;
float score;

bool with_bbox;
float area;
float x, y, w, h;

bool with_mask;
DlcvCMask mask;

bool with_angle;
float angle;

bool with_mean;
double foreground_mean;
double background_mean;
} DlcvCObjectResult;

typedef struct DlcvCSampleResult {
DlcvCObjectResult* results;
int n;
} DlcvCSampleResult;

typedef struct DlcvCResult {
int code;
char* message;
DlcvCSampleResult* sample_results;
int n;
} DlcvCResult;

DlcvCImage 包含图像数据地址、宽度、高度和通道数。彩色图像通道顺序是 RGB。

DlcvCImageList 包含 DlcvCImage 数组和数量。调用 dlcv_infer_c 时传入该结构体的地址。

DlcvCMask 包含 mask 数据地址、宽度和高度。

DlcvCObjectResult 的主要字段如下:

  • category_idcategory_namescore:类别编号、类别名称和置信度。
  • with_bboxxywh:是否包含检测框,以及检测框左上角坐标和宽高。
  • area:物体面积。
  • with_maskmask:是否包含 mask,以及 mask 数据。
  • with_angleangle:是否包含角度及弧度值。
  • with_meanforeground_meanbackground_mean:是否包含均值,以及 mask 前景区域和背景区域的像素均值。

DlcvCSampleResult 包含一张图片的结果数组和数量。

DlcvCResult 包含返回码、消息、图片结果数组和数量。返回码为 0 表示成功,非 0 表示失败。结果读取完成后调用 dlcv_free_model_result_c(&result);该函数不会释放输入图像内存。

结果示例

内存管理

压力测试模型创建:

压力测试推理: