跳到主要内容

高性能SDK套件 - C++接口

信息

本文对应 OpenIVS 提供的 C++ API,接口源码与 Visual Studio 工程位于 OpenIVS 仓库。

完整调用示例见 C++测试程序-例程

开发文件

核心 SDK 通过 AI 平台安装,C++ 接口和 Qt 例程从 OpenIVS 构建,运行时 DLL 放在例程同目录。

配置正确位置
底层 SDK DLL 与头文件<Python环境>/Lib/site-packages/dlcvpro_infer
C++ 包装头文件<OpenIVS>/dlcv_infer_cpp/dlcv_infer.hdlcv_sntl_admin.h
C ABI 头文件<OpenIVS>/dlcv_infer_cpp/dlcv_infer_c_api.h
C++ DLL 与导入库(解决方案构建)<OpenIVS>/<配置>/dlcv_infer_cpp.dlldlcv_infer_cpp.lib
C++ DLL 与导入库(单独构建工程)<OpenIVS>/dlcv_infer_cpp/<配置>/
Qt 例程输出<OpenIVS>/<配置>/dlcv_infer_cpp_qt_demo/

独立调用工程需要配置以下目录:

  • 包含目录:<OpenIVS>/dlcv_infer_cpp<Python环境>/Lib/site-packages/dlcvpro_infer/include 和 OpenCV 4.x 头文件目录
  • 库目录:选择与调用工程配置一致的 OpenIVS 构建输出目录
  • 运行目录:放置同一配置生成的 dlcv_infer_cpp.dll;底层 dlcv_infer.dlldlcv_infer_v.dll 由封装层从核心 SDK 目录加载

C++ 接口使用 std::stringstd::vectornlohmann::jsoncv::Mat。调用工程应使用 x64、C++17,并采用与 SDK 兼容的 Visual C++ 与 OpenCV 运行环境。Debug 与 Release 文件不可混用。

常用接口

namespace dlcv_infer
{
using json = nlohmann::json;

class Model
{
public:
int modelIndex = -1;
bool OwnModelIndex = true;

Model();
Model(const std::string& modelPath, int device_id);
Model(const std::wstring& modelPath, int device_id);

Model(const Model&) = delete;
Model& operator=(const Model&) = delete;
Model(Model&& other) noexcept;
Model& operator=(Model&& other) noexcept;
virtual ~Model();

void FreeModel();
json GetModelInfo();
json GetDvsModelInfo();

Result Infer(
const cv::Mat& image,
const json& params_json = nullptr);

Result InferBatch(
const std::vector<cv::Mat>& image_list,
const json& params_json = nullptr);

json InferOneOutJson(
const cv::Mat& image,
const json& params_json = nullptr);

static void GetLastInferTiming(
double& dlcvInferMs,
double& totalInferMs);

static std::vector<FlowNodeTiming> GetLastFlowNodeTimings();

static bool GetLastInspectionStatus(
bool& ok,
std::vector<std::string>& reasons,
size_t sampleIndex = 0);
};

class Utils
{
public:
static std::string JsonToString(const json& value);
static void FreeAllModels();
static json GetDeviceInfo();
static Result OcrInfer(
Model& detectModel,
Model& recognizeModel,
const cv::Mat& image);
static json GetGpuInfo();
static void KeepMaxClock();
};

json GetAllDogInfo();
}

以上签名与 dlcv_infer_cpp.dll 的 C++ 导出一致。动态库还包含流程模型、C ABI 和测试检查使用的导出;普通 C++ 推理程序主要使用本页列出的接口。

加载模型

Windows 下推荐使用 std::wstring 传递模型路径,避免中文路径经过窄字符串转换:

#include "dlcv_infer.h"

std::wstring modelPath = LR"(D:\dlcv_demo\balloon.dvt)";
int deviceId = 0;

dlcv_infer::Model model(modelPath, deviceId);
  • modelPath:模型文件路径。std::wstring 直接传入 UTF-16 路径;std::string 重载会先尝试按 UTF-8 解析,无法往返转换时再按 GBK 解析
  • device_id-1 表示 CPU,非负整数表示 GPU 编号;可用设备还受模型格式和运行环境限制
  • 构造函数完成模型加载,加载失败时抛出异常

获取模型信息:

auto info = model.GetModelInfo();
std::cout << dlcv_infer::Utils::JsonToString(info) << std::endl;

图像输入

InferInferBatch 接收 cv::Mat。彩色输入采用 RGB 通道顺序,OpenCV imread 默认返回 BGR,需要在调用前转换:

cv::Mat decoded = cv::imread(R"(D:\dlcv_demo\balloon.jpg)", cv::IMREAD_UNCHANGED);
if (decoded.empty()) {
throw std::runtime_error("image decode failed");
}

cv::Mat inferImage;
if (decoded.channels() == 3) {
cv::cvtColor(decoded, inferImage, cv::COLOR_BGR2RGB);
} else if (decoded.channels() == 4) {
cv::cvtColor(decoded, inferImage, cv::COLOR_BGRA2RGB);
} else {
inferImage = decoded.clone();
}

推理接口

单张图

dlcv_infer::json params;
params["threshold"] = 0.5;
params["with_mask"] = true;
params["calc_mean"] = false;

dlcv_infer::Result result = model.Infer(inferImage, params);

批量图

std::vector<cv::Mat> images = {inferImage, inferImage};

dlcv_infer::json params;
params["threshold"] = 0.5;
params["with_mask"] = true;
params["calc_mean"] = false;
params["batch_size"] = static_cast<int>(images.size());

dlcv_infer::Result result = model.InferBatch(images, params);

InferBatch 返回的 sampleResults 与输入图片顺序对应。批量大小应在模型支持范围内,并与传入图片数量一致。

JSON 结果

dlcv_infer::json resultJson = model.InferOneOutJson(inferImage, params);

普通模型返回当前图片的结果数组,实例分割的 mask 会转换为轮廓点。流程模型产生判定状态时,返回对象包含 result_listokreason;也可在同一线程调用 GetLastInspectionStatus 读取最近一次判定状态。

结果结构

struct ObjectResult
{
int categoryId;
std::string categoryName;
float score;
float area;
std::vector<double> bbox;
bool withMask;
cv::Mat mask;
bool withBbox;
bool withAngle;
float angle;
bool withMean;
double foregroundMean;
double backgroundMean;
};

struct SampleResult
{
std::vector<ObjectResult> results;
};

struct Result
{
std::vector<SampleResult> sampleResults;
};
  • categoryName:Windows C++ 结构化结果使用 GBK 编码
  • bbox:水平框为 [x, y, width, height];旋转框中心、宽高保存在 bbox,角度保存在 angle
  • maskwithMask=true 时为 CV_8UC1 图像
  • withMean:表示 foregroundMeanbackgroundMean 是否有效
  • InferOneOutJson 返回的类别名称使用 JSON 的 UTF-8 字符串

结果遍历示例:

for (const auto& sample : result.sampleResults) {
for (const auto& object : sample.results) {
std::cout << "category_id=" << object.categoryId
<< ", score=" << object.score;

if (object.withBbox && object.bbox.size() >= 4) {
std::cout << ", bbox=["
<< object.bbox[0] << ", "
<< object.bbox[1] << ", "
<< object.bbox[2] << ", "
<< object.bbox[3] << "]";
}
std::cout << std::endl;
}
}

资源释放

  • Model 不可复制,可以移动
  • Model 析构时默认释放其拥有的底层模型,也可提前调用 FreeModel()
  • InferInferBatchInferOneOutJson 会在内部释放底层返回指针,调用端无需另行释放
  • Utils::FreeAllModels() 会释放当前进程中由封装层管理的全部模型,应在推理工作停止后调用
  • 不需要共享已有 modelIndex 时,不要修改 OwnModelIndex