Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - great-wind/dev-docs: 服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。 · GitHub
Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - great-wind/dev-docs: 服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。 · GitHub
Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - great-wind/dev-docs: 服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。 · GitHub
Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - great-wind/dev-docs: 服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。 · GitHub
Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - great-wind/dev-docs: 服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。 · GitHub
Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - great-wind/dev-docs: 服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。 · GitHub
Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - great-wind/dev-docs: 服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。 · GitHub
Skip to content

Repository files navigation

EV_SDK

说明

EV_SDK的目标

开发者专注于算法开发及优化,最小化业务层编码,即可快速部署到生产环境,共同打造商用级高质量算法。

极市平台做了哪些

  1. 统一定义算法接口:针对万千视频和图片分析算法,抽象出接口,定义在include目录下的ji.h文件中
  2. 提供工具包:比如算法授权(必须实现)、模型加密,在3rd目录下
  3. 应用层服务:此模块不在ev_sdk中,比如视频处理服务、算法对外通讯的http服务等

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口,同时包括授权、支持分析区域等功能
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

ev_sdk
|-- 3rd # 第三方源码或库目录,发布时请删除
| |-- wkt_parser # 针对使用WKT格式编写的字符串的解析器
| |-- cJSON # c版json库,简单易用
| |-- ev_encrypt_module # 模型加密库及相关工具
| |-- darknet # 示例项目依赖的库
| `-- license # SDK授权库及相关工具
|-- CMakeLists.txt # 本项目的cmake构建文件
|-- README.md # 本说明文件
|-- model # 模型数据存放文件夹
|-- config # 程序配置目录
| |-- README.md # algo_config.json文件各个参数的说明和配置方法
| `-- algo_config.json # 程序配置文件
|-- doc
|-- include # 库头文件目录
| `-- ji.h # libji.so的头文件,理论上仅有唯一一个头文件
|-- lib # 本项目编译并安装之后,默认会将依赖的库放在该目录,包括libji.so
|-- src # 实现ji.cpp的代码
`-- test # 针对ji.h中所定义接口的测试代码,请勿修改!!!

使用示例

作为示例,我们提供了一个使用darknet实现的图像检测器,并将其使用EV_SDK规范进行封装,需要实现的业务逻辑是当检测到时,需要返回相关的报警信息。使用如下步骤尝试编译和测试该项目:

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

测试示例程序和接口规范

执行完成之后,/usr/local/ev_sdk/lib下将生成libji.so和相关的依赖库,以及/usr/local/ev_sdk/bin/下的测试程序test-ji-api

  1. 要使用/usr/local/ev_sdk/bin/test-ji-api测试EV_SDK的接口,需要重新生成授权所使用的参考码reference.txt,并使用私钥对其进行加密后重新生成授权文件license.txt

    # 生成公私钥以及公钥对应的头文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh
    # 生成硬件参考码文件和授权文件
    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh
  2. 使用test-ji-api测试ji_calc_frame接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -l /usr/local/ev_sdk/authorization/license.txt -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0.1 0.8,0.2 0.25))"]}'

    输出内容样例:

     code: 0
    json: {
    "alert_flag": 1,
    "dogs": [{
    "x": 129,
    "y": 186,
    "width": 369,
    "height": 516,
    "confidence": 0.566474
    }]
    }

使用EV_SDK快速封装算法

假设项目需要检测输入图像中是否有,如果检测到,就需要输出报警信息,以下示例开发算法与使用EV_SDK进行封装的流程

实现自己的模型

假设我们使用darknet开发了针对的检测算法,程序需要在检测到狗时输出报警信息。

下载EV_SDK

git clone https://github.com/ExtremeMart/dev-docs
mv dev-docs /usr/local/ev_sdk

生成授权功能所依赖的文件

  1. 使用EV_SDK提供的工具一键生成公钥和私钥、以及公钥对应的头文件pubKey.hpp

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyAuth.sh

    执行成功后将在/usr/local/ev_sdk下生成公钥authorization/pubKey.perm和私钥authorization/privateKey.pem,以及头文件include/pubKey.hpp

  2. ji_init(int argc, char **argv)的接口实现中,添加校验授权文件的功能。

    注:这部分代码在示例代码ji.cpp中已经实现,可以无需变动,直接使用。

    // 使用公钥校验授权信息int ret = ji_check_license(pubKey, license, url, activation, timestamp, qps, version);
    return ret == EV_SUCCESS ? JISDK_RET_SUCCEED : JISDK_RET_UNAUTHORIZED;

更多授权功能的原理,请参考算法授权

添加模型加密功能

  1. 使用EV_SDK提供的工具加密模型,并生成C++头文件,这里仅仅示例加密yolov3-tiny.cfg文件,请根据实际需要,对重要的模型/权重文件进行加密

    mkdir -p /usr/local/ev_sdk/model_encryption/
    cd /usr/local/ev_sdk/model_encryption/
    /usr/local/3rd/ev_encrypt_module/bin/encrypt_tool /usr/local/ev_sdk/model/yolov3-tiny.cfg

    执行成功后会生成加密后的文件model_str.hppencrypt_tool程序支持在加密模型时指定一个混淆字符串,具体方法请执行encrypt_tool参考帮助文档。将头文件移动到代码区

    mv /usr/local/ev_sdk/model_encryption/model_str.hpp /usr/local/ev_sdk/include

    这个加密后的模型将被硬编码libji.so

  2. ji_create_predictor(int)的接口实现中,添加模型解密的功能。

    注:示例代码ji.cpp里面提供了解密的方法,对于加密文本类型的模型文件的场景可以直接使用,无需更改。

    // 创建解密句柄void *h = CreateEncryptor(model_str.c_str(), model_str.size(), key.c_str());
    // 获取解密后的字符串int fileLen = 0;
    model_struct_str = (char *) FetchBuffer(h, fileLen);
    // 获取解密后的文件句柄// file *file = (file *) FetchFile(h);DestroyEncrtptor(h);

    模型解密的详细接口函数请参考其头文件encrypt_wrapper.h

实现ji.h中的接口

ji.h中定义了所有EV_SDK规范的接口,详细的接口定义和实现示例,请参考头文件ji.h和示例代码ji.cpp

将代码编译成libji.so

mkdir -p /usr/local/ev_sdk/build
cd /usr/local/ev_sdk/build
cmake ..
make install

编译完成后,将在/usr/local/ev_sdk/lib下生成libji.so和其他依赖的库。

测试接口功能

测试libji.so的授权功能是否正常工作以及ji.h的接口规范

  1. 使用EV_SDK提供的程序oneKeyTest.sh一键生成授权文件

    bash /usr/local/ev_sdk/3rd/license/bin/oneKeyTest.sh

    oneKeyTest.sh会执行:

    • 检查authorization/pubKey.pemauthorization/privateKey.pem的有效性;

    • 生成硬件参考码文件authorization/reference.txt和授权文件authorization/license.txt

  2. 检查授权功能和ji.h的接口规范性

    EV_SDK代码中提供了测试所有接口的测试程序,编译并安装libji.so之后,会在/usr/local/ev_sdk/bin下生成test-ji-api可执行文件,test-ji-api用于测试ji.h的接口实现是否正常,例如,测试ji_calc_frame接口以及授权功能是否正常:

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_frame \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -l /usr/local/ev_sdk/authorization/license.txt \
    -a '{"roi":["POLYGON((0.2 0.2,0.6 0.1,0.8 0.7,0.4 0.9,0 0.8,0.2 0.2))"]}'

    接口测试程序的详细功能请查阅test-ji-api --help的帮助文档及其代码test.cpp

哪些内容必须完成才能通过测试?

按照需求实现接口(由项目经理告知)

  1. ji_calc_frame ,用于实时视频流分析
  2. ji_calc_buffer ,用于分析图片buffer
  3. ji_calc_file ,用于分析图片文件
  4. ji_calc_video_file :用于极市平台测试组测试和开发者自测视频文件

规范要求

规范测试大部分内容依赖于内置的/usr/local/ev_sdk/test下面的代码,这个测试程序会链接/usr/local/ev_sdk/lib/libji.so库,EV_SDK封装完成提交后,极市方会使用test-ji-api程序测试ji.h中的所有接口。测试程序与EV_SDK的实现没有关系,所以请请不要修改/usr/local/ev_sdk/test目录下的代码!!!

  1. 接口功能要求

    • 确定test-ji-api能够正常编译,并且将test-ji-apilicense.txt移动到任意目录,都需要能够正常运行;

    • 在提交算法之前,请自行通过/usr/local/ev_sdk/bin/test-ji-api测试接口功能是否正常;

    • 未实现的接口需要返回JISDK_RET_UNUSED

    • 实现的接口,如果传入参数异常时,需要返回JISDK_RET_INVALIDPARAMS

    • 对于实现多个接口的情况,请确保每个接口对同样的输入数据保持一致的算法分析结果,比如ji_calc_frameji_calc_file两个接口对于同样的输入图片数据,应该保持一样的分析结果;

    • 输入图片和输出图片的尺寸应保持一致;

    • 对于接口中传入的参数args(如,ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中中args),根据项目需求,算法实现需要支持args实际传入的参数。

      例如,如果项目需要支持在args中传入roi参数,使得算法只对roi区域进行分析,那么算法内部必须实现只针对roi区域进行分析的功能

    • 对于接口ji_calc_video接口,其保存的json文件格式必须与ji_calc_frameji_calc_fileji_calc_buffer中的JI_EVENT.json格式保持一致;

    • 通常输出图片中需要画roi区域、目标框等,请确保这一功能正常,包括但不仅限于:

      • args中输入的roi需要支持多边形
      • 算法默认分析区域必须是全尺寸图,如当roi传入为空时,算法对整张图进行分析;
    • 为了保证多个算法显示效果的一致性,与画框相关的功能必须优先使用ji_utils.hpp.h中提供的工具函数;

    1. test-ji-api的使用方法可以参考上面的使用示例以及运行test-ji-api --help
    2. 以上要求在示例程序ji.cpp中有实现;
  2. 业务逻辑要求

    针对需要报警的需求,算法必须按照以下规范输出结果:

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag"=1

    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag"=0

    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED

    • 算法输出的json数据必须与项目需求保持一致;

  3. 授权功能要求

    需要实现授权功能,并且在调用接口(比如ji_calc_frame)时,如果授权没有通过,必须返回JISDK_RET_UNAUTHORIZED

    注:授权功能已经在示例代码实现,基本不需要修改

  4. 算法配置选项要求

    • EV_SDK的实现需要使用标准JSON格式的配置文件,所有算法与SDK可配置参数必须存放在统一的配置文件:/usr/local/ev_sdk/config/algo_config.json中;
    • 配置文件中必须实现的参数项:
      • draw_roi_areatrue或者false,是否在输出图中绘制roi分析区域;
      • roi_line_thickness:ROI区域的边框粗细;
      • roi_fill:是否使用颜色填充ROI区域;
      • roi_colorroi框的颜色,以BGRA表示的数组,如[0, 255, 0, 0],参考model/README.md
      • roi:针对图片的感兴趣区域进行分析,如果没有此参数或者此参数解析错误,则roi默认值为整张图片区域;
      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);
      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;
      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;
      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。
    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_frameji_calc_bufferji_calc_fileji_calc_video_file四个接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。
  5. 算法输出规范要求

    算法输出结果,即JI_EVENT.json必须是使用json格式填充的字符串,json字符串内所有的键名称必须是小写字母,并且单词之间使用下划线分隔,如alert_flag

  6. 文件结构规范要求

    • 授权功能生成的公私钥必须放在/usr/local/ev_sdk/bin ,且一次生成后,请勿再次更新公私钥(极市方会保存第一版的私钥),如果在后续更新中,重新生成了公私钥,会导致公私钥不匹配;
    • 与模型相关的文件必须存放在/usr/local/ev_sdk/model目录下,例如权重文件、目标检测通常需要的名称文件coco.names等。
    • 最终编译生成的libji.so必须自行链接必要的库,test-ji-api不会链接除/usr/local/ev_sdk/lib/libji.so以外的算法依赖库;
    • 如果libji.so依赖了系统动态库搜索路径(如/usr/lib/lib等)以外的库,必须将其安装到/usr/local/ev_sdk/lib下,可以使用ldd /usr/local/ev_sdk/lib/libji.so查看libji.so是否正确链接了所有的依赖库。
    • 授权文件位置
      • 请务必将生成的私钥privateKey.pem和公钥publicKey.pem放到/usr/local/ev_sdk/authorization下。并请自行保存一份,后续算法迭代过程都会使用第一次提交的公私钥,不能重新生成

FAQ

如何使用接口中的args

通常,在实际项目中,外部需要将多种参数(例如ROI)传入到算法,使得算法可以根据这些参数来改变处理逻辑。EV_SDK接口(如int ji_calc_frame(void *, const JI_CV_FRAME *, const char *args, JI_CV_FRAME *, JI_EVENT *)中的args参数通常由开发者自行定义和解析,但只能使用JSON格式。格式样例:

{
"cid": "1000",
"roi": [
"POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))",
"POLYGON((0.5130.232,0.790.1075,0.9280.102,0.9530.64,0.7590.89,0.510.245))",
"POLYGON((0.1150.497,0.5920.82,0.5810.917,0.140.932))"
],
"cross_line": ["LINESTRING(0.070.21,0.360.245,0.580.16,0.970.27)"],
"point": [
"POINT(0.38 0.10)",
"POINT(0.47 0.41)"
]
}

例如当算法支持输入ROI参数时,那么开发者需要在EV_SDK的接口实现中解析上面示例中roi这一值,提取其中的ROI参数,并使用WKTParser对其进行解析,应用到自己的算法逻辑中。

如何在algo_config.json内添加一个自定义配置项?

假定需要在配置文件中添加一个额外的算法阈值参数nms_thresh,则需要:

  1. algo_config.json中加入默认配置参数:

    "nms_thresh": 0.4
  2. Configuration.hpp中的Configuration结构体中添加这一参数对应的变量:

    float nmsThresh = 0.4;
  3. Configuration.hppConfiguration.parseAndUpdateArgs方法中添加对该参数的解析代码:

    cJSON *nmsThreshObj = cJSON_GetObjectItem(confObj, "nms_thresh");
    if (nmsThreshObj != nullptr && nmsThreshObj->type == cJSON_Number) {
    nmsThresh = nmsThreshObj->valuedouble; // 获取默认的阈值
    algoConfig.thresh = newThresh;
    }

为什么不能且不需要修改/usr/local/ev_sdk/test下的代码?

  1. /usr/local/ev_sdk/test下的代码是用于测试ji.h接口在libji.so中是否被正确实现,这一测试程序与EV_SDK的实现无关,且是极市方的测试标准,不能变动;
  2. 编译后test-ji-api程序只会依赖libji.so,如果test-ji-api无法正常运行,很可能是libji.so没有按照规范进行封装;

为什么运行test-ji-api时,会提示找不到链接库?

由于test-ji-api对于算法而言,只链接了/usr/local/ev_sdk/lib/libji.so库,如果test-ji-api运行过程中,找不到某些库,那么很可能是libji.so依赖的某些库找不到了。此时

  1. 可以使用ldd /usr/local/ev_sdk/lib/libji.so检查是否所有链接库都可以找到;
  2. 请按照规范将系统动态库搜索路径以外的库放在/usr/local/ev_sdk/lib目录下。

如何使用test-ji-api进行测试?

  1. 输入单张图片和授权文件,并调用ji_calc_frame接口:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt
  2. 输入json格式的roi参数到args参数:

    ./test-ji-api \
    -f ji_calc_frame \
    -i /path/to/test.jpg \
    -l /path/to/license.txt \
    -a '{"roi":["POLYGON((0.21666666666666667 0.255,0.6924242424242424 0.1375,0.8833333333333333 0.72,0.4106060606060606 0.965,0.048484848484848485 0.82,0.2196969696969697 0.2575))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_frame -i /path/to/test.jpg -l /path/to/license.txt -o /path/to/out.jpg

更多选项,请参考test-ji-api --help

About

服务于极市平台开发者的项目,提供SDK接口文件规范与常见问题示例代码。欢迎所有开发者一起参与示例代码编写。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages