插件框架开发
Vision SDK提供的插件框架,定义了如何生成标准插件,从而实现插件间的数据对接、插件属性设置。Vision SDK目前支持单输入、单输出、多输入、多输出插件。
- 开发插件类。
- 注册属性与获取属性值。属性用于提升插件的通用性,可通过修改pipeline配置文件中插件的属性来实现参数传递,进而达到适配业务的目的。
- 注册元件属性。
用户重写DefineProperties函数,并按照如下方式注册自定义属性:
std::vector<std::shared_ptr<void>> properties; std::shared_ptr<ElementProperty<string>> outputResizeHeight(new ElementProperty<string> {STRING, "resizeHeight", "resizeHeight", "the height of the resized output image", 640, 6, 4096}); properties.push_back(parentNameSptr); return properties;
其中ElementProperty为描述属性的结构体,内容和说明如下:template<class T> struct ElementProperty { PropertyType type; // 属性数据类型,可选STRING, INT, UINT, FLOAT, DOUBLE, LONG, ULONG。 std::string name; // 属性名称,用于获取属性值(在获取属性值章节中介绍)。 std::string nickName; // 属性别名,保留字段。 std::string desc; // 属性描述,介绍该属性的功能。 T defaultValue; // 属性默认值。 T min; // 属性最小值,按需填写,例如STRING类型数据无最小值,可填“NULL”。 T max; // 属性最大值,按需填写,同上。 };
- 获取元件属性值。
在“Init()”函数中,插件对应的属性值将通过“configParamMap”入参传入,可通过属性名称获取。
std::shared_ptr<string> outputResizeHeight = std::static_pointer_cast<string>configParamMap["resizeHeight"]); std::string parentName = *outputResizeHeight.get();
- 注册元件属性。
- (可选)定义端口属性。
插件的输入和输出端口分别用于接收输入数据和发送输出结果,插件支持注册多个输入/输出端口(参考多输入/输出插件端口创建)。
端口类型包括静态和动态两种(参考动态端口创建):静态端口为创建元件后必然生成的端口,端口必须有连接,否则Stream创建失败,动态端口数量可变,根据实际需要创建。
通过重写DefineInputPorts与DefineOutputPorts函数,用户可以定义端口,以单输入静态端口为例,按照如下方式注册端口自定义属性:- “DefineInputPorts”中,通过GenerateStaticInputPortsInfo()接口构建静态输入端口信息MxpiPortInfo,Vision SDK获取“DefineInputPorts”的返回值用于创建端口。
- 接口入参为一个二层vector,内层vector用于定义端口支持的数据格式(端口格式用于区分元件端口是否允许连接,目前已有端口格式请参考表3),例如:"image/jpeg"为JPEG图像解码前数据,用户可以给单个端口定义多个数据格式(以推理插件为例:{"metadata/object", "metadata/class"})。
- 接口外层vector用于区分端口数量,例如:{{"image/jpeg"}, {"metadata/object"}}表示创建两个端口,第一个为“jpeg”格式,第二个为“object”格式。
自定义字符串只支持以英文字母开头,可使用字母,阿拉伯数字与下划线。建议使用"一级类别/二级类别"命名,例如"image/yuv"。
- 同样的方式,在“DefineOutputPorts”定义输出端口。
- 基类中:
MxpiPortInfo MxPluginBase::DefineInputPorts() { MxpiPortInfo defaultInputPortInfo; std::vector<std::vector<std::string>> value = {{"ANY"}}; GenerateStaticInputPortsInfo(value, defaultInputPortInfo); return defaultInputPortInfo; }
- 推理插件中:
MxpiPortInfo MpModelInfer::DefineInputPorts() { MxpiPortInfo inputPortInfo; std::vector<std::vector<std::string>> value = {{"image/yuv"}}; GenerateStaticInputPortsInfo(value, inputPortInfo); return inputPortInfo; }
- 基类中:
目前已开发的插件所使用到的端口格式如表3:
表3 端口格式 端口
类型
原图
image/jpeg
视频
video/x-h264
解码图
image/yuv
image/rgb
目标框
metadata/object
图像类别
metadata/class
图像属性
metadata/attribute
图像特征
metadata/feature-vector
张量
metadata/tensor
绘图单元
metadata/osd
语义分割像素
metadata/semanticseg
纯文本
metadata/texts
目标关键点
metadata/keypoint
序列化结果
result/json-result
兼容任意
ANY,表示可以匹配任意格式数据,即这个端口可以与任意端口相连。
表4 插件描述 插件
输入
输出
简述
mxpi_imagedecoder
image/jpeg
image/yuv或
image/rgb或
metadata/object
图片解码,分块时支持metadata/object。
mxpi_videodecoder
video/x-h264
image/yuv或
image/rgb
视频解码。
mxpi_imageresize
image/yuv或
image/rgb或
metadata/object
image/yuv或
image/rgb
图片缩放。
mxpi_tensorinfer
metadata/tensor或
image/yuv
metadata/tensor
张量推理。输入张量或者图片,输出张量。
mxpi_modelinfer
image/yuv
metadata/object或
metadata/class或
metadata/attribute或
metadata/feature-vector或
metadata/tensor
推理图片,不同模型后处理会得到不同结果:目标框、属性或特征。
不使用后处理时,直接输出推理结果。
mxpi_imagecrop
metadata/objectbox
image/yuv或
image/rgb
图片裁剪。
mxpi_dataserialize
ANY
result/json-result
序列化为JSON字符串。
- 插件框架构建与命名。插件源文件中,通过如下宏构建插件框架(其中“CustomPlugin”为用户自定义插件类名)。
MX_PLUGIN_GENERATE(CustomPlugin)
插件名称对应于pipeline配置文件中的“factory”参数,在插件“CMakeLists.txt”文件中通过以下方式注册(其中“mxpi_customplugin”为插件名)。set(PLUGIN_NAME "mxpi_customplugin") add_compile_options("-DPLUGIN_NAME=${PLUGIN_NAME}")
多输入/输出插件端口创建
插件开发支持用户添加多个输入端口或多个输出端口,多输入多输出插件开发需要增加如下步骤。
- 选择数据的处理模式。
- 同步处理:等待所有输入端口都收到上游发送的数据后调用插件的Process()函数,即保证Process()函数入参的vector中所有输入端口对应序号的数据都存在。
- 异步处理:任意一个输入端口收到上游发送的数据就调用插件的Process()函数,需判断Process()函数入参的vector中的第几个编号存在数据。
处理模式在pipeline中设置为配置参数“status”,“0”为异步,“1”为同步,默认为异步。
图1 通过status配置处理模式 - 修改插件输入接口DefineInputPorts函数的portNum,以推理插件为例,将输入设置成两端口。
MxpiPortInfo MpModelInfer::DefineInputPorts() { MxpiPortInfo inputPortInfo; std::vector<std::vector<std::string>> value = {{"image/yuv"},{"image/yuv"}}; GenerateStaticInputPortsInfo(value, inputPortInfo); return inputPortInfo; }
修改插件输出接口DefineOutputPorts函数的portNum,以推理插件为例,将输出设置成两端口。
MxpiPortInfo MpModelInfer::DefineOutputPorts() { MxpiPortInfo outputPortInfo; std::vector<std::vector<std::string>> value = { {"metadata/object", "metadata/class", "metadata/attribute", "metadata/feature-vector", "metadata/tensor"}, {"metadata/object", "metadata/class", "metadata/attribute", "metadata/feature-vector", "metadata/tensor"} }; GenerateStaticOutputPortsInfo(value, outputPortInfo); return outputPortInfo; }
- 修改pipeline。
- 含多输入端口的元件。
图2 多输入端口元件示例
- 含多输出端口的元件。
图3 多输出端口元件示例
- 含多输入端口的元件。
动态端口创建
动态端口应用于可变输入或输出数据数量的场景,例如同步等待插件(mxpi_synchronize),等待的输入数据个数可以由用户配置。动态端口的数量可变,用户可根据需要通过编辑pipeline配置文件创建。
如图4所示,同步等待插件既可以创建两个也可以创建三个输入端口,图中右侧内容为pipeline配置文件对应内容。