Giter Site home page Giter Site logo

dev-docs's Introduction

EV_SDK

说明

EV_SDK的目标

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

极市平台做了哪些

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

开发者需要做什么

  1. 模型的训练和调优
  2. 实现ji.h约定的接口
  3. 实现约定的输入输出
  4. 其他后面文档提到的功能

目录

代码目录结构

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

使用示例

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

下载EV_SDK

#注意需要下载至/usr/local/ev_sdk
git clone https://github.com/ExtremeMart/dev-docs /usr/local/ev_sdk

编译

编译和安装libji.so

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

编译和安装test-ji-api:

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

测试示例程序和接口规范

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

  1. 使用test-ji-api测试ji_calc_image接口,测试添加了一个ROI参数

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_image -i /usr/local/ev_sdk/data/dog.jpg -o /tmp/output.jpg -a '{"polygon_1":["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: {
       "algorithm_data": {
          "is_alert": true,
          "target_info": [{
             "x": 129,
             "y": 186,
             "width": 240,
             "height": 330,
             "name": "dog",
             "confidence": 0.566484
          }]
       },
       "model_data": {
          "objects": [{
             "x": 129,
             "y": 186,
             "width": 240,
             "height": 330,
             "name": "dog",
             "confidence": 0.566484
          }]
       }
    }

使用EV_SDK快速封装算法

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

实现自己的模型

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

下载EV_SDK

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

实现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和其他依赖的库。

测试接口功能

  1. 检查ji.h的接口规范性

    编译测试工具

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

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

    /usr/local/ev_sdk/bin/test-ji-api -f ji_calc_image \
    -i /usr/local/ev_sdk/data/dog.jpg \
    -o /tmp/output.jpg \
    -a '{"polygon_1":["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的帮助文档及其代码

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

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

  1. ji_calc_image ,用于图片同步分析
  2. ji_calc_image_asyn,用于图片异步分析
  3. ji_face_*,用于人脸识别相关操作

规范要求

规范测试大部分内容依赖于内置的/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-api移动到任意目录,都需要能够正常运行;

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

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

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

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

    • 对于接口中传入的参数args,根据项目需求,算法实现需要支持args实际传入的参数。

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

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

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

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

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

    • 报警时输出:JI_EVENT.code=JISDK_CODE_ALARMJI_EVENT.json内部填充"alert_flag" : true
    • 未报警时输出:JI_EVENT.code=JISDK_CODE_NORMALJI_EVENT.json内部填充"alert_flag" : false
    • 处理失败的接口返回JI_EVENT.code=JISDK_CODE_FAILED
  3. 算法配置选项要求

    • 配置文件必须遵循EV_SDK配置协议

    • 所有算法与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默认值为整张图片区域; 注:多个点、线、框有两种实现方式:

        • 使用WKT格式,如:"roi": "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))"
        • 使用数组形式,如:"roi":["POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))", "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"]

        config/README.md内必须说明使用的是哪一种格式。

      • thresh:算法阈值,需要有可以调整算法灵敏度、召回率、精确率的阈值参数,如果算法配置项有多个参数,请自行扩展,所有与算法效果相关并且可以变动的参数必须/usr/local/ev_sdk/config/README.md中提供详细的配置方法和说明(包括类型、取值范围、建议值、默认值、对算法效果的影响等);

      • draw_resulttrue或者false,是否绘制分析结果,比如示例程序中,如果检测到狗,是否将检测框和文字画在输出图中;

      • draw_confidencetrue或者false,是否将置信度画在检测框顶部,小数点后保留两位;

      • language:所显示文字的语言,需要支持enzh两种选项,分别对应英文和中文;

      • 所有json内的键名称必须是小写字母,并且单词间以下划线分隔,如上面几个示例。

    • 必须支持参数实时更新。所有/usr/local/ev_sdk/config/algo_config.json内的可配置参数必须支持能够在调用ji_calc_imageji_calc_image_asyn接口时,进行实时更新。也就是必须要在ji_calc_*等接口的args参数中,加入这些可配置项。

      根据算法的实际功能和使用场景,参数实时更新功能可能只能够使部分参数有效,其中

      1. 可以通过ji_calc_image等接口的args参数传入并实时更新的参数,比如示例代码中检测框的颜色target_rect_color,这些配置项称为动态参数(即可动态变更);

      2. 其他无法通过args参数传入并进行实时更新的参数称为静态参数,通常这些参数需要重启算法实例才能生效;

        静态参数的名称规范

        静态参数必须以static作为前缀,例如static_detect_thresh

    • 算法开发完成后,必须按照config/README.md的模版,修改成当前算法的配置说明

  4. 算法输出规范要求

    • 算法输出必须遵循极视算法SDK输出协议;
    • 算法必须要输出基础模型的结果,否则不予通过测试
    • model_data表示模型输出的原始数据,用于评估原始算法模型的精度,该键值中的nameclass字段一定要与groundtruth中的完全相同,否则会影响模型性能评估
  5. 文件结构规范要求

    • 与模型相关的文件必须存放在/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是否正确链接了所有的依赖库。

FAQ

如何使用接口中的args

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

{
    "polygon_1": [
        "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))"
    ]
}

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

为什么要定义roi_type字段

不同算法需要的点线框格式不同,为了保证上层应用能正确地下发args参数,需要开发者通过roi_type字段说明算法支持的类型,如:

{
   "roi_type":"polygon_1;"
   "polygon_1": ["POLYGON((0.0480.357,0.1660.0725,0.3930.0075,0.3920.202,0.2420.375))"]
}

如何在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_image接口:

    ./test-ji-api -f ji_calc_image -i /path/to/test.jpg 
  2. 输入json格式的polygon_1参数到args参数:

    ./test-ji-api \
    -f ji_calc_image \
    -i /path/to/test.jpg \
    -a '{"polygon_1":["POLYGON((0.2 0.2,0.7 0.13,0.9 0.7,0.4 0.9,0.05 0.8,0.2 0.25))"]}'
  3. 保存输出图片:

    ./test-ji-api -f ji_calc_image -i /path/to/test.jpg -o /path/to/out.jpg

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

EV_SDK配置协议的实现样例

配置协议规定:

  1. 只能有一级KEY-VALUE
  2. VALUE的类型有两种:
    1. JSON格式定义的非数组和非对象类型,如stringnumberfalsetrue
    2. 由配置协议所定义的数据类型;

举例:

  1. 算法支持多个ROI时的配置,VALUE可以使用协议所定义的多个POLYGON类型:

    {
      "roi_type":"polygon_1;",
      "polygon_1": ["POLYGON ((0.1 0.1, 0.1 0.1, 0.2 0.3, 0.9 0.9))", "POLYGON ((0.1 0.1, 0.1 0.1, 0.2 0.3, 0.9 0.9))"]
    }
  2. 算法需要多个ROI,并且多个每个ROI表示不同逻辑含义时:

    {
      "roi_type":"polygon_1;polygon_2",
      "polygon_1": ["POLYGON ((0.1 0.1, 0.1 0.1, 0.2 0.3, 0.9 0.9))"],
      "polygon_2": ["POLYGON ((0.1 0.1, 0.1 0.1, 0.2 0.3, 0.9 0.9))"]
    }

    算法内部根据polygon_1polygon_2进行逻辑区分。

  3. 如果算法需要以组合的形式配置算法,且组合的数量不设限制时,可用如下配置:

    {
    
      "polygon_1": ["POLYGON ((0.1 0.1, 0.1 0.1, 0.2 0.3, 0.9 0.9))"],
      "line_1": ["LINESTRING (0.1 0.1, 0.12 0.15, 0.2 0.3)"],
      "polygon_2": ["POLYGON ((0.1 0.1, 0.1 0.1, 0.2 0.3, 0.9 0.9))"],
      "line_2": ["LINESTRING (0.1 0.1, 0.12 0.15, 0.2 0.3)"]
      ......
    }

    算法内部需要:

    • 针对字段名称将所设置的值进行组合,例如将polygon_1line_1组合为一组,从而合成自己所需的格式;
    • 对于数量,通过字段的数字后缀来遍历得到,例如当外部传入polygon_3line_3时,算法内部需要自行通过遍历获得这第三组配置

    以上配置方法必须在实现时写入config/README.md配置文档。

  4. 人员闯入算法通常需要配置一个分析区域和一条闯入边界线,可以使用以下配置:

    {
      "roi_type":"polygon_1;cross_line_1",
      "polygon_1": ["POLYGON ((0.1 0.1, 0.1 0.1, 0.2 0.3, 0.9 0.9))"],
      "cross_line_1": ["LINESTRING (0.1 0.1, 0.12 0.15, 0.2 0.3)"]
    }

dev-docs's People

Contributors

extreme-assistant avatar laurenluoyun avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.