diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 000000000..15a15b218
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/R_User_Library.xml b/.idea/libraries/R_User_Library.xml
new file mode 100644
index 000000000..71f5ff749
--- /dev/null
+++ b/.idea/libraries/R_User_Library.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/mindocr-1.iml b/.idea/mindocr-1.iml
new file mode 100644
index 000000000..bba6157d1
--- /dev/null
+++ b/.idea/mindocr-1.iml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 000000000..a2e120dcc
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 000000000..9a6359b4c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..94a25f7f4
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 000000000..51599d441
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,330 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ create
+ create_tran
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1676022469774
+
+
+ 1676022469774
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/deploy/infer_pipeline/README.md b/deploy/infer_pipeline/README.md
new file mode 100644
index 000000000..a685252dc
--- /dev/null
+++ b/deploy/infer_pipeline/README.md
@@ -0,0 +1,650 @@
+# mxOCR
+
+# 1 简介
+
+## 1.1 背景介绍
+
+本参考设计的目的主要包括以下几个方面:
+
+1.为金融、安防、互联网等客户提供基于Atlas做OCR的参考样例,验证可行性;
+
+2.作为客户基于mxBase开发OCR应用的编程样例(下称Demo),开放源代码给客户参考,降低客户准入门槛,包含c++和python两个版本;
+
+3.提供新架构下系统优化案例,打造超高性能原型系统,为客户提供选择Atlas的理由。
+
+本Demo模型选择是面向直排文本,不考虑弯曲文本的情况,并选择JPEG作为输入图像格式,实现识别输入图片中的文字功能。本文档提供对OCR Demo实现方案的说明。
+
+## 1.2 支持的产品
+
+本系统采用Atlas 300I Pro, Atlas 300V, Atlas 300I作为实验验证的硬件平台。
+
+## 1.3 软件方案介绍
+
+软件方案包含OCR的三个环节:文本检测,方向分类,字符识别。其中文本检测和字符识别是必要环节,方向分类为可选环节。
+
+本Demo支持基于Paddle PP-OCR server 2.0的DBNet(检测)和CRNN(识别)模型 与 Paddle PP-OCR3.0的DBNet(检测)和SVTR(识别)模型进行静态分档推理。
+
+本Demo支持Paddle PP-OCR server 2.0的CRNN模型进行动态Shape推理
+(注:Atlas 300I 仅支持静态分档推理)
+
+本Demo的CPP版本支持在310与310P芯片上进行多卡并行推理。
+
+为了提高CPU、NPU资源利用率,实现极致性能,Demo采用了流水并行及多路并行处理方案。
+
+### 代码主要目录介绍
+
+本Demo工程名为mindxsdk-mxocr,根目录下src为源码目录,现将src的子目录介绍如下:
+**注意**:代码目录中的cpp/Modules/DbnetPost下的clipper.cpp、clipper.hpp为开源第三方模块,Demo中不包含这两个文件,需用户自行下载这两个文件,然后放在对应位置。
+clipper.cpp、clipper.hpp文件下载链接:https://udomain.dl.sourceforge.net/project/polyclipping/clipper_ver6.4.2.zip
+
+```
+.
+├── src
+│ └── demo
+│ ├── cpp
+│ │ ├── main.cpp // c++版Demo 主函数
+│ │ ├── build.sh
+│ │ ├── CMakeLists.txt
+│ │ ├── ascendbase
+│ │ │ ├── BlockingQueue // 阻塞队列模块,用于实现流水并行
+│ │ │ ├── CommandParser // 命令行参数解析模块
+│ │ │ ├── ConfigParser // 配置文件解析模块
+│ │ │ └── Framework // 流水并行框架模块
+│ │ ├── config
+│ │ │ └── setup.config // 配置文件
+│ │ └── Modules
+│ │ ├── DataType // 流水并行时各模块间共用的数据结构
+│ │ ├── CrnnPost // crnn 后处理模块
+│ │ ├── DbnetPost // DBNet 后处理模块
+│ │ │ ├── clipper.cpp
+│ │ │ ├── clipper.hpp
+│ │ │ ├── DbnetPost.cpp
+│ │ │ └── DbnetPost.h
+│ │ ├── Processors // 流水并行处理的各个模块
+│ │ │ ├── HandOutProcess // 图片分发模块
+│ │ │ ├── DbnetPreProcess // dbnet前处理操作模块
+│ │ │ ├── DbnetInferProcess // dbnet推理操作模块
+│ │ │ ├── DbnetPostProcess // dbnet后处理操作模块
+│ │ │ ├── ClsPreProcess // 分类模型前处理操作模块
+│ │ │ ├── ClsInferProcess // 分类模型推理操作模块
+│ │ │ ├── ClstPostProcess // 分类模型后处理操作模块
+│ │ │ ├── CrnnPreProcess // 识别模型前处理操作模块
+│ │ │ ├── CrnnInferProcess // 识别模型推理操作模块
+│ │ │ ├── CrnnPostProcess // 识别模型后处理操作模块
+│ │ │ └── CollectProcess // 推理结果保存模块
+│ │ ├── Signal // 程序终止信号处理模块
+│ │ └── Utils // 公共数据结构模块
+│ ├── data
+│ │ ├── auto_gear // 识别模型插入argmax算子脚本
+│ │ │ ├── atc_helper.py // atc转换辅助脚本
+│ │ │ ├── auto_gear.py //自动分档工具脚本
+│ │ │ ├── auto_select.py //识别模型自动选择工具脚本
+│ │ │ └── __init__.py
+│ │ ├── pdmodel2onnx // 识别模型插入argmax算子脚本
+│ │ ├── models // 310P onnx模型转换为om模型脚本
+│ │ └── models_310 // 310 onnx模型转换为om模型脚本
+│ ├── eval_script
+│ │ ├── eval_script.py // 精度测试脚本
+│ │ └── requirements.txt // 精度测试脚本的python三方库依赖文件
+│ └── python
+│ ├── main.py // python版Demo 主函数
+│ ├── requirements.txt // python三方库依赖文件
+│ ├── config // python 版Demo参考配置文件
+│ └── src
+│ ├── data_type //流水并行模块间传输使用的data class
+│ ├── framework //流水并行框架
+│ ├── processors //流水并行模块实现
+│ │ ├── classification
+│ │ │ └── cls //paddle pp-ocr mobile 2.0 相关模块
+│ │ ├── common // 解码,图像分发,mini batch收集 相关模块
+│ │ ├── detection
+│ │ │ └── dbnet //dbnet 相关模块
+│ │ └── recognition
+│ │ └── crnn //crnn 相关模块
+│ └── utils // Demo使用的相关工具
+│
+├── README.md
+└── version.info
+```
+
+# 2 环境搭建
+
+### 2.1 软件依赖说明
+
+**表2-1** 软件依赖说明
+
+| 依赖软件 | 版本 | 依赖说明 |
+| ------------- |-----------------| ------------------ |
+| CANN | 5.1.RC2或6.0.RC1 | 提供基础acl接口 |
+| mxVision | 3.0.RC3 | 提供基础mxBase的能力 |
+
+
+### 2.2 CANN环境变量设置
+
+```bash
+. 安装目录/ascend-toolkit/set_env.sh
+```
+
+### 2.3 mxVision环境变量设置
+
+```bash
+. 安装目录/mxVision/set_env.sh
+```
+
+# 3 模型转换及数据集获取
+
+## 3.1 Demo所用模型下载地址
+
+Paddle PP-OCR server 2.0模型:
+
+| 名称 | 下载链接 |
+| ----------------- | --------------- |
+| Paddle PP-OCR server 2.0 DBNet | https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_det_infer.tar|
+| Paddle PP-OCR server 2.0 Cls | https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar|
+| Paddle PP-OCR server 2.0 CRNN | https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_rec_infer.tar|
+
+
+Paddle PP-OCR 3.0模型:
+
+
+| 名称 | 下载链接 |
+| ----------------- | --------------- |
+| Paddle PP-OCR3.0 DBNet | https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar|
+| Paddle PP-OCR3.0 Cls | https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar|
+| Paddle PP-OCR3.0 SVTR | https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar|
+
+
+
+识别模型字典文件下载地址:
+https://raw.githubusercontent.com/PaddlePaddle/PaddleOCR/release/2.5/ppocr/utils/ppocr_keys_v1.txt
+
+
+**注: ch_ppocr_server_v2.0 与 ch_PP-OCRv3 均使用此名为ch_ppocr_mobile_v2.0_cls_infer的分类模型与名为ppocr_keys_v1.txt的识别模型的字典。**
+
+
+## 3.2 Demo所用测试数据集下载地址
+数据集ICDAR-2019 LSVT下载地址:
+
+
+| 名称 | 下载链接 |
+| ----------------- | --------------- |
+| 图片压缩包1 | https://dataset-bj.cdn.bcebos.com/lsvt/train_full_images_0.tar.gz|
+| 图片压缩包2 | https://dataset-bj.cdn.bcebos.com/lsvt/train_full_images_1.tar.gz|
+| 标注文件 | https://dataset-bj.cdn.bcebos.com/lsvt/train_full_labels.json|
+
+
+图片压缩包名为 train_full_images_0.tar.gz 与 train_full_images_1.tar.gz
+
+标签文件名为 train_full_labels.json
+
+### 3.1.1 数据集准备
+
+#### 3.1.1.1 数据集下载
+命令参考
+```
+wget https://dataset-bj.cdn.bcebos.com/lsvt/train_full_images_0.tar.gz
+wget https://dataset-bj.cdn.bcebos.com/lsvt/train_full_images_1.tar.gz
+wget https://dataset-bj.cdn.bcebos.com/lsvt/train_full_labels.json
+```
+
+#### 3.1.1.2 数据集目录创建
+创建数据集目录
+```
+mkdir -p ./icdar2019/images
+```
+#### 3.1.1.3 解压图片并移动到对应目录
+解压图片压缩包并移动图片到对应目录
+```
+tar -zvxf ./train_full_images_0.tar.gz
+tar -zvxf ./train_full_images_1.tar.gz
+mv train_full_images_0/* ./icdar2019/images
+mv train_full_images_1/* ./icdar2019/images
+rm -r train_full_images_0
+rm -r train_full_images_1
+```
+#### 3.1.1.4 标签格式转换
+label文件格式转换为ICDAR2015格式, 转换脚本位于src/demo/data/label_format_trans/label_format_trans.py
+
+运行标签格式转换脚本工具需要依赖的三方库如下所示:
+**表3-1** label_format_trans.py依赖python三方库
+
+| 名称 | 版本 |
+| ----------------- | --------------- |
+| numpy | =1.22.4|
+| tqdm | =4.64.0|
+
+
+格式转换脚本参考如下:
+```
+python ./label_format_trans.py --label_json_path=/xx/xx/train_full_labels.json --output_path=/xx/xx/icdar2019/
+```
+
+## 3.2 pdmodel模型转换为onnx模型
+- **步骤 1** 将下载好的paddle模型转换成onnx模型。
+执行以下命令安装转换工具paddle2onnx
+ ```
+ pip3 install paddle2onnx==0.9.5
+ ```
+运行paddle2onnx工具需要依赖的三方库如下所示:
+
+**表3-1** paddle2onnx依赖python三方库
+
+| 名称 | 版本 |
+| ----------------- | --------------- |
+| paddlepaddle | 2.3.0|
+
+**DBNet paddle模型转成onnx模型**
+
+PP-OCR server 2.0版本指令参考如下:
+```
+paddle2onnx --model_dir ./ch_ppocr_server_v2.0_det_infer/ --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file ./ch_ppocr_server_v2.0_det_infer.onnx --opset_version 11 --enable_onnx_checker True --input_shape_dict="{'x':[-1,3,-1,-1]}"
+```
+
+Paddle PP-OCR3.0版本指令参考如下:
+```
+paddle2onnx --model_dir ./ch_PP-OCRv3_det_infer/ --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file ./ch_PP-OCRv3_det_infer.onnx --opset_version 11 --enable_onnx_checker True
+```
+
+CRNN paddle模型转成onnx模型指令参考如下:
+```
+paddle2onnx --model_dir ./ch_ppocr_server_v2.0_rec_infer/ --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file ./ch_ppocr_server_v2.0_rec_infer.onnx --opset_version 11 --enable_onnx_checker True --input_shape_dict="{'x':[-1,3,32,-1]}"
+```
+
+SVTR paddle模型转成onnx模型指令参考如下:
+```
+paddle2onnx --model_dir ./ch_PP-OCRv3_rec_infer/ --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file ./ch_PP-OCRv3_rec_infer.onnx --opset_version 11 --enable_onnx_checker True
+```
+
+分类模型转成onnx模型指令参考如下:
+```
+paddle2onnx --model_dir ./ch_ppocr_mobile_v2.0_cls_infer --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file ./ch_ppocr_mobile_v2.0_cls_infer.onnx --opset_version 11 --enable_onnx_checker True
+```
+
+## 3.3 识别模型插入ArgMax算子
+- **步骤 2** 使用算子插入工具insert_argmax给字符识别模型(CRNN/SVTR)插入argmax算子。
+
+转到data/pdmodel2onnx目录下,执行脚本,此处需要传入两个参数:'model_path',对应ch_ppocr_server_v2.0_rec_infer.onnx或ch_PP-OCRv3_rec_infer.onnx模型所在路径;'check_output_onnx',为是否需要针对输出模型做校验,默认值为Ture,可选choices=[True, False]
+
+使用算子插入工具insert_argmax插入argmax算子指令参考:
+ ```
+ python3 insert_argmax.py --model_path /xx/xx/ch_ppocr_server_v2.0_rec_infer.onnx --check_output_onnx True
+ ```
+**表3-2** 使用自动算子插入工具插入argmax算子。
+
+|参数名称 | 参数含义 |默认值 | 可选值|
+| ---------- |----------------------------------------------| ------------|----------|
+| model_path | 对应ch_ppocr_server_v2.0_rec_infer.onnx或ch_PP-OCRv3_rec_infer.onnx模型所在路径 |''|''|
+|check_output_onnx| 是否需要针对输出模型做校验 |True|True,False|
+
+转换出来的结果位于'model_path'路径下,命名为'ch_ppocr_server_v2.0_rec_infer_argmax.onnx' 或 'ch_PP-OCRv3_rec_infer_argmax.onnx'的onnx模型文件。
+
+**表3-3** insert_argmax.py脚本依赖python三方库
+
+| 名称 | 版本 |
+|-------------|----------|
+| onnx | >=1.9.0 |
+| onnxruntime | >=1.13.1 |
+
+## 3.4 静态分档模型转换
+
+****进行静态分档模型转换前需设置CANN环境变量**** 默认的路径为
+```
+. /usr/local/Ascend/ascend-toolkit/set_env.sh
+```
+请以实际安装路径为准
+
+## 3.4.1静态分档工具
+- **步骤 3** 使用静态分档工具auto_gear将onnx模型转换成om模型。
+
+转到data/auto_gear文件下,执行auto_gear静态分档转换。
+
+指令参考如下:
+```
+python auto_gear.py --image_path=/xx/xx/icdar2019/images --gt_path=/xx/xx/icdar2019/labels --det_onnx_path=/xx/xx/ch_ppocr_server_v2.0_det_infer.onnx --rec_onnx_path=/xx/xx/ch_ppocr_server_v2.0_rec_infer_argmax.onnx --rec_model_height=32 --soc_version=Ascend310P3 --output_path=./output
+```
+其中的参数'image_path'和'gt_path'分别为数据集的图片路径与标签路径,具体路径按照实际情况修改;参数'det_onnx_path'为上一步dbnet转换所得的onnx模型;参数'rec_onnx_path'为上一步crnn转换得到的onnx模型再插入argmax算子所得。
+
+**rec_model_height请进行合理的设置,ch_ppocr_server_v2.0_rec_infer_argmax.onnx对应的值是32, ch_PP-OCRv3_rec_infer_argmax.onnx对应的值是48**
+
+输出在同级目录的output文件夹中,为不同挡位的om模型文件。
+
+**表3-4** 静态分档工具auto_gear脚本运行参数。
+
+|参数名称| 参数含义 |默认值|
+|-----|------------------------------------|-----|
+|image_path| 数据集图片所在路径 |""|
+|det_gear_limit| 检测模型限制的档位数量 |100|
+|det_limit_side_len| dbnet前处理指定的最长边的长度 |960|
+|det_strategy| 检测模型档位生成的策略,请在max_min和mean_std中选择 |"mean_std"|
+|det_expand_ratio| 检测模型档位档位的膨胀系数,仅在策略为max_min时生效 |0.2|
+|det_n_std| 检测模型档位档位的膨胀系数,仅在策略为mean_std时生效 |3|
+|det_width_range| 检测模型档位的宽的范围 |"1,8192"|
+|det_height_range| 检测模型档位的高的范围 |"1,8192"|
+|gt_path| 数据集标签txt文件所在路径,格式请使用icdar2015格式 |''|
+|rec_gear_limit| 识别模型限制的档位数量 |32|
+|rec_model_height| 识别模型的高,当模型为CRNN时推荐为32,当模型为SVTR时推荐为48 |''|
+|rec_strategy| 识别模型档位生成的策略,请在max_min和mean_std中选择 |"mean_std"|
+|rec_expand_ratio| 识别模型档位档位的膨胀系数,仅在策略为max_min时生效 |0.2|
+|rec_n_std| 识别模型档位档位的膨胀系数,仅在策略为mean_std时生效 |3|
+|rec_height_range| 识别模型档位的高的范围 |"1,8192"|
+|rec_multi_batch| 识别模型是否使用多batch |True|
+|rec_model_channel| 识别模型的channel数,当输入为gbr/rgb图时为3,当输入为灰度图时为1,只支持1或者3 |3|
+|det_onnx_path| dbnet转换所得的onnx模型路径 |''|
+|rec_onnx_path| crnn/svtr转换得到的onnx模型再插入argmax算子后路径 |''|
+|soc_version| 静态分档模型适配的芯片版本,可选值[Ascend310P3, Ascend310] |Ascend310P3|
+|output_path| 转换完成的静态分档模型的输出路径 |./output|
+
+**注意**:det_gear_limit与rec_gear_limit参数限制的是根据既定策略计算出的档位数,实际的档位数会高于此设置的单位数。
+
+- **步骤 3** 使用自动挑选工具auto_select自动挑选识别om模型。
+
+在data/auto_gear目录下,运行auto_gear.py脚本实现自动挑选om模型,参考命令如下:
+```
+python3 auto_select.py --rec_model_path ./output/crnn
+```
+**表3-5** auto_select.py脚本运行参数
+
+|参数名称|参数含义|默认值|
+|------|------|-----|
+|rec_model_path|识别模型经静态分档后的om模型路径|''|
+|device_id|使用芯片卡编号|0|
+
+输出的om文件保存在rec_model_path同级目录下的'selected'和'unselected'文件夹中。 **请使用selected路径中的模型文件。**
+
+### 3.4.2 分类模型转换
+将onnx模型转换成om模型。转换指令参考src/demo/data/models/cls目录下面的对应的atc转换脚本:
+```
+bash atc.sh
+```
+
+**注: ch_ppocr_server_v2.0 与 ch_PP-OCRv3 均使用此分类模型。**
+
+
+## 3.5 动态Shape模型转换
+
+### 3.5.1 ch_ppocr_server_v2.0_rec模型动态shape
+如需使用动态Shape模型请使用以下路径下的指令进行转换。转换指令参考src/demo/data/models/crnn/目录下面的对应的atc转换脚本:
+```
+bash atc_dynamic.sh
+```
+
+**注:当前仅在Atlas 300I Pro 与 Atlas 300V支持动态shape版本的ch_ppocr_server_v2.0_rec模型**
+
+
+# 4 C++版demo编译运行
+
+## 4.1 系统方案各子模块功能介绍
+表4.1 系统方案各子模块功能:
+
+| 序号 | 子系统 | 功能描述 |
+| ---- | ----------------- | ------------------------------------------------------------ |
+| 1 | 图片分发模块 | 从用户指定的文件夹读取图片,并分发给后续的模块。 |
+| 2 | DBNet模型前处理 | 主要负责解码和缩放,在310P芯片上使用dvpp解码,310芯片使用opencv解码。 |
+| 3 | DBNet模型推理 | 本模块负责将前处理好的图片输入进检测模型并获得模型推理出的Tensor。 |
+| 4 | DBNet模型后处理 | 本模块主要负责将输出的Tensor根据与训练一致的后处理流程将输入图片切割为包含文本的子图。|
+| 5 | Cls模型前处理 | 对dbnet后处理之后切割的子图做resize和归一化操作以及分类模型推理时的batch划分 |
+| 6 | Cls模型推理 | 本模块负责将前处理好的图片输入进分类模型并获得模型推理出的Tensor。 |
+| 7 | Cls模型后处理 | 将模型输出的Tensor根据与训练一致的后处理流程将需要翻转的子图翻转180度。 |
+| 8 | Crnn模型前处理 | 对dbnet后处理之后切割的子图做resize和归一化操作以及识别模型推理时的batch划分 |
+| 9 | Crnn模型推理 | 本模块负责将前处理好的图片输入进识别模型并获得模型推理出的Tensor。支持动态batch和静态分档的推理。 |
+| 10 | Crnn模型后处理 | 将模型输出的Tensor根据字典转换为文字识别的结果。 |
+| 11 | 推理结果保存模块 | 保存推理结果,并在推理结束时发送停止信号。 |
+
+## 4.2 配置
+
+运行前需要在 `/src/demo/cpp/config/setup.config` 配置以下信息
+
+配置程序运行的deviceId,deviceType及模型路径等信息
+**注意**:如果输入图片中包含敏感信息,使用完后请按照当地法律法规要求自行处理,防止信息泄露。
+配置device
+ ```bash
+ deviceId = 0 // 进行推理的device的id, 如需使用多卡进行推理请用逗号隔开device的id, 如 0,1,2,3
+ deviceType = 310P // 310 or 310P
+ ```
+
+配置待模型路径
+ ```bash
+ detModelPath = ./models/dbnet/dbnet_dy_dynamic_shape.om // DBNet模型路径
+ recModelPath = ./models/crnn/static // 识别模型路径, 静态分档时仅需输入包含识别模型的文件夹的路径即可, 动态shape时需要输入模型的路径
+ clsModelPath = ./models/cls/cls_310P.om // 分类模型路径
+ ```
+
+配置文本识别模型输入要求的高、宽的步长、字符标签文件
+ ```bash
+ staticRecModelMode = true // true时采用静态分档, false时采用动态shape
+ recHeight = 32 // 识别模型输入要求的高, 需和crnn转om模型的参数对应 [仅需在使用动态shape模型时配置!]
+ recMinWidth = 320 // 识别模型输入宽的最小值, 需和crnn转om模型的参数对应 [仅需在使用动态shape模型时配置!]
+ recMaxWidth = 2240 // 识别模型输入宽的最大值, 需和crnn转om模型的参数对应 [仅需在使用动态shape模型时配置!]
+ dictPath = ./models/crnn/ppocr_keys_v1.txt // 识别模型字典文件
+ ```
+
+配置识别文字的输出结果路径
+ ```bash
+ saveInferResult = false // 是否保存推理结果到文件, 默认不保存, 如果需要, 该值设置为true, 并配置推理结果保存路径
+ resultPath = ./result // 推理结果保存路径
+ ```
+**注意**:推理结果写文件是追加写的,如果推理结果保存路径中已经存在推理结果文件,推理前请手动删除推理结果文件,如果有需要,提前做好备份。
+
+## 4.3 编译
+
+- **步骤 1** 登录服务器操作后台,安装CANN及mxVision并设置环境变量。
+
+- **步骤 2** 将mxOCR压缩包下载至任意目录,如“/home/HwHiAiUser/mxOCR”,解压。
+
+- **步骤 3** 执行如下命令,构建代码。
+
+ ```
+ cd /home/HwHiAiUser/mxOCR/mindxsdk-mxocr/src/demo/cpp;
+ bash build.sh
+ ```
+
+ *提示:编译完成后会生成可执行文件“main”,存放在“/home/HwHiAiUser/mxOCR/mindxsdk-mxocr/src/demo/cpp/dist/”目录下。*
+
+## 4.4 运行
+**注意 C++ Demo 运行时日志打印调用的是mxVison里面的日志模块,mxVison默认打印日志级别为error,如果需要查看info日志,请将配置文件logging.conf中的console_level值设为 0 。**
+logging.conf文件路径:mxVison安装目录/mxVision/config/logging.conf
+
+### 输入图像约束
+
+仅支持JPEG格式,图片名格式为前缀+下划线+数字的形式,如xxx_xx.jpg。
+
+### 运行程序
+**注意 在模型的档位较多,或者设置并发数过大的情况下,有可能会导致超出device内存。请关注报错信息。**
+
+执行如下命令,启动OCR demo程序。
+
+ ```
+ ./dist/main -i /xx/xx/icdar2019/images/ -t 1 -use_cls false -config ./config/setup.config
+ ```
+
+ 根据屏幕日志确认是否执行成功。
+
+ 识别结果存放在“/home/HwHiAiUser/mxOCR/mindxsdk-mxocr/src/demo/cpp/result”目录下。
+
+*提示:输入./dist/main -h可查看该命令所有信息。运行可使用的参数如表4-2 运行可使用的参数说明所示。*
+
+**表4-2** 运行可使用的参数说明
+
+| 选项 | 意义 | 默认值 |
+| -------------- | ---------------------------------- | -----------------------------|
+| -i | 输入图片所在的文件夹路径 | ./data/imgDir |
+| -t | 运行程序的线程数,请根据环境内存设置合适值。 | 1 |
+| -use_cls | 是否在检测模型之后使用方向分类模型。 | false |
+| -config | 配置文件setup.config的完整路径。 | ./config/setup.config |
+
+### 结果展示
+
+OCR识别结果保存在配置文件中指定路径的infer_img_x.txt中(x 为图片id)
+每个infer_img_x.txt中保存了每个图片文本框四个顶点的坐标位置以及文本内容,格式如下:
+ ```bash
+ 1183,1826,1711,1837,1710,1887,1181,1876,签发机关/Authority
+ 2214,1608,2821,1625,2820,1676,2212,1659,有效期至/Dateofexpin
+ 1189,1590,1799,1606,1797,1656,1187,1641,签发日期/Dateofissue
+ 2238,1508,2805,1528,2802,1600,2235,1580,湖南/HUNAN
+ 2217,1377,2751,1388,2750,1437,2216,1426,签发地点/Placeofis
+ ```
+**注意**:如果输入图片中包含敏感信息,使用完后请按照当地法律法规要求自行处理,防止信息泄露。
+
+# 4.5 动态库依赖说明
+
+Demo动态库依赖可参见代码中“src”目录的“CMakeLists.txt”文件中“target_link_libraries”参数处。
+
+**表4-3** 动态库依赖说明
+
+| 依赖软件 | 说明 |
+| ------------------ | ------------------------------------|
+| libascendcl.so | ACL框架接口,具体介绍可参见ACL接口文档。 |
+| libacl_dvpp.so | ACL框架接口,具体介绍可参见ACL接口文档。 |
+| libpthread.so | C++的线程库。 |
+| libglog.so | c++日志库。 |
+| libopencv_world.so | OpenCV的基本组件,用于图像的基本处理。 |
+| libmxbase.so | 基础SDK的基本组件,用于模型推理及内存拷贝等。|
+
+# 5 Python版demo编译运行
+
+## 5.1 依赖python三方库安装
+Demo运行依赖的三方库如表4-1所示
+
+**表5-1** 依赖python三方库
+
+| 名称 | 版本 |
+| ----------------- | --------------- |
+| shapely | >=1.8.2 |
+| pyclipper | >=1.3.0.post3 |
+| textdistance | >=4.3.0 |
+| numpy | >=1.22.4 |
+| mindx | >=3.0rc3 |
+
+安装命令
+ ```
+ pip3 install + 包名
+ ```
+
+注:mindx的wheel包一般会在安装mxVision的包时自动安装,如果没有成功安装,可以在mxVision的python目录下找到wheel包,并手动pip install。
+
+## 5.2 运行
+
+### 输入图像约束
+
+仅支持JPEG格式,图片名格式为前缀+下划线+数字的形式,如xxx_xx.jpg。
+
+### 修改配置文件
+
+配置文件结构参考
+ ```bash
+# 流水线中模型的排列顺序,当前只支持 [ 'dbnet', 'crnn' ] 与 [ 'dbnet', 'cls', 'crnn' ] 两种输入
+module_order: [ 'dbnet','cls','crnn' ]
+
+# 推理使用的芯片类型,当前只支持'Ascend310P3'与'Ascend310'两种输入,当输入为Ascend310P3时使用DVPP解码,其他情况使用OpenCV解码
+device: 'Ascend310P3'
+
+# 全局设置的芯片编号,支持单个数字或列表输入,当输入为列表时将启用多芯片推理,设置前请用npu-smi info确定芯片id与个数
+device_id: [ 0 ]
+
+# DBNet相关设置,当流水线模型排列中有dbnet时必须设置相关内容
+dbnet:
+ model_path: './models/dbnet/dbnet_dy_dynamic_shape.om' #DBNet模型路径, 输入必须为模型文件的路径
+
+# 分类模型相关设置,当流水线模型排列中有cls时必须设置相关内容
+cls:
+ model_path: './models/cls/cls_310P.om' #分类模型的路径,输入必须为模型文件的路径
+
+# CRNN/SVTR模型相关设置,当流水线模型排列中有crnn时必须设置相关内容
+# 当static_method为True时,输入可以是模型文件的路径或者是仅包含分档识别模型的文件夹的路径。 当static_method为False,输入仅支持模型文件的路径
+# 请使用model_dir输入仅包含分档识别模型的文件夹路径
+# 请使用model_path输入识别模型的文件路径
+crnn:
+ static_method: True #是否使用分档模型,默认为True,当使用动态shape模型时请设置为False
+ model_dir: './models/crnn/static' # 仅包含识别模型文件夹的路径。
+ dict_path: './models/crnn/ppocr_keys_v1.txt' # 识别模型字典的路径,输入必须为识别模型字典的具体路径。
+ device_id: [0] # 指定模型使用device id进行推理,支持单个数字或列表输入。当全局device id与模型指定device id都设置时,优先使用模型指定的device进行推理。默认使用全局device id进行设置。
+ model_height: 32 #识别模型输入要求的高, 需和crnn转om模型的参数对应 [仅需在使用动态shape模型时配置!]
+ model_min_width: 32 #识别模型输入宽的最小值, 需和crnn转om模型的参数对应 [仅需在使用动态shape模型时配置!]
+ model_max_width: 4096 #识别模型输入宽的最大值, 需和crnn转om模型的参数对应 [仅需在使用动态shape模型时配置!]
+ ```
+
+### 运行程序
+**注意 在模型的档位较多,或者设置并发数过大的情况下,有可能会导致超出device内存。请关注报错信息。**
+
+- **步骤 1** 登录服务器操作后台,安装CANN及mxVision并设置环境变量。
+- **步骤 2** 将mxOCR压缩包下载至任意目录,如“/home/HwHiAiUser/mxOCR”,解压。
+- **步骤 3** 执行如下命令,启动OCR demo程序,命令中各个参数路径请根据实际情况指定。
+
+ ```
+ cd /home/HwHiAiUser/mxOCR/mindxsdk-mxocr/src/demo/python;
+ python3 main.py --input_images_path=./input_imgs --config_path=./config/static_ocr_without_cls.yaml
+ --parallel_num=1 --infer_res_save_path=./result
+ ```
+
+ 根据屏幕日志确认是否执行成功。
+
+ 识别结果存放在 --infer_res_save_path 参数指定的目录下。
+
+*提示:输入python3 main -h可查看该命令所有信息。运行可使用的参数如表5-2 运行可使用的参数说明所示。*
+
+**表5-2** 运行可使用的参数说明
+
+| 选项 | 意义 | 默认值 |
+| ------------------------ | --------------------------------------- | -----------------------------|
+| --input_images_path | 输入图片的文件夹路径。 | 必选项,需用户指定 |
+| --config_path | 配置文件输入路径。 | 必选项,需用户指定 |
+| --parallel_num | 并发数,请根据环境内存设置合适值。 | 1 |
+| --infer_res_save_path | 推理结果保存路径。
默认不保存推理结果,需指定输出路径后才会保存。***注意:如果输出路径已经存在,将会抹除输出路径重新创建文件夹*** | "" |
+
+### 结果展示
+
+OCR识别结果保存在配置文件中指定路径的infer_img_x.txt中(x 为图片id)
+每个infer_img_x.txt中保存了每个图片文本框四个顶点的坐标位置以及文本内容,格式如下:
+ ```bash
+ 1183,1826,1711,1837,1710,1887,1181,1876,签发机关/Authority
+ 2214,1608,2821,1625,2820,1676,2212,1659,有效期至/Dateofexpin
+ 1189,1590,1799,1606,1797,1656,1187,1641,签发日期/Dateofissue
+ 2238,1508,2805,1528,2802,1600,2235,1580,湖南/HUNAN
+ 2217,1377,2751,1388,2750,1437,2216,1426,签发地点/Placeofis
+ ```
+**注意**:如果输入图片中包含敏感信息,使用完后请按照当地法律法规要求自行处理,防止信息泄露。
+
+# 6 精度测试脚本使用
+
+## 6.1 依赖python三方库安装
+
+精度测试脚本运行依赖的三方库如表5-1所示
+
+**表6-1** 依赖python三方库
+
+| 名称 | 版本 |
+| ----------------- | --------------- |
+| shapely | >=1.8.2 |
+| numpy | >=1.22.4 |
+| joblib | >=1.1.0 |
+| tqdm | >4.64.0 |
+
+安装命令
+ ```
+ pip3 install + 包名
+ ```
+
+## 6.2 运行
+
+### 运行程序
+
+- **步骤 1** 将mxOCR压缩包下载至任意目录,如“/home/HwHiAiUser/mxOCR”,解压。
+- **步骤 2** 运行ocr Demo生成推理结果文件。
+- **步骤 3** 执行如下命令,启动精度测试脚本,命令中各个参数请根据实际情况指定。
+
+ ```
+ cd /home/HwHiAiUser/mxOCR/mindxsdk-mxocr/src/demo/eval_script;
+ python3 eval_script.py --gt_path=/xx/xx/icdar2019/labels --pred_path=/xx/xx/result
+ ```
+
+ 根据屏幕日志确认是否执行成功。
+
+*运行可使用的参数如表5-2 运行可使用的参数说明所示。*
+
+**表6-2** 运行可使用的参数说明
+
+| 选项 | 意义 | 默认值 |
+| ------------------------ |----------------------| ------------------------|
+| --gt_path | 测试数据集标注文件路径。 | "" |
+| --pred_path | Ocr Demo运行的推理结果存放路径。 | "" |
+| --parallel_num | 并行数。 | 32 |
\ No newline at end of file
diff --git a/deploy/infer_pipeline/src/demo/cpp/CMakeLists.txt b/deploy/infer_pipeline/src/demo/cpp/CMakeLists.txt
new file mode 100644
index 000000000..fcdc0d36a
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/CMakeLists.txt
@@ -0,0 +1,89 @@
+# Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
+cmake_minimum_required(VERSION 3.10.2)
+project(OcrDemo)
+
+add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
+add_definitions(-Dgoogle=mindxsdk_private)
+
+set(PROJECT_SRC_ROOT ${CMAKE_CURRENT_LIST_DIR})
+set(CMAKE_MODULE_PATH ${PROJECT_SRC_ROOT}/CMake)
+set(CMAKE_SKIP_BUILD_RPATH True)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SRC_ROOT}/dist)
+add_compile_options(-std=c++11 -fPIE -fstack-protector-all -Wall)
+add_definitions(-DENABLE_DVPP_INTERFACE)
+
+set(AscendBaseFolder ${PROJECT_SRC_ROOT}/ascendbase)
+
+# Find ascendbase
+set(ASCEND_BASE_DIR ${AscendBaseFolder})
+get_filename_component(ASCEND_BASE_ABS_DIR ${ASCEND_BASE_DIR} ABSOLUTE)
+
+file(GLOB_RECURSE ASCEND_BASE_SRC_FILES
+ ${ASCEND_BASE_ABS_DIR}/BlockingQueue/*cpp
+ ${ASCEND_BASE_ABS_DIR}/ConfigParser/*cpp
+ ${ASCEND_BASE_ABS_DIR}/Framework/ModuleManager/*cpp
+ ${ASCEND_BASE_ABS_DIR}/CommandParser/*cpp
+ )
+
+# Find Header
+set(HEADER_FILE_DIR
+ ${ASCEND_BASE_ABS_DIR}
+ ${ASCEND_BASE_ABS_DIR}/Framework
+ ${PROJECT_SRC_ROOT}/Modules
+ ${PROJECT_SRC_ROOT}/Modules/CrnnPost
+ ${PROJECT_SRC_ROOT}/Modules/DbnetPost
+ ${PROJECT_SRC_ROOT}/Modules/Processors
+ ${PROJECT_SRC_ROOT}/Modules/Signal
+ ${PROJECT_SRC_ROOT}/Modules/Utils
+ )
+include_directories(${HEADER_FILE_DIR})
+
+# Find Src
+file(GLOB_RECURSE SRC_FILE
+ ${PROJECT_SRC_ROOT}/main.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/HandOutProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/DbnetPreProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/DbnetInferProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/DbnetPostProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/ClsPreProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/ClsInferProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/ClsPostProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/CrnnPreProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/CrnnInferProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/CrnnPostProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Processors/CollectProcess/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/CrnnPost/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/DbnetPost/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Signal/*.cpp
+ ${PROJECT_SRC_ROOT}/Modules/Utils/*.cpp
+ )
+
+set(SOURCE_FILE
+ ${SRC_FILE}
+ ${ASCEND_BASE_SRC_FILES}
+ )
+
+set(MX_SDK_HOME $ENV{MX_SDK_HOME})
+set(ASCEND_HOME_PATH $ENV{ASCEND_HOME_PATH})
+set(ARCH_PATTERN $ENV{ARCH_PATTERN})
+include_directories(
+ ${MX_SDK_HOME}/include
+ ${MX_SDK_HOME}/opensource/include
+ ${MX_SDK_HOME}/opensource/include/opencv4
+ ${MX_SDK_HOME}/include/MxBase
+ ${ASCEND_HOME_PATH}/${ARCH_PATTERN}/include
+ ${ASCEND_HOME_PATH}/${ARCH_PATTERN}/runtime/include
+)
+
+link_directories(
+ ${MX_SDK_HOME}/lib
+ ${MX_SDK_HOME}/lib/modelpostprocessors
+ ${MX_SDK_HOME}/include
+ ${MX_SDK_HOME}/opensource/lib
+ ${ASCEND_HOME_PATH}/atc/lib64
+)
+
+# Set the target executable file
+add_executable(main ${SOURCE_FILE})
+
+target_link_libraries(main ascendcl acl_dvpp opencv_world mxbase cpprest glog pthread -Wl,-z,relro,-z,now,-z,noexecstack -pie -s)
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/CrnnPost/CrnnPost.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/CrnnPost/CrnnPost.cpp
new file mode 100644
index 000000000..dfd5ee47a
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/CrnnPost/CrnnPost.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CrnnPost.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "Log/Log.h"
+
+CrnnPost::CrnnPost(void) {}
+
+// trim from end of string (right)
+inline std::string &rtrim(std::string &s)
+{
+ const char *ws = "\n\r";
+ s.erase(s.find_last_not_of(ws) + 1);
+ return s;
+}
+
+void CrnnPost::ClassNameInit(const std::string &fileName)
+{
+ std::ifstream fsIn(fileName);
+ std::string line;
+
+ if (fsIn) { // 有该文件
+ labelVec_.clear();
+ labelVec_.push_back("");
+ while (getline(fsIn, line)) {
+ labelVec_.push_back(rtrim(line));
+ }
+ } else {
+ LogInfo << "no such file";
+ }
+ labelVec_.push_back(" ");
+ fsIn.close();
+
+ classNum_ = labelVec_.size();
+
+ LogInfo << " ClassNameInit classNum_ " << classNum_;
+
+ return;
+}
+
+std::string CrnnPost::GetClassName(const size_t classId)
+{
+ if (classId >= labelVec_.size()) {
+ LogError << "Failed to get classId(" << classId << ") label, size(" << labelVec_.size() << ").";
+ return "";
+ }
+ return labelVec_[classId];
+}
+
+
+void CrnnPost::CalcOutputIndex(void *resHostBuf, size_t batchSize, size_t objectNum, std::vector &resVec)
+{
+ LogDebug << "Start to Process CalcOutputIndex.";
+
+ auto *outputInfo = static_cast(resHostBuf);
+
+ batchSize_ = batchSize;
+ objectNum_ = objectNum;
+
+ for (uint32_t i = 0; i < batchSize_; i++) {
+ int64_t blankIdx = blankIdx_;
+ int64_t previousIdx = blankIdx_;
+ std::string result = "";
+ std::string str = "";
+ for (int64_t j = 0; j < objectNum_; j++) {
+ int64_t outputNum = i * objectNum_ + j;
+ if (outputInfo[outputNum] != blankIdx && outputInfo[outputNum] != previousIdx) {
+ result = GetClassName(outputInfo[outputNum]);
+ str += result;
+ }
+ previousIdx = outputInfo[outputNum];
+ }
+ if (std::strcmp(str.c_str(), "") == 0) {
+ str = "###";
+ }
+
+ resVec[i] = resVec[i] + str;
+ }
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/CrnnPost/CrnnPost.h b/deploy/infer_pipeline/src/demo/cpp/Modules/CrnnPost/CrnnPost.h
new file mode 100644
index 000000000..0d8e841e6
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/CrnnPost/CrnnPost.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CRNNPOST_H
+#define CRNNPOST_H
+
+#include
+#include
+#include
+#include "Utils/Utils.h"
+
+class CrnnPost {
+public:
+ CrnnPost(void);
+
+ ~CrnnPost() {};
+
+ void ClassNameInit(const std::string &fileName);
+
+ std::string GetClassName(const size_t classId);
+
+ void CalcOutputIndex(void *resHostBuf, size_t batchSize, size_t objectNum, std::vector &resVec);
+
+private:
+ std::vector labelVec_ = {}; // labels info
+ uint32_t classNum_ = 0;
+ uint32_t objectNum_ = 200;
+ uint32_t batchSize_ = 0;
+ uint32_t blankIdx_ = 0;
+};
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/DataType/DataType.h b/deploy/infer_pipeline/src/demo/cpp/Modules/DataType/DataType.h
new file mode 100644
index 000000000..e4d979ce3
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/DataType/DataType.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Common data for modules.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_DATATYPE_H
+#define CPP_DATATYPE_H
+
+#include "Utils.h"
+#include "MxBase/MxBase.h"
+
+#include
+#include
+#include
+#include
+
+struct CommonData {
+ // modules info
+ int channelId = {};
+ int imgId = {};
+ int imgTotal = {};
+ int subImgTotal = {};
+
+ // img info
+ std::string imgPath = {};
+ std::string imgName = {};
+ uint32_t srcWidth = {};
+ uint32_t srcHeight = {};
+ cv::Mat frame = {};
+ std::vector imgMatVec = {};
+
+ // infer related
+ uint8_t *imgBuffer = {};
+ std::vector outputTensorVec = {};
+ std::vector resizedImageInfos = {};
+
+ // det info
+ uint32_t resizeWidth = {};
+ uint32_t resizeHeight = {};
+ float ratio = {};
+
+ // cls and rec
+ uint32_t batchSize = {};
+ uint32_t frameSize = {};
+ bool eof = {};
+
+ // rec
+ int maxResizedW = {};
+ float maxWHRatio = {};
+
+ // infer res
+ std::string saveFileName = {};
+ std::vector inferRes = {};
+};
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/DbnetPost/DbnetPost.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/DbnetPost/DbnetPost.cpp
new file mode 100644
index 000000000..1b798a40a
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/DbnetPost/DbnetPost.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+#include "clipper.hpp"
+#include "DbnetPost.h"
+
+DbnetPost::DbnetPost(void) {}
+
+APP_ERROR DbnetPost::DbnetObjectDetectionOutput(std::vector &singleResult,
+ std::vector> &textObjInfos, const std::vector &resizedImageInfos)
+{
+ LogDebug << "DbnetPost start to write results.";
+ uint32_t batchSize = singleResult.size();
+ for (uint32_t i = 0; i < batchSize; i++) {
+ auto ProbMap = (float *)(singleResult[0].GetData());
+ resizedH_ = resizedImageInfos[i].heightResize;
+ resizedW_ = resizedImageInfos[i].widthResize;
+
+ std::vector prob(resizedW_ * resizedH_, ' ');
+ std::vector fprob(resizedW_ * resizedH_, 0.f);
+ for (size_t j = 0; j < resizedW_ * resizedH_; ++j) {
+ prob[j] = (uchar)(ProbMap[j] * MAX_VAL);
+ fprob[j] = (float)ProbMap[j];
+ }
+ cv::Mat mask(resizedH_, resizedW_, CV_8UC1, (uchar *)prob.data());
+ cv::Mat prediction(resizedH_, resizedW_, CV_32F, (float *)fprob.data());
+ cv::Mat binmask;
+
+ cv::threshold(mask, binmask, (float)(thresh_ * MAX_VAL), MAX_VAL, cv::THRESH_BINARY);
+
+
+ std::vector> contours;
+ cv::findContours(binmask, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
+ int contourNum = NpClip(contours.size(), candidates_);
+ std::vector textObjectInfo;
+
+ // traverse and filter all contours
+ for (int j = 0; j < contourNum; j++) {
+ std::vector contour = contours[j];
+ std::vector box;
+ float minSide1 = 0.f;
+ float minSide2 = 0.f;
+ float score = 0.f;
+ // 1st filter
+ FilterByMinSize(contour, box, minSide1);
+ if (minSide1 < minSize_) {
+ continue;
+ }
+ // 2nd filter
+ FilterByBoxScore(prediction, box, score);
+ if (score < boxThresh_) {
+ continue;
+ }
+ // 3rd filter
+ FilterByClippedMinSize(box, minSide2);
+ if (minSide2 < minSize_ + UNCLIP_DISTANCE) {
+ continue;
+ }
+ // write box info into TextObjectInfo
+ ConstructInfo(textObjectInfo, box, resizedImageInfos, i, score);
+ }
+ textObjInfos.emplace_back(std::move(textObjectInfo));
+ }
+
+ return APP_ERR_OK;
+}
+
+void DbnetPost::ConstructInfo(std::vector &textObjectInfo, std::vector &box,
+ const std::vector &resizedImageInfos, const uint32_t &index, float score)
+{
+ uint32_t originWidth = resizedImageInfos[index].widthOriginal;
+ uint32_t originHeight = resizedImageInfos[index].heightOriginal;
+ if (originWidth == 0 || originHeight == 0) {
+ LogError << GetError(APP_ERR_DIVIDE_ZERO) << "the origin width or height must not equal to 0!";
+ return;
+ }
+ if (resizedW_ == 0 || resizedH_ == 0) {
+ LogError << GetError(APP_ERR_DIVIDE_ZERO) << "the resized width or height must not equal to 0!";
+ return;
+ }
+ float ratio = resizedImageInfos[index].ratio;
+
+ TextObjectInfo info;
+ info.x0 = NpClip(std::round(box[POINT1].x / ratio), originWidth);
+ info.y0 = NpClip(std::round(box[POINT1].y / ratio), originHeight);
+ info.x1 = NpClip(std::round(box[POINT2].x / ratio), originWidth);
+ info.y1 = NpClip(std::round(box[POINT2].y / ratio), originHeight);
+ info.x2 = NpClip(std::round(box[POINT3].x / ratio), originWidth);
+ info.y2 = NpClip(std::round(box[POINT3].y / ratio), originHeight);
+ info.x3 = NpClip(std::round(box[POINT4].x / ratio), originWidth);
+ info.y3 = NpClip(std::round(box[POINT4].y / ratio), originHeight);
+ info.confidence = score;
+
+ // check whether current info is valid
+ float side1 = std::sqrt(pow((info.x0 - info.x1), INDEX2) + pow((info.y0 - info.y1), INDEX2));
+ float side2 = std::sqrt(pow((info.x0 - info.x3), INDEX2) + pow((info.y0 - info.y3), INDEX2));
+ float validMinSide = std::max(minSize_ / ratio, minSize_ / ratio);
+ if (std::min(side1, side2) < validMinSide) {
+ return;
+ }
+ textObjectInfo.emplace_back(std::move(info));
+}
+
+void DbnetPost::FilterByMinSize(std::vector &contour, std::vector &box, float &minSide)
+{
+ cv::Point2f cv_vertices[POINTNUM];
+ cv::RotatedRect cvbox = cv::minAreaRect(contour);
+ float width = cvbox.size.width;
+ float height = cvbox.size.height;
+ minSide = std::min(width, height);
+ cvbox.points(cv_vertices);
+ // use vector to manage 4 vertices
+ std::vector vertices(cv_vertices, cv_vertices + POINTNUM);
+ // sort the vertices by x-coordinates
+ std::sort(vertices.begin(), vertices.end(), SortByX);
+ std::sort(vertices.begin(), vertices.begin() + POINT3, SortByY);
+ std::sort(vertices.begin() + POINT3, vertices.end(), SortByY);
+ // save the box
+ box.push_back(vertices[POINT1]);
+ box.push_back(vertices[POINT3]);
+ box.push_back(vertices[POINT4]);
+ box.push_back(vertices[POINT2]);
+}
+
+void DbnetPost::FilterByBoxScore(const cv::Mat &prediction, std::vector &box, float &score)
+{
+ std::vector tmpbox = box;
+ std::sort(tmpbox.begin(), tmpbox.end(), SortByX);
+
+ // construct the mask according to box coordinates.
+ int minX = NpClip(int(std::floor(tmpbox.begin()->x)), resizedW_);
+ int maxX = NpClip(std::ceil(tmpbox.back().x), resizedW_);
+ std::sort(tmpbox.begin(), tmpbox.end(), SortByY);
+ int minY = NpClip(int(std::floor(tmpbox.begin()->y)), resizedH_);
+ int maxY = NpClip(int(std::ceil(tmpbox.back().y)), resizedH_);
+ cv::Mat mask = cv::Mat::zeros(maxY - minY + 1, maxX - minX + 1, CV_8UC1);
+ cv::Mat predCrop;
+ cv::Point abs_point[POINTNUM];
+ for (int i = 0; i < POINTNUM; ++i) {
+ abs_point[i].x = int(box[i].x - minX);
+ abs_point[i].y = int(box[i].y - minY);
+ }
+ const cv::Point *ppt[1] = {abs_point};
+ int npt[] = {4};
+ cv::fillPoly(mask, ppt, npt, 1, cv::Scalar(1));
+
+ // use cv method to calculate the box score
+ prediction(cv::Rect(minX, minY, maxX - minX + 1, maxY - minY + 1)).copyTo(predCrop);
+ score = cv::mean(predCrop, mask)[0];
+}
+
+void DbnetPost::FilterByClippedMinSize(std::vector &box, float &minSide)
+{
+ // calculate the clip distance
+ float side01 = PointsL2Distance(box[POINT1], box[POINT2]);
+ float side12 = PointsL2Distance(box[POINT2], box[POINT3]);
+ float side23 = PointsL2Distance(box[POINT3], box[POINT4]);
+ float side30 = PointsL2Distance(box[POINT4], box[POINT1]);
+ float diag = PointsL2Distance(box[POINT2], box[POINT4]);
+
+ float perimeter = side01 + side12 + side23 + side30;
+ float k1 = (side01 + diag + side30) / INDEX2;
+ float k2 = (side12 + side23 + diag) / INDEX2;
+ float area1 = std::sqrt(k1 * (k1 - side01) * (k1 - diag) * (k1 - side30));
+ float area2 = std::sqrt(k2 * (k2 - side12) * (k2 - side23) * (k2 - diag));
+
+ float area = area1 + area2;
+ float distance = area * unclipRatio_ / perimeter;
+
+ ClipperLib::ClipperOffset rect;
+ ClipperLib::Path path;
+ for (auto point : box) {
+ path.push_back(ClipperLib::IntPoint(int(point.x), int(point.y)));
+ }
+ rect.AddPath(path, ClipperLib::jtRound, ClipperLib::etClosedPolygon);
+ ClipperLib::Paths result;
+ rect.Execute(result, distance);
+
+ std::vector contour;
+ for (size_t i = 0; i < result.size(); ++i) {
+ for (size_t j = 0; j < result[result.size() - 1].size(); ++j) {
+ contour.emplace_back(result[i][j].X, result[i][j].Y);
+ }
+ }
+ // check for exception
+ box.clear();
+ FilterByMinSize(contour, box, minSide);
+}
+
+const int DbnetPost::NpClip(const int &coordinate, const int &sideLen)
+{
+ if (coordinate < 0) {
+ return 0;
+ }
+ if (coordinate > sideLen - 1) {
+ return sideLen - 1;
+ }
+ return coordinate;
+}
+
+bool DbnetPost::SortByX(cv::Point2f p1, cv::Point2f p2)
+{
+ return p1.x < p2.x;
+}
+
+bool DbnetPost::SortByY(cv::Point2f p1, cv::Point2f p2)
+{
+ return p1.y < p2.y;
+}
+
+
+float DbnetPost::PointsL2Distance(cv::Point2f p1, cv::Point2f p2)
+{
+ return std::sqrt(pow((p1.x - p2.x), INDEX2) + pow((p1.y - p2.y), INDEX2));
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/DbnetPost/DbnetPost.h b/deploy/infer_pipeline/src/demo/cpp/Modules/DbnetPost/DbnetPost.h
new file mode 100644
index 000000000..477870064
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/DbnetPost/DbnetPost.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DBNETPOST_H
+#define DBNETPOST_H
+
+#include
+#include "Log/Log.h"
+#include "Utils/Utils.h"
+#include "ErrorCode/ErrorCode.h"
+
+const float THRESH = 0.3;
+const float BOXTHRESH = 0.5;
+const int MIN_SIZE = 3;
+const int MAX_SIZE = 5;
+const int POINT1 = 0;
+const int POINT2 = 1;
+const int POINT3 = 2;
+const int POINT4 = 3;
+const int POINTNUM = 4;
+const int INDEX2 = 2;
+const int MAX_CANDIDATES = 999;
+const int MAX_VAL = 255;
+const float UNCLIP_RATIO = 2;
+const int UNCLIP_DISTANCE = 2;
+
+class DbnetPost {
+public:
+ DbnetPost(void);
+
+ ~DbnetPost() {};
+
+ APP_ERROR DbnetObjectDetectionOutput(std::vector &singleResult,
+ std::vector> &textObjInfos, const std::vector &resizedImageInfos);
+
+private:
+ void FilterByMinSize(std::vector &contour, std::vector &box, float &minSide);
+
+ void FilterByBoxScore(const cv::Mat &prediction, std::vector &box, float &score);
+
+ void FilterByClippedMinSize(std::vector &box, float &minSide);
+
+ void ConstructInfo(std::vector &textObjectInfo, std::vector &box,
+ const std::vector &resizedImageInfos, const uint32_t &index, float score);
+
+ const int NpClip(const int &coordinate, const int &sideLen);
+
+ float PointsL2Distance(cv::Point2f p1, cv::Point2f p2);
+
+ static bool SortByX(cv::Point2f p1, cv::Point2f p2);
+
+ static bool SortByY(cv::Point2f p1, cv::Point2f p2);
+
+ int minSize_ = MIN_SIZE;
+ float thresh_ = THRESH;
+ float boxThresh_ = BOXTHRESH;
+ uint32_t resizedW_;
+ uint32_t resizedH_;
+
+ float unclipRatio_ = UNCLIP_RATIO;
+ int candidates_ = MAX_CANDIDATES;
+};
+
+#endif // DBNETPOST_H
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsInferProcess/ClsInferProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsInferProcess/ClsInferProcess.cpp
new file mode 100644
index 000000000..67605d029
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsInferProcess/ClsInferProcess.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Cls infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "ClsInferProcess.h"
+#include "ClsPostProcess/ClsPostProcess.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+ClsInferProcess::ClsInferProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+ClsInferProcess::~ClsInferProcess() {}
+
+APP_ERROR ClsInferProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "ClsInferProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+ LogInfo << "ClsInferProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+
+APP_ERROR ClsInferProcess::DeInit(void)
+{
+ LogInfo << "ClsInferProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR ClsInferProcess::ParseConfig(ConfigParser &configParser)
+{
+ std::vector deviceIdVec;
+ APP_ERROR ret = configParser.GetVectorUint32Value("deviceId", deviceIdVec);
+ if (ret != APP_ERR_OK || deviceIdVec.empty()) {
+ LogError << "Get device id failed, please check the value of deviceId";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ deviceId_ = (int32_t)deviceIdVec[instanceId_ % deviceIdVec.size()];
+ LogDebug << "deviceId: " << deviceId_;
+
+ std::string clsModelPath;
+ ret = configParser.GetStringValue("clsModelPath", clsModelPath);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get recModelPath failed, please check the value of recModelPath";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ LogDebug << "recModelPath: " << clsModelPath;
+
+ ret = Utils::CheckPath(clsModelPath, "clsModelPath");
+ if (ret != APP_ERR_OK) {
+ LogError << "rec model path: " << clsModelPath << " is not exist of can not read.";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ ClsNet_.reset(new MxBase::Model(clsModelPath, deviceId_));
+ clsHeight = 48;
+ clsWidth = 192;
+ return APP_ERR_OK;
+}
+
+std::vector ClsInferProcess::ClsModelInfer(uint8_t *srcData, uint32_t batchSize, int maxResizedW)
+{
+ LogDebug << "infer: maxResizedW: " << maxResizedW << std::endl;
+
+ std::vector shape;
+ shape.push_back(batchSize);
+ shape.push_back(3);
+ shape.push_back(clsHeight);
+ shape.push_back(clsWidth);
+ MxBase::TensorDType tensorDataType = MxBase::TensorDType::FLOAT32;
+
+ std::vector inputs = {};
+ MxBase::Tensor imageToTensor(srcData, shape, tensorDataType, deviceId_);
+ inputs.push_back(imageToTensor);
+
+ // 选择模型
+
+ LogDebug << "batchSize: " << batchSize;
+ // (2) 开始推理
+ auto inferStartTime = std::chrono::high_resolution_clock::now();
+ ClsOutputs = ClsNet_->Infer(inputs);
+ auto inferEndTime = std::chrono::high_resolution_clock::now();
+ double inferCostTime = std::chrono::duration(inferEndTime - inferStartTime).count();
+ Signal::clsInferTime += inferCostTime;
+ for (auto &output : ClsOutputs) {
+ output.ToHost();
+ }
+ LogInfo << "End Cls Model Infer progress...";
+
+ return ClsOutputs;
+}
+
+APP_ERROR ClsInferProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+ if (data->eof) {
+ SendToNextModule(MT_ClsPostProcess, data, data->channelId);
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::clsInferProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ return APP_ERR_OK;
+ }
+
+ std::vector ClsOutput = ClsModelInfer(data->imgBuffer, data->batchSize, data->maxResizedW);
+ data->outputTensorVec = ClsOutput;
+ if (data->imgBuffer != nullptr) {
+ delete data->imgBuffer;
+ data->imgBuffer = nullptr;
+ }
+ SendToNextModule(MT_ClsPostProcess, data, data->channelId);
+
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::clsInferProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ return APP_ERR_OK;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsInferProcess/ClsInferProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsInferProcess/ClsInferProcess.h
new file mode 100644
index 000000000..fba86eac6
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsInferProcess/ClsInferProcess.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Cls infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_CLSINFERPROCESS_H
+#define CPP_CLSINFERPROCESS_H
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "DataType/DataType.h"
+#include "Signal.h"
+#include "MxBase/MxBase.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+class ClsInferProcess : public ascendBaseModule::ModuleBase {
+public:
+ ClsInferProcess();
+
+ ~ClsInferProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ int clsHeight;
+ int clsWidth;
+ int32_t deviceId_ = 0;
+ std::unique_ptr ClsNet_;
+ std::vector batchSizeList;
+ std::vector ClsOutputs;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ std::vector ClsModelInfer(uint8_t *srcData, uint32_t BatchSize, int maxResizedW);
+};
+
+MODULE_REGIST(ClsInferProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPostProcess/ClsPostProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPostProcess/ClsPostProcess.cpp
new file mode 100644
index 000000000..65cd4e1d6
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPostProcess/ClsPostProcess.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Cls post process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "ClsPostProcess.h"
+#include "CrnnPreProcess/CrnnPreProcess.h"
+#include "MxBase/MxBase.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+ClsPostProcess::ClsPostProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+ClsPostProcess::~ClsPostProcess() {}
+
+APP_ERROR ClsPostProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+
+ AssignInitArgs(initArgs);
+ LogInfo << "ClsPostProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR ClsPostProcess::DeInit(void)
+{
+ LogInfo << "ClsPostProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR ClsPostProcess::PostProcessCls(uint32_t framesSize, std::vector &inferOutput,
+ std::vector &imgMatVec)
+{
+ std::vector shape = inferOutput[0].GetShape();
+ auto *tensorData = (float *)inferOutput[0].GetData();
+ uint32_t dirVecSize = shape[1];
+
+ for (uint32_t i = 0; i < framesSize; i++) {
+ uint32_t index = i * dirVecSize + 1;
+ if (tensorData[index] > 0.9) {
+ cv::rotate(imgMatVec[i], imgMatVec[i], cv::ROTATE_180);
+ }
+ }
+ return APP_ERR_OK;
+}
+
+APP_ERROR ClsPostProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+
+ if (!data->eof) {
+ APP_ERROR ret = PostProcessCls(data->frameSize, data->outputTensorVec, data->imgMatVec);
+ if (ret != APP_ERR_OK) {
+ return ret;
+ }
+ }
+ SendToNextModule(MT_CrnnPreProcess, data, data->channelId);
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::clsPostProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ return APP_ERR_OK;
+}
\ No newline at end of file
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPostProcess/ClsPostProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPostProcess/ClsPostProcess.h
new file mode 100644
index 000000000..5eca0d0b6
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPostProcess/ClsPostProcess.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Cls post process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_CLSPOSTPROCESS_H
+#define CPP_CLSPOSTPROCESS_H
+
+#include
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "Signal.h"
+#include "DataType/DataType.h"
+#include "MxBase/MxBase.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+class ClsPostProcess : public ascendBaseModule::ModuleBase {
+public:
+ ClsPostProcess();
+
+ ~ClsPostProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ APP_ERROR PostProcessCls(uint32_t framesSize, std::vector &inferOutput,
+ std::vector &imgMatVec);
+};
+
+MODULE_REGIST(ClsPostProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPreProcess/ClsPreProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPreProcess/ClsPreProcess.cpp
new file mode 100644
index 000000000..4b0873852
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPreProcess/ClsPreProcess.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Cls pre process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include
+#include "ClsPreProcess.h"
+#include "ClsInferProcess/ClsInferProcess.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+ClsPreProcess::ClsPreProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+ClsPreProcess::~ClsPreProcess() {}
+
+APP_ERROR ClsPreProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "ClsPreProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+ clsHeight = 48;
+ clsWidth = 192;
+
+ LogInfo << "ClsPreProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR ClsPreProcess::DeInit(void)
+{
+ LogInfo << "ClsPreProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR ClsPreProcess::ParseConfig(ConfigParser &configParser)
+{
+ std::string clsModelPath;
+ APP_ERROR ret = configParser.GetStringValue("clsModelPath", clsModelPath);
+ if (ret != APP_ERR_OK) {
+ LogError << "Parse the config file path failed, please check if the path is correct.";
+ return ret;
+ }
+ std::string baseName = Utils::BaseName(clsModelPath) + ".bin";
+ std::string modelConfigPath("./temp/cls/");
+ Utils::LoadFromFileVec(modelConfigPath + baseName, batchSizeList);
+
+ return APP_ERR_OK;
+}
+
+uint8_t *ClsPreProcess::PreprocessCls(std::vector &frames, uint32_t BatchSize)
+{
+ cv::Mat resizedImg;
+ cv::Mat inImg;
+
+ uint32_t bufferlen = Utils::RgbImageSizeF32(clsWidth, clsHeight);
+ auto *srcData = new uint8_t[bufferlen * BatchSize];
+
+ int pos = 0;
+ for (uint32_t i = 0; i < frames.size(); i++) {
+ inImg = frames[i];
+ float ratio = float(inImg.cols) / float(inImg.rows);
+ int resize_w;
+ if (std::ceil(clsHeight * ratio) > clsWidth)
+ resize_w = clsWidth;
+ else
+ resize_w = int(std::ceil(clsHeight * ratio));
+ cv::resize(inImg, resizedImg, cv::Size(resize_w, clsHeight), 0.f, 0.f, cv::INTER_LINEAR);
+ if (resize_w < clsWidth) {
+ cv::copyMakeBorder(resizedImg, resizedImg, 0, 0, 0, clsWidth - resize_w, cv::BORDER_CONSTANT,
+ cv::Scalar(0, 0, 0));
+ }
+
+ resizedImg.convertTo(resizedImg, CV_32FC3, 1.0 / 255);
+ resizedImg = (resizedImg - 0.5) / 0.5;
+
+ std::vector channels;
+ cv::split(resizedImg, channels);
+
+ // Transform NHWC to NCHW
+ uint32_t size = Utils::RgbImageSizeF32(clsWidth, clsHeight);
+ uint8_t *buffer = Utils::ImageNchw(channels, size);
+
+ // 把padding后的图片都组装起来
+ memcpy(srcData + pos, buffer, bufferlen);
+ pos += bufferlen;
+ delete[] buffer;
+ }
+
+ return srcData;
+}
+
+std::vector ClsPreProcess::GetClsBatchSize(uint32_t frameSize)
+{
+ int lastIndex = batchSizeList.size() - 1;
+ std::vector splitList(frameSize / batchSizeList[lastIndex], batchSizeList[lastIndex]);
+ frameSize = frameSize - batchSizeList[lastIndex] * (frameSize / batchSizeList[lastIndex]);
+ if (!frameSize) {
+ return splitList;
+ }
+ for (auto bs : batchSizeList) {
+ if (frameSize <= bs) {
+ splitList.push_back(bs);
+ break;
+ }
+ }
+ return splitList;
+}
+
+APP_ERROR ClsPreProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+ uint32_t totalSize = data->imgMatVec.size();
+ if (totalSize == 0) {
+ data->eof = true;
+ SendToNextModule(MT_ClsInferProcess, data, data->channelId);
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::clsPreProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ return APP_ERR_OK;
+ }
+
+ std::vector splitIndex = GetClsBatchSize(totalSize);
+ int startIndex = 0;
+ for (unsigned int &bs : splitIndex) {
+ std::shared_ptr dataNew = std::make_shared();
+
+ std::vector resizedImageInfosCls;
+ std::vector input(data->imgMatVec.begin() + startIndex,
+ data->imgMatVec.begin() + std::min(startIndex + bs, totalSize));
+ std::vector splitRes(data->inferRes.begin() + startIndex,
+ data->inferRes.begin() + std::min(startIndex + bs, totalSize));
+
+ uint8_t *ClsInput = PreprocessCls(input, bs);
+
+ dataNew->eof = false;
+ dataNew->outputTensorVec = data->outputTensorVec;
+ dataNew->imgName = data->imgName;
+ dataNew->inferRes = splitRes;
+ dataNew->imgTotal = data->imgTotal;
+ dataNew->imgMatVec = input;
+
+ dataNew->resizedImageInfos = resizedImageInfosCls;
+ dataNew->batchSize = bs;
+ dataNew->imgBuffer = ClsInput;
+ dataNew->frameSize = std::min(startIndex + bs, totalSize) - startIndex;
+ dataNew->maxWHRatio = data->maxWHRatio;
+ dataNew->saveFileName = data->saveFileName;
+ dataNew->subImgTotal = data->subImgTotal;
+ dataNew->imgId = data->imgId;
+
+ startIndex += bs;
+ SendToNextModule(MT_ClsInferProcess, dataNew, data->channelId);
+ }
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::clsPreProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+
+ return APP_ERR_OK;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPreProcess/ClsPreProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPreProcess/ClsPreProcess.h
new file mode 100644
index 000000000..8af5e763d
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/ClsPreProcess/ClsPreProcess.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Cls pre process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_CLSPREPROCESS_H
+#define CPP_CLSPREPROCESS_H
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "Utils.h"
+#include "DataType/DataType.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+#include "Signal.h"
+
+class ClsPreProcess : public ascendBaseModule::ModuleBase {
+public:
+ ClsPreProcess();
+
+ ~ClsPreProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ int clsHeight = 48;
+ int clsWidth = 192;
+ int32_t deviceId_ = 0;
+ std::vector batchSizeList;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ std::vector GetClsBatchSize(uint32_t frameSize);
+
+ uint8_t *PreprocessCls(std::vector &frames, uint32_t batchSize);
+};
+
+MODULE_REGIST(ClsPreProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CollectProcess/CollectProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CollectProcess/CollectProcess.cpp
new file mode 100644
index 000000000..a13210537
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CollectProcess/CollectProcess.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: collect profiling and infer result data process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "CollectProcess.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+CollectProcess::CollectProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+CollectProcess::~CollectProcess() {}
+
+APP_ERROR CollectProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "CollectProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+
+ LogInfo << "CollectProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR CollectProcess::DeInit(void)
+{
+ LogInfo << "CollectProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR CollectProcess::ParseConfig(ConfigParser &configParser)
+{
+ configParser.GetBoolValue("saveInferResult", saveInferResult);
+ if (saveInferResult) {
+ configParser.GetStringValue("resultPath", resultPath);
+ if (resultPath[resultPath.size() - 1] != '/') {
+ resultPath += "/";
+ }
+ }
+
+ return APP_ERR_OK;
+}
+
+void CollectProcess::SignalSend(int imgTotal)
+{
+ if (inferSize == imgTotal) {
+ Signal::GetInstance().GetStopedThreadNum()++;
+ if (Signal::GetInstance().GetStopedThreadNum() == Signal::GetInstance().GetThreadNum()) {
+ Signal::signalRecieved = true;
+ }
+ }
+}
+
+APP_ERROR CollectProcess::Process(std::shared_ptr commonData)
+{
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+ if (saveInferResult) {
+ std::ofstream outfile(resultPath + data->saveFileName, std::ios::out | std::ios::app);
+ std::string line;
+ for (uint32_t i = 0; i < data->frameSize; i++) {
+ std::string finalRes = data->inferRes[i];
+ outfile << finalRes << std::endl;
+ }
+ outfile.close();
+ LogInfo << "----------------------- Save infer result to " << data->saveFileName << " succeed.";
+ }
+
+ auto it = idMap.find(data->imgId);
+ if (it == idMap.end()) {
+ int remaining = data->subImgTotal - data->inferRes.size();
+ if (remaining) {
+ idMap.insert({ data->imgId, remaining });
+ } else {
+ inferSize += 1;
+ }
+ } else {
+ it->second -= data->inferRes.size();
+ if (it->second == 0) {
+ idMap.erase(it);
+ inferSize += 1;
+ }
+ }
+
+
+ SignalSend(data->imgTotal);
+ return APP_ERR_OK;
+}
\ No newline at end of file
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CollectProcess/CollectProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CollectProcess/CollectProcess.h
new file mode 100644
index 000000000..bc2105c3b
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CollectProcess/CollectProcess.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: collect profiling and infer result data process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_COLLECTPROCESS_H
+#define CPP_COLLECTPROCESS_H
+
+#include
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "Signal.h"
+#include "DataType/DataType.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+
+class CollectProcess : public ascendBaseModule::ModuleBase {
+public:
+ CollectProcess();
+
+ ~CollectProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ std::string resultPath;
+ bool saveInferResult = false;
+
+ std::unordered_map idMap;
+ int inferSize = 0;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ void SignalSend(int imgTotal);
+};
+
+MODULE_REGIST(CollectProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnInferProcess/CrnnInferProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnInferProcess/CrnnInferProcess.cpp
new file mode 100644
index 000000000..8e27495a0
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnInferProcess/CrnnInferProcess.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "CrnnInferProcess.h"
+#include "CrnnPostProcess/CrnnPostProcess.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+CrnnInferProcess::CrnnInferProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+CrnnInferProcess::~CrnnInferProcess() {}
+
+APP_ERROR CrnnInferProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "CrnnInferProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+ LogInfo << "CrnnInferProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+
+APP_ERROR CrnnInferProcess::DeInit(void)
+{
+ LogInfo << "CrnnInferProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR CrnnInferProcess::ParseConfig(ConfigParser &configParser)
+{
+ std::vector deviceIdVec;
+ APP_ERROR ret = configParser.GetVectorUint32Value("deviceId", deviceIdVec);
+ if (ret != APP_ERR_OK || deviceIdVec.empty()) {
+ LogError << "Get device id failed, please check the value of deviceId";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ deviceId_ = (int32_t)deviceIdVec[instanceId_ % deviceIdVec.size()];
+
+ configParser.GetBoolValue("staticRecModelMode", staticMethod);
+ LogDebug << "staticMethod: " << staticMethod;
+
+ configParser.GetIntValue("recHeight", mStdHeight);
+ LogDebug << "mStdHeight: " << mStdHeight;
+
+ std::string pathExpr;
+ ret = configParser.GetStringValue("recModelPath", pathExpr);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get recModelPath failed, please check the value of recModelPath";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ LogDebug << "recModelPath: " << pathExpr;
+
+ ret = Utils::CheckPath(pathExpr, "recModelPath");
+ if (ret != APP_ERR_OK) {
+ LogError << "rec model path: " << pathExpr << " is not exist of can not read.";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+
+ if (staticMethod) {
+ std::vector files;
+ Utils::GetAllFiles(pathExpr, files);
+ for (auto &file : files) {
+ crnnNet_.push_back(new MxBase::Model(file, deviceId_));
+ std::vector> dynamicGearInfo = crnnNet_[crnnNet_.size() - 1]->GetDynamicGearInfo();
+ mStdHeight = dynamicGearInfo[0][2];
+ batchSizeList.push_back(dynamicGearInfo[0][0]);
+ }
+ std::sort(batchSizeList.begin(), batchSizeList.end(), Utils::UintCompare);
+ std::sort(crnnNet_.begin(), crnnNet_.end(), Utils::ModelCompare);
+ } else {
+ crnnNet_.push_back(new MxBase::Model(pathExpr, deviceId_));
+ }
+
+ return APP_ERR_OK;
+}
+
+std::vector CrnnInferProcess::CrnnModelInfer(uint8_t *srcData, uint32_t batchSize, int maxResizedW)
+{
+ LogDebug << "infer: maxResizedW: " << maxResizedW << std::endl;
+
+ std::vector shape;
+ shape.push_back(batchSize);
+ shape.push_back(3);
+ shape.push_back(mStdHeight);
+ shape.push_back(maxResizedW);
+ MxBase::TensorDType tensorDataType = MxBase::TensorDType::FLOAT32;
+
+ std::vector inputs = {};
+ MxBase::Tensor imageToTensor(srcData, shape, tensorDataType, deviceId_);
+ inputs.push_back(imageToTensor);
+
+ // 选择模型
+ int modelIndex = 0;
+ if (staticMethod) {
+ auto it = find(batchSizeList.begin(), batchSizeList.end(), batchSize);
+ modelIndex = it - batchSizeList.begin();
+ }
+
+ LogDebug << "batchSize: " << batchSize;
+ LogDebug << "modelIndex: " << modelIndex;
+ // (2) 开始推理
+ auto inferStartTime = std::chrono::high_resolution_clock::now();
+ crnnOutputs = crnnNet_[modelIndex]->Infer(inputs);
+ auto inferEndTime = std::chrono::high_resolution_clock::now();
+ double inferCostTime = std::chrono::duration(inferEndTime - inferStartTime).count();
+ Signal::recInferTime += inferCostTime;
+ for (auto &output : crnnOutputs) {
+ output.ToHost();
+ }
+ LogInfo << "End Crnn Model Infer progress...";
+
+ return crnnOutputs;
+}
+
+APP_ERROR CrnnInferProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+ if (data->eof) {
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::recInferProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ SendToNextModule(MT_CrnnPostProcess, data, data->channelId);
+ return APP_ERR_OK;
+ }
+
+ std::vector crnnOutput = CrnnModelInfer(data->imgBuffer, data->batchSize, data->maxResizedW);
+ data->outputTensorVec = crnnOutput;
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ if (data->imgBuffer != nullptr) {
+ delete data->imgBuffer;
+ data->imgBuffer = nullptr;
+ }
+
+ Signal::recInferProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ SendToNextModule(MT_CrnnPostProcess, data, data->channelId);
+
+ return APP_ERR_OK;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnInferProcess/CrnnInferProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnInferProcess/CrnnInferProcess.h
new file mode 100644
index 000000000..f2dbc3574
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnInferProcess/CrnnInferProcess.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_CRNNINFERPROCESS_H
+#define CPP_CRNNINFERPROCESS_H
+
+#include "CrnnPost.h"
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "DataType/DataType.h"
+#include "Signal.h"
+#include "MxBase/MxBase.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+class CrnnInferProcess : public ascendBaseModule::ModuleBase {
+public:
+ CrnnInferProcess();
+
+ ~CrnnInferProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ int mStdHeight = 48;
+ int32_t deviceId_ = 0;
+ bool staticMethod = true;
+ std::vector crnnNet_;
+ std::vector batchSizeList;
+ std::vector crnnOutputs;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ std::vector CrnnModelInfer(uint8_t *srcData, uint32_t BatchSize, int maxResizedW);
+};
+
+MODULE_REGIST(CrnnInferProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPostProcess/CrnnPostProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPostProcess/CrnnPostProcess.cpp
new file mode 100644
index 000000000..f8498ba4b
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPostProcess/CrnnPostProcess.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn post process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "CrnnPostProcess.h"
+#include "CollectProcess/CollectProcess.h"
+#include "MxBase/MxBase.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+CrnnPostProcess::CrnnPostProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+CrnnPostProcess::~CrnnPostProcess() {}
+
+APP_ERROR CrnnPostProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "CrnnPostProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+ crnnPost_.ClassNameInit(recDictionary);
+
+ LogInfo << "CrnnPostProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR CrnnPostProcess::DeInit(void)
+{
+ LogInfo << "CrnnPostProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR CrnnPostProcess::ParseConfig(ConfigParser &configParser)
+{
+ APP_ERROR ret = configParser.GetStringValue("dictPath", recDictionary);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get dictPath failed, please check the value of dictPath";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ ret = Utils::CheckPath(recDictionary, "character label file");
+ if (ret != APP_ERR_OK) {
+ LogError << "Character label file: " << recDictionary << " is not exist of can not read.";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ LogDebug << "dictPath: " << recDictionary;
+
+ configParser.GetBoolValue("saveInferResult", saveInferResult);
+ if (saveInferResult) {
+ configParser.GetStringValue("resultPath", resultPath);
+ if (resultPath[resultPath.size() - 1] != '/') {
+ resultPath += "/";
+ }
+ }
+
+ return APP_ERR_OK;
+}
+
+APP_ERROR CrnnPostProcess::PostProcessCrnn(uint32_t framesSize, std::vector &inferOutput,
+ std::vector &textsInfos)
+{
+ auto *objectinfo = (int64_t *)inferOutput[0].GetData();
+ auto objectNum = (size_t)inferOutput[0].GetShape()[1];
+ crnnPost_.CalcOutputIndex(objectinfo, framesSize, objectNum, textsInfos);
+
+ return APP_ERR_OK;
+}
+
+APP_ERROR CrnnPostProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+ std::vector recResVec;
+ if (!data->eof) {
+ APP_ERROR ret = PostProcessCrnn(data->frameSize, data->outputTensorVec, data->inferRes);
+ if (ret != APP_ERR_OK) {
+ return ret;
+ }
+ }
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+
+ Signal::recPostProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ SendToNextModule(MT_CollectProcess, data, data->channelId);
+ return APP_ERR_OK;
+}
\ No newline at end of file
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPostProcess/CrnnPostProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPostProcess/CrnnPostProcess.h
new file mode 100644
index 000000000..6fc07f8f9
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPostProcess/CrnnPostProcess.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn post process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_CRNNPOSTPROCESS_H
+#define CPP_CRNNPOSTPROCESS_H
+
+#include
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "Signal.h"
+#include "DataType/DataType.h"
+#include "MxBase/MxBase.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+#include "CrnnPost.h"
+
+class CrnnPostProcess : public ascendBaseModule::ModuleBase {
+public:
+ CrnnPostProcess();
+
+ ~CrnnPostProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ CrnnPost crnnPost_;
+ std::string recDictionary;
+ std::string resultPath;
+ bool saveInferResult = false;
+
+ std::unordered_set idSet;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ APP_ERROR PostProcessCrnn(uint32_t framesSize, std::vector &inferOutput,
+ std::vector &textsInfos);
+};
+
+MODULE_REGIST(CrnnPostProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPreProcess/CrnnPreProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPreProcess/CrnnPreProcess.cpp
new file mode 100644
index 000000000..695ab68d6
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPreProcess/CrnnPreProcess.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "CrnnPreProcess.h"
+#include "CrnnInferProcess/CrnnInferProcess.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+CrnnPreProcess::CrnnPreProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+CrnnPreProcess::~CrnnPreProcess() {}
+
+APP_ERROR CrnnPreProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "CrnnPreProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+ useCls = Utils::EndsWith(initArgs.pipelineName, "true");
+
+ if (staticMethod) {
+ std::string tempPath("./temp/crnn");
+ std::vector files;
+ Utils::GetAllFiles(tempPath, files);
+ for (auto &file : files) {
+ std::vector nameInfo;
+ Utils::StrSplit(file, ".", nameInfo);
+ batchSizeList.push_back(uint64_t(std::stoi(nameInfo[nameInfo.size() - 2])));
+ if (gearInfo.empty()) {
+ Utils::LoadFromFilePair(file, gearInfo);
+ }
+ }
+
+ std::sort(gearInfo.begin(), gearInfo.end(), Utils::PairCompare);
+ std::sort(batchSizeList.begin(), batchSizeList.end(), Utils::UintCompare);
+ recMaxWidth = gearInfo[gearInfo.size() - 1].second;
+ recMinWidth = gearInfo[0].second;
+ mStdHeight = gearInfo[0].first;
+ }
+
+
+ LogInfo << recMinWidth << " " << recMaxWidth << " " << mStdHeight;
+
+ LogInfo << "CrnnPreProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR CrnnPreProcess::DeInit(void)
+{
+ LogInfo << "CrnnPreProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR CrnnPreProcess::ParseConfig(ConfigParser &configParser)
+{
+ configParser.GetIntValue("recHeight", mStdHeight);
+ LogDebug << "recHeight: " << mStdHeight;
+
+ APP_ERROR ret = configParser.GetBoolValue("staticRecModelMode", staticMethod);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get staticRecModelMode failed, please check the value of staticRecModelMode";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ LogDebug << "staticRecModelMode: " << staticMethod;
+
+ if (ret != APP_ERR_OK) {
+ LogError << "Get recBatchSize failed, please check the value of recBatchSize";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+
+ if (ret != APP_ERR_OK) {
+ LogError << "Parse the config file path failed, please check if the path is correct.";
+ return ret;
+ }
+
+ if (!staticMethod) {
+ ret = configParser.GetIntValue("recMinWidth", recMinWidth);
+ LogDebug << "recMinWidth: " << recMinWidth;
+ if (ret != APP_ERR_OK) {
+ LogError << "Get recMinWidth failed, please check the value of recMinWidth";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ if (recMinWidth < 1) {
+ LogError << "recMinWidth: " << recMinWidth << " is less than 1, not valid";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ recMaxWidth = std::ceil(float(recMinWidth) / 32.0) * 32;
+
+ ret = configParser.GetIntValue("recMaxWidth", recMaxWidth);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get recMaxWidth failed, please check the value of recMaxWidth";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ if (recMaxWidth < 1) {
+ LogError << "recMaxWidth: " << recMaxWidth << " is less than 1, not valid";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ recMaxWidth = std::floor(float(recMaxWidth) / 32.0) * 32;
+ LogDebug << "recMaxWidth: " << recMaxWidth;
+ }
+ return APP_ERR_OK;
+}
+
+void CrnnPreProcess::GetGearInfo(int maxResizedW, std::pair &gear)
+{
+ if (maxResizedW <= recMaxWidth) {
+ auto info = std::upper_bound(gearInfo.begin(), gearInfo.end(),
+ std::pair(mStdHeight, maxResizedW), Utils::GearCompare);
+ gear = gearInfo[info - gearInfo.begin()];
+ }
+}
+
+
+int CrnnPreProcess::GetCrnnMaxWidth(std::vector frames, float maxWHRatio)
+{
+ int maxResizedW = 0;
+ for (auto &frame : frames) {
+ int resizedW;
+ int imgH = frame.rows;
+ int imgW = frame.cols;
+ float ratio = imgW / float(imgH);
+ int maxWidth = int(maxWHRatio * mStdHeight);
+ if (std::ceil(mStdHeight * ratio) > maxWidth) {
+ resizedW = maxWidth;
+ } else {
+ resizedW = int(std::ceil(mStdHeight * ratio));
+ }
+ maxResizedW = std::max(resizedW, maxResizedW);
+ maxResizedW = std::max(std::min(maxResizedW, recMaxWidth), recMinWidth);
+ }
+ std::pair gear;
+ if (staticMethod) {
+ GetGearInfo(maxResizedW, gear);
+ } else {
+ gear.second = std::ceil(maxResizedW / 32.0) * 32;
+ }
+
+ return gear.second;
+}
+
+uint8_t *CrnnPreProcess::PreprocessCrnn(std::vector &frames, uint32_t BatchSize, int maxResizedW,
+ float maxWHRatio, std::vector &resizedImageInfos)
+{
+ cv::Mat resizedImg;
+ cv::Mat inImg;
+ cv::Mat outImg;
+ int resizedW;
+ int imgH;
+ int imgW;
+ uint32_t bufferlen = Utils::RgbImageSizeF32(maxResizedW, mStdHeight);
+ uint8_t *srcData = new uint8_t[bufferlen * BatchSize];
+
+ int pos = 0;
+ for (uint32_t i = 0; i < frames.size(); i++) {
+ inImg = frames[i];
+ imgH = inImg.rows;
+ imgW = inImg.cols;
+ float ratio = imgW / float(imgH);
+ int maxWidth = int(maxWHRatio * mStdHeight);
+ if (std::ceil(mStdHeight * ratio) > maxWidth) {
+ resizedW = maxWidth;
+ } else {
+ resizedW = int(std::ceil(mStdHeight * ratio));
+ }
+ resizedW = std::min(resizedW, recMaxWidth);
+ cv::resize(inImg, resizedImg, cv::Size(resizedW, mStdHeight));
+ int paddingLen = maxResizedW - resizedW;
+ if (paddingLen > 0) {
+ cv::copyMakeBorder(resizedImg, resizedImg, 0, 0, 0, paddingLen, cv::BORDER_CONSTANT, 0);
+ }
+
+ LogDebug << "input image [" << i << "] size / preprocessed image size: " << inImg.size() << "/" <<
+ resizedImg.size();
+
+ ResizedImageInfo ResizedInfo;
+ ResizedInfo.widthResize = resizedW;
+ ResizedInfo.heightResize = mStdHeight;
+ ResizedInfo.widthOriginal = inImg.cols;
+ ResizedInfo.heightOriginal = inImg.rows;
+ resizedImageInfos.emplace_back(std::move(ResizedInfo));
+
+ outImg = resizedImg;
+ outImg.convertTo(outImg, CV_32FC3, 1.0 / 255);
+ outImg = (outImg - 0.5) / 0.5;
+
+ // GRAY channel means
+ std::vector channels;
+ cv::split(outImg, channels);
+
+ // Transform NHWC to NCHW
+ uint32_t size = Utils::RgbImageSizeF32(maxResizedW, mStdHeight);
+ uint8_t *buffer = Utils::ImageNchw(channels, size);
+
+ // 把padding后的图片都组装起来
+ memcpy(srcData + pos, buffer, bufferlen);
+ pos += bufferlen;
+ delete[] buffer;
+ }
+
+ return srcData;
+}
+
+std::vector CrnnPreProcess::GetCrnnBatchSize(uint32_t frameSize)
+{
+ int lastIndex = batchSizeList.size() - 1;
+ std::vector splitList(frameSize / batchSizeList[lastIndex], batchSizeList[lastIndex]);
+ frameSize = frameSize - batchSizeList[lastIndex] * (frameSize / batchSizeList[lastIndex]);
+ if (!frameSize) {
+ return splitList;
+ }
+ for (auto bs : batchSizeList) {
+ if (frameSize <= bs) {
+ splitList.push_back(bs);
+ break;
+ }
+ }
+ return splitList;
+}
+
+APP_ERROR CrnnPreProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+ uint32_t totalSize = data->imgMatVec.size();
+ if (totalSize == 0) {
+ data->eof = true;
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::recPreProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ SendToNextModule(MT_CrnnInferProcess, data, data->channelId);
+ return APP_ERR_OK;
+ }
+
+ std::vector splitIndex = { totalSize };
+ if (staticMethod) {
+ splitIndex = GetCrnnBatchSize(totalSize);
+ }
+
+ int startIndex = 0;
+ int shareId = 0;
+ for (size_t i = 0; i < splitIndex.size(); i++) {
+ std::shared_ptr dataNew = std::make_shared();
+
+ std::vector resizedImageInfosCrnn;
+ std::vector input(data->imgMatVec.begin() + startIndex,
+ data->imgMatVec.begin() + std::min(startIndex + splitIndex[i], totalSize));
+ std::vector splitRes(data->inferRes.begin() + startIndex,
+ data->inferRes.begin() + std::min(startIndex + splitIndex[i], totalSize));
+ int maxResizedW = GetCrnnMaxWidth(input, data->maxWHRatio);
+
+ uint8_t *crnnInput = PreprocessCrnn(input, splitIndex[i], maxResizedW, data->maxWHRatio, resizedImageInfosCrnn);
+ shareId++;
+
+ dataNew->eof = false;
+ dataNew->outputTensorVec = data->outputTensorVec;
+ dataNew->imgName = data->imgName;
+ dataNew->inferRes = splitRes;
+ dataNew->imgTotal = data->imgTotal;
+ dataNew->maxResizedW = maxResizedW;
+
+ dataNew->resizedImageInfos = resizedImageInfosCrnn;
+ dataNew->batchSize = splitIndex[i];
+ dataNew->imgBuffer = crnnInput;
+ dataNew->saveFileName = data->saveFileName;
+ dataNew->frameSize = std::min(startIndex + splitIndex[i], totalSize) - startIndex;
+ dataNew->subImgTotal = data->subImgTotal;
+ dataNew->imgId = data->imgId;
+
+ startIndex += splitIndex[i];
+ SendToNextModule(MT_CrnnInferProcess, dataNew, data->channelId);
+ }
+
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::recPreProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+
+ return APP_ERR_OK;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPreProcess/CrnnPreProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPreProcess/CrnnPreProcess.h
new file mode 100644
index 000000000..aee6bc896
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/CrnnPreProcess/CrnnPreProcess.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn pre process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_CRNNPREPROCESS_H
+#define CPP_CRNNPREPROCESS_H
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "Utils.h"
+#include "DataType/DataType.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Signal.h"
+#include "Log/Log.h"
+
+class CrnnPreProcess : public ascendBaseModule::ModuleBase {
+public:
+ CrnnPreProcess();
+
+ ~CrnnPreProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ int mStdHeight = 48;
+ int recMinWidth = 320;
+ int recMaxWidth = 2240;
+ bool staticMethod = true;
+ bool useCls = false;
+ std::vector> gearInfo;
+ std::vector batchSizeList;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ std::vector GetCrnnBatchSize(uint32_t frameSize);
+
+ int GetCrnnMaxWidth(std::vector frames, float maxWHRatio);
+
+ uint8_t *PreprocessCrnn(std::vector &frames, uint32_t batchSize, int maxResizedW, float maxWHRatio,
+ std::vector &resizedImageInfos);
+
+ void GetGearInfo(int maxResizedW, std::pair &gear);
+};
+
+MODULE_REGIST(CrnnPreProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetInferProcess/DbnetInferProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetInferProcess/DbnetInferProcess.cpp
new file mode 100644
index 000000000..27b949638
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetInferProcess/DbnetInferProcess.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Dbnet infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "DbnetInferProcess.h"
+#include "DbnetPostProcess/DbnetPostProcess.h"
+#include
+
+using namespace ascendBaseModule;
+
+DbnetInferProcess::DbnetInferProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+DbnetInferProcess::~DbnetInferProcess() {}
+
+APP_ERROR DbnetInferProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "DbnetInferProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+
+ LogInfo << "DbnetInferProcess [" << instanceId_ << "] Init success.";
+ return ret;
+}
+
+APP_ERROR DbnetInferProcess::DeInit(void)
+{
+ LogInfo << "DbnetInferProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR DbnetInferProcess::ParseConfig(ConfigParser &configParser)
+{
+ std::vector deviceIdVec;
+ APP_ERROR ret = configParser.GetVectorUint32Value("deviceId", deviceIdVec);
+ if (ret != APP_ERR_OK || deviceIdVec.empty()) {
+ LogError << "Get device id failed, please check the value of deviceId";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ deviceId_ = (int32_t)deviceIdVec[instanceId_ % deviceIdVec.size()];
+ std::string detModelPath;
+ ret = configParser.GetStringValue("detModelPath", detModelPath);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get detModelPath failed, please check the value of detModelPath";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ ret = Utils::CheckPath(detModelPath, "detModelPath");
+ if (ret != APP_ERR_OK) {
+ LogError << "detModelPath: " << detModelPath << " is not exist or can not read.";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ LogDebug << "detModelPath: " << detModelPath;
+
+ dbNet_.reset(new MxBase::Model(detModelPath, deviceId_));
+ LogInfo << deviceId_;
+ return APP_ERR_OK;
+}
+
+APP_ERROR DbnetInferProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+
+ std::vector shape;
+ uint32_t batchSize = 1;
+ shape.push_back(batchSize);
+ shape.push_back(3);
+ shape.push_back(data->resizeHeight);
+ shape.push_back(data->resizeWidth);
+ MxBase::TensorDType tensorDataType = MxBase::TensorDType::FLOAT32;
+
+ MxBase::Tensor imageToTensor(data->imgBuffer, shape, tensorDataType, deviceId_);
+
+ std::vector inputs = {};
+ inputs.push_back(imageToTensor);
+
+ // (2) 开始推理
+ auto inferStartTime = std::chrono::high_resolution_clock::now();
+ dbNetoutputs = dbNet_->Infer(inputs);
+ auto inferEndTime = std::chrono::high_resolution_clock::now();
+ double inferCostTime = std::chrono::duration(inferEndTime - inferStartTime).count();
+ Signal::detInferTime += inferCostTime;
+ LogInfo << " [" << data->imgName << "] dbnet infer time cost: " << inferCostTime << "ms.";
+
+ LogDebug << "c: " << dbNetoutputs[0].GetShape()[1];
+ LogDebug << "h: " << dbNetoutputs[0].GetShape()[2];
+ LogDebug << "w: " << dbNetoutputs[0].GetShape()[3];
+ LogDebug << "End Model Infer progress...";
+ LogDebug << "current imgName: " << data->imgName;
+ LogDebug << "current resizeHeight: " << data->resizeHeight;
+ LogDebug << "current resizeWidth: " << data->resizeWidth;
+
+ const size_t outputLen = dbNetoutputs.size();
+ if (outputLen <= 0) {
+ LogError << "Failed to get model output data";
+ return APP_ERR_INFER_GET_OUTPUT_FAIL;
+ }
+ for (auto &output : dbNetoutputs) {
+ output.ToHost();
+ }
+
+
+ std::vector res = { dbNetoutputs[0] };
+ data->outputTensorVec = res;
+
+
+ if (data->imgBuffer != nullptr) {
+ delete data->imgBuffer;
+ data->imgBuffer = nullptr;
+ }
+ SendToNextModule(MT_DbnetPostProcess, data, data->channelId);
+
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::detInferProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+ return APP_ERR_OK;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetInferProcess/DbnetInferProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetInferProcess/DbnetInferProcess.h
new file mode 100644
index 000000000..77283010f
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetInferProcess/DbnetInferProcess.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Dbnet infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_DBNETINFERPROCESS_H
+#define CPP_DBNETINFERPROCESS_H
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "DataType/DataType.h"
+#include "Signal.h"
+#include "MxBase/MxBase.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+class DbnetInferProcess : public ascendBaseModule::ModuleBase {
+public:
+ DbnetInferProcess();
+
+ ~DbnetInferProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ int32_t deviceId_ = 0;
+ std::unique_ptr dbNet_;
+ std::vector dbNetoutputs;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+};
+
+MODULE_REGIST(DbnetInferProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPostProcess/DbnetPostProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPostProcess/DbnetPostProcess.cpp
new file mode 100644
index 000000000..e16dd28fa
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPostProcess/DbnetPostProcess.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Dbnet post process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "DbnetPostProcess.h"
+#include "CrnnPreProcess/CrnnPreProcess.h"
+#include "ClsPreProcess//ClsPreProcess.h"
+#include "DbnetPost.h"
+#include "Utils.h"
+
+using namespace ascendBaseModule;
+
+DbnetPostProcess::DbnetPostProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+DbnetPostProcess::~DbnetPostProcess() {}
+
+APP_ERROR DbnetPostProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "DbnetPostProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+
+ bool useCls = Utils::EndsWith(initArgs.pipelineName, "true");
+ if (useCls) {
+ nextModule = MT_ClsPreProcess;
+ } else {
+ nextModule = MT_CrnnPreProcess;
+ }
+ LogInfo << "DbnetPostProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR DbnetPostProcess::DeInit(void)
+{
+ LogInfo << "DbnetPostProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR DbnetPostProcess::ParseConfig(ConfigParser &configParser)
+{
+ APP_ERROR ret = configParser.GetBoolValue("saveInferResult", saveInferResult);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get saveInferResult failed, please check the value of saveInferResult";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ if (saveInferResult) {
+ ret = configParser.GetStringValue("resultPath", resultPath);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get resultPath failed, please check the value of resultPath";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ if (access(resultPath.c_str(), 0) == -1) {
+ int retCode = system(("mkdir -p " + resultPath).c_str());
+ if (retCode == -1) {
+ LogError << "Can not create dir [" << resultPath << "], please check the value of resultPath.";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ LogInfo << resultPath << " create!";
+ }
+ }
+
+ return APP_ERR_OK;
+}
+
+
+APP_ERROR DbnetPostProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+
+ std::vector resizedImageInfos;
+ ResizedImageInfo ResizedInfo;
+
+ ResizedInfo.widthResize = data->resizeWidth;
+ ResizedInfo.heightResize = data->resizeHeight;
+ ResizedInfo.widthOriginal = data->srcWidth;
+ ResizedInfo.heightOriginal = data->srcHeight;
+ ResizedInfo.ratio = data->ratio;
+ resizedImageInfos.emplace_back(std::move(ResizedInfo));
+
+ std::vector> textObjInfos;
+
+ DbnetPost DbnetPost;
+ DbnetPost.DbnetObjectDetectionOutput(data->outputTensorVec, textObjInfos, resizedImageInfos);
+
+ std::vector resizeImgs;
+ std::vector inferRes;
+ float maxWHRatio = 0;
+
+ for (uint32_t i = 0; i < textObjInfos.size(); i++) {
+ std::vector textInfo = textObjInfos[i];
+ for (uint32_t j = 0; j < textInfo.size(); j++) {
+ LogDebug << "#Obj " << j;
+ LogDebug << "x0 " << textInfo[j].x0 << " y0 " << textInfo[j].y0;
+ LogDebug << "x1 " << textInfo[j].x1 << " y1 " << textInfo[j].y1;
+ LogDebug << "x2 " << textInfo[j].x2 << " y2 " << textInfo[j].y2;
+ LogDebug << "x3 " << textInfo[j].x3 << " y3 " << textInfo[j].y3;
+ LogDebug << "confidence: " << textInfo[j].confidence;
+
+ cv::Mat resizeimg;
+ std::string str = std::to_string((int)textInfo[j].x1) + "," + std::to_string((int)textInfo[j].y1) + "," +
+ std::to_string((int)textInfo[j].x2) + "," + std::to_string((int)textInfo[j].y2) + "," +
+ std::to_string((int)textInfo[j].x3) + "," + std::to_string((int)textInfo[j].y3) + "," +
+ std::to_string((int)textInfo[j].x0) + "," + std::to_string((int)textInfo[j].y0) + ",";
+ inferRes.push_back(str);
+
+ float cropWidth = CalcCropWidth(textInfo[j]);
+ float cropHeight = CalcCropHeight(textInfo[j]);
+
+ // 期望透视变换后二维码四个角点的坐标
+ cv::Point2f dst_points[4];
+ cv::Point2f src_points[4];
+ // 通过Image Watch查看的二维码四个角点坐标
+ src_points[0] = cv::Point2f(textInfo[j].x0, textInfo[j].y0);
+ src_points[1] = cv::Point2f(textInfo[j].x1, textInfo[j].y1);
+ src_points[2] = cv::Point2f(textInfo[j].x2, textInfo[j].y2);
+ src_points[3] = cv::Point2f(textInfo[j].x3, textInfo[j].y3);
+
+ dst_points[0] = cv::Point2f(0.0, 0.0);
+ dst_points[1] = cv::Point2f(cropWidth, 0.0);
+ dst_points[2] = cv::Point2f(cropWidth, cropHeight);
+ dst_points[3] = cv::Point2f(0.0, cropHeight);
+
+ cv::Mat H = cv::getPerspectiveTransform(src_points, dst_points);
+
+ cv::Mat rotation;
+
+ cv::Mat img_warp = cv::Mat(cropHeight, cropWidth, CV_8UC3);
+ cv::warpPerspective(data->frame, img_warp, H, img_warp.size());
+ int imgH = img_warp.rows;
+ int imgW = img_warp.cols;
+ if (imgH * 1.0 / imgW >= 1.5) {
+ cv::rotate(img_warp, img_warp, cv::ROTATE_90_COUNTERCLOCKWISE);
+ imgH = img_warp.rows;
+ imgW = img_warp.cols;
+ }
+ maxWHRatio = std::max(maxWHRatio, float(imgW) / float(imgH));
+ resizeImgs.emplace_back(img_warp);
+ }
+ }
+ data->maxWHRatio = maxWHRatio;
+ data->imgMatVec = resizeImgs;
+ data->inferRes = inferRes;
+ data->subImgTotal = resizeImgs.size();
+ SendToNextModule(nextModule, data, data->channelId);
+
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::detPostProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+
+ return APP_ERR_OK;
+}
+
+float DbnetPostProcess::CalcCropWidth(const TextObjectInfo &textObject)
+{
+ float x0 = std::abs(textObject.x1 - textObject.x0);
+ float y0 = std::abs(textObject.y1 - textObject.y0);
+ float line0 = sqrt(std::pow(x0, 2) + std::pow(y0, 2));
+
+ float x1 = std::abs(textObject.x2 - textObject.x3);
+ float y1 = std::abs(textObject.y2 - textObject.y3);
+ float line1 = std::sqrt(std::pow(x1, 2) + std::pow(y1, 2));
+
+ return line1 > line0 ? line1 : line0;
+}
+
+float DbnetPostProcess::CalcCropHeight(const TextObjectInfo &textObject)
+{
+ float x0 = std::abs(textObject.x0 - textObject.x3);
+ float y0 = std::abs(textObject.y0 - textObject.y3);
+ float line0 = sqrt(std::pow(x0, 2) + std::pow(y0, 2));
+
+ float x1 = std::abs(textObject.x1 - textObject.x2);
+ float y1 = std::abs(textObject.y1 - textObject.y2);
+ float line1 = std::sqrt(std::pow(x1, 2) + std::pow(y1, 2));
+
+ return line1 > line0 ? line1 : line0;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPostProcess/DbnetPostProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPostProcess/DbnetPostProcess.h
new file mode 100644
index 000000000..5321b3031
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPostProcess/DbnetPostProcess.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Dbnet post process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_DBNETPOSTPROCESS_H
+#define CPP_DBNETPOSTPROCESS_H
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "DataType/DataType.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Signal.h"
+#include "Log/Log.h"
+
+class DbnetPostProcess : public ascendBaseModule::ModuleBase {
+public:
+ DbnetPostProcess();
+
+ ~DbnetPostProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ bool saveInferResult = false;
+ std::string resultPath;
+ std::string nextModule;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ static float CalcCropWidth(const TextObjectInfo &textObject);
+
+ static float CalcCropHeight(const TextObjectInfo &textObject);
+};
+
+MODULE_REGIST(DbnetPostProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPreProcess/DbnetPreProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPreProcess/DbnetPreProcess.cpp
new file mode 100644
index 000000000..52beb0acf
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPreProcess/DbnetPreProcess.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Dbnet pre process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "DbnetPreProcess.h"
+#include "DbnetInferProcess/DbnetInferProcess.h"
+
+#include "MxBase/MxBase.h"
+#include
+#include
+#include
+#include
+
+using namespace ascendBaseModule;
+
+DbnetPreProcess::DbnetPreProcess()
+{
+ withoutInputQueue_ = false;
+ isStop_ = false;
+}
+
+DbnetPreProcess::~DbnetPreProcess() {}
+
+APP_ERROR DbnetPreProcess::Init(ConfigParser &confiPgarser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(confiPgarser);
+ if (ret != APP_ERR_OK) {
+ LogError << "DbnetPreProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+
+ if (deviceType_ == "310P") {
+ imageProcessor.reset(new MxBase::ImageProcessor(deviceId_));
+ }
+ LogInfo << "DbnetPreProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR DbnetPreProcess::DeInit(void)
+{
+ LogInfo << "DbnetPreProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR DbnetPreProcess::ParseConfig(ConfigParser &configParser)
+{
+ APP_ERROR ret = configParser.GetStringValue("deviceType", deviceType_);
+ if (ret != APP_ERR_OK) {
+ LogError << "Get device type failed, please check the value of deviceType";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ if (deviceType_ != "310P" && deviceType_ != "310") {
+ LogError << "Device type only support 310 or 310P, please check the value of device type.";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+
+ std::vector deviceIdVec;
+ ret = configParser.GetVectorUint32Value("deviceId", deviceIdVec);
+ if (ret != APP_ERR_OK || deviceIdVec.empty()) {
+ LogError << "Get device id failed, please check the value of deviceId";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+ deviceId_ = (int32_t)deviceIdVec[instanceId_ % deviceIdVec.size()];
+ if (deviceId_ < 0) {
+ LogError << "Device id: " << deviceId_ << " is less than 0, not valid";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+
+ std::string detModelPath;
+ ret = configParser.GetStringValue("detModelPath", detModelPath);
+ if (ret != APP_ERR_OK) {
+ LogError << "Parse the config file path failed, please check if the path is correct.";
+ return ret;
+ }
+
+ std::string baseName = Utils::BaseName(detModelPath) + ".1.bin";
+ std::string modelConfigPath("./temp/dbnet/");
+ Utils::LoadFromFilePair(modelConfigPath + baseName, gearInfo);
+ std::sort(gearInfo.begin(), gearInfo.end(), Utils::PairCompare);
+ uint64_t hwSum = 0;
+ for (auto &pair : gearInfo) {
+ uint64_t h = pair.first;
+ uint64_t w = pair.second;
+ MaxH = MaxH > h ? MaxH : h;
+ MaxW = MaxW > w ? MaxW : w;
+ if (h * w > hwSum) {
+ hwSum = h * w;
+ maxDotGear.first = h;
+ maxDotGear.second = w;
+ }
+ }
+
+ return APP_ERR_OK;
+}
+
+void DbnetPreProcess::getMatchedGear(const cv::Mat &inImg, std::pair &gear)
+{
+ uint64_t imgH = inImg.rows;
+ uint64_t imgW = inImg.cols;
+ if (imgH > MaxH || imgW > MaxW) {
+ gear = maxDotGear;
+ } else {
+ auto info = std::upper_bound(gearInfo.begin(), gearInfo.end(), std::pair(imgH, imgW),
+ Utils::GearCompare);
+ gear = gearInfo[info - gearInfo.begin()];
+ }
+}
+
+void DbnetPreProcess::resize(const cv::Mat &inImg, cv::Mat &outImg, const std::pair &gear,
+ float &ratio_)
+{
+ int imgH = inImg.rows;
+ int imgW = inImg.cols;
+ int gearH = gear.first;
+ int gearW = gear.second;
+ float ratio = 1.f;
+ if (imgH > gearH || imgW > gearW) {
+ if (imgH > imgW) {
+ ratio = float(gearH) / float(imgH);
+ int resizeByH = int(ratio * float(imgW));
+ if (resizeByH > gearW) {
+ ratio = float(gearW) / float(imgW);
+ }
+ } else {
+ ratio = float(gearW) / float(imgW);
+ int resizeByW = int(ratio * float(imgH));
+ if (resizeByW > gearH) {
+ ratio = float(gearH) / float(imgH);
+ }
+ }
+ }
+ int resizeH = int(float(imgH) * ratio);
+ int resizeW = int(float(imgW) * ratio);
+ cv::resize(inImg, outImg, cv::Size(resizeW, resizeH));
+ ratio_ = float(resizeH) / float(imgH);
+}
+
+void DbnetPreProcess::padding(cv::Mat &inImg, const std::pair &gear)
+{
+ int imgH = inImg.rows;
+ int imgW = inImg.cols;
+ int gearH = gear.first;
+ int gearW = gear.second;
+ int paddingH = gearH - imgH;
+ int paddingW = gearW - imgW;
+ if (paddingH || paddingW) {
+ cv::copyMakeBorder(inImg, inImg, 0, paddingH, 0, paddingW, cv::BORDER_CONSTANT, 0);
+ }
+}
+
+cv::Mat DbnetPreProcess::DecodeImgDvpp(std::string imgPath)
+{
+ MxBase::Image decodedImage;
+ imageProcessor->Decode(imgPath, decodedImage, MxBase::ImageFormat::BGR_888);
+ decodedImage.ToHost();
+
+ MxBase::Size imgOriSize = decodedImage.GetOriginalSize();
+ MxBase::Size imgSize = decodedImage.GetSize();
+ cv::Mat imgBGR;
+ imgBGR.create(imgSize.height, imgSize.width, CV_8UC3);
+ imgBGR.data = (uchar *)decodedImage.GetData().get();
+ cv::Rect area(0, 0, imgOriSize.width, imgOriSize.height);
+ imgBGR = imgBGR(area).clone();
+ return imgBGR;
+}
+
+void DbnetPreProcess::normalizeByChannel(std::vector &bgr_channels)
+{
+ for (uint32_t i = 0; i < bgr_channels.size(); i++) {
+ bgr_channels[i].convertTo(bgr_channels[i], CV_32FC1, 1.0 * scale_[i], (0.0 - mean_[i]) * scale_[i]);
+ }
+}
+
+APP_ERROR DbnetPreProcess::Process(std::shared_ptr commonData)
+{
+ auto startTime = std::chrono::high_resolution_clock::now();
+ std::shared_ptr data = std::static_pointer_cast(commonData);
+ std::string imgPath = data->imgPath;
+
+ std::chrono::high_resolution_clock::time_point dbPreEndTime;
+ cv::Mat inImg;
+ if (deviceType_ == "310P") {
+ inImg = DecodeImgDvpp(imgPath);
+ } else {
+ inImg = cv::imread(imgPath);
+ }
+ data->frame = inImg;
+ data->srcWidth = inImg.cols;
+ data->srcHeight = inImg.rows;
+ cv::Mat resizedImg;
+ cv::Mat outImg;
+
+ inImg.convertTo(inImg, CV_32FC3, 1.0 / 255.0);
+ std::pair gear;
+ getMatchedGear(inImg, gear);
+
+ float ratio = 0;
+ resize(inImg, resizedImg, gear, ratio);
+
+ padding(resizedImg, gear);
+
+ // Normalize: y = (x - mean) / std
+ std::vector bgr_channels(3);
+ cv::split(resizedImg, bgr_channels);
+ normalizeByChannel(bgr_channels);
+
+ // Transform NHWC to NCHW
+ uint32_t size = Utils::RgbImageSizeF32(resizedImg.cols, resizedImg.rows);
+ uint8_t *buffer = Utils::ImageNchw(bgr_channels, size);
+
+ data->eof = false;
+ data->channelId = 0;
+ data->imgBuffer = buffer;
+ data->resizeWidth = resizedImg.cols;
+ data->resizeHeight = resizedImg.rows;
+ data->ratio = ratio;
+ SendToNextModule(MT_DbnetInferProcess, data, data->channelId);
+ auto endTime = std::chrono::high_resolution_clock::now();
+ double costTime = std::chrono::duration(endTime - startTime).count();
+ Signal::detPreProcessTime += costTime;
+ Signal::e2eProcessTime += costTime;
+
+ return APP_ERR_OK;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPreProcess/DbnetPreProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPreProcess/DbnetPreProcess.h
new file mode 100644
index 000000000..e9414756b
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/DbnetPreProcess/DbnetPreProcess.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Dbnet pre process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_DBNETPREPROCESS_H
+#define CPP_DBNETPREPROCESS_H
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "DataType/DataType.h"
+#include "Utils.h"
+#include "Signal.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+class DbnetPreProcess : public ascendBaseModule::ModuleBase {
+public:
+ DbnetPreProcess();
+
+ ~DbnetPreProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ std::string deviceType_;
+ int32_t deviceId_ = 0;
+
+ std::unique_ptr imageProcessor;
+ uint64_t MaxH = 0;
+ uint64_t MaxW = 0;
+
+ std::pair maxDotGear;
+
+ std::vector mean_ = { 0.485f, 0.456f, 0.406f };
+ std::vector scale_ = { 1 / 0.229f, 1 / 0.224f, 1 / 0.225f };
+
+ std::vector> gearInfo;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ cv::Mat DecodeImgDvpp(std::string imgPath);
+
+ void getMatchedGear(const cv::Mat &inImg, std::pair &gear);
+
+ void resize(const cv::Mat &inImg, cv::Mat &outImg, const std::pair &gear, float &ratio);
+
+ void padding(cv::Mat &inImg, const std::pair &gear);
+
+ void normalizeByChannel(std::vector &bgr_channels);
+};
+
+MODULE_REGIST(DbnetPreProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/HandOutProcess/HandOutProcess.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/HandOutProcess/HandOutProcess.cpp
new file mode 100644
index 000000000..d794f4617
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/HandOutProcess/HandOutProcess.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "HandOutProcess.h"
+#include "DbnetPreProcess/DbnetPreProcess.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace ascendBaseModule;
+
+HandOutProcess::HandOutProcess()
+{
+ withoutInputQueue_ = true;
+ isStop_ = false;
+}
+HandOutProcess::~HandOutProcess() {}
+
+APP_ERROR HandOutProcess::Init(ConfigParser &configParser, ModuleInitArgs &initArgs)
+{
+ LogInfo << "Begin to init instance " << initArgs.instanceId;
+ AssignInitArgs(initArgs);
+ APP_ERROR ret = ParseConfig(configParser);
+ if (ret != APP_ERR_OK) {
+ LogError << "HandOutProcess[" << instanceId_ << "]: Fail to parse config params." << GetAppErrCodeInfo(ret);
+ return ret;
+ }
+ LogInfo << "HandOutProcess [" << instanceId_ << "] Init success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR HandOutProcess::DeInit(void)
+{
+ LogInfo << "HandOutProcess [" << instanceId_ << "]: Deinit success.";
+ return APP_ERR_OK;
+}
+
+APP_ERROR HandOutProcess::ParseConfig(ConfigParser &configParser)
+{
+ configParser.GetBoolValue("saveInferResult", saveInferResult);
+ if (saveInferResult) {
+ configParser.GetStringValue("resultPath", resultPath);
+ }
+
+ return APP_ERR_OK;
+}
+
+APP_ERROR HandOutProcess::Process(std::shared_ptr commonData)
+{
+ std::string imgConfig = "./config/" + pipelineName_;
+ LogInfo << pipelineName_;
+ std::ifstream imgFileCount;
+ imgFileCount.open(imgConfig);
+ std::string imgPathCount;
+ int imgTotal = 0;
+ while (getline(imgFileCount, imgPathCount)) {
+ imgTotal++;
+ }
+ imgFileCount.close();
+
+ std::ifstream imgFile;
+ imgFile.open(imgConfig);
+ std::string imgPath;
+ std::regex reg("^([A-Za-z]+)_([0-9]+).*$");
+ std::cmatch m;
+ std::string basename;
+ while (getline(imgFile, imgPath) && !Signal::signalRecieved) {
+ LogInfo << pipelineName_ << " read file:" << imgPath;
+ basename = Utils::BaseName(imgPath);
+ std::regex_match(basename.c_str(), m, reg);
+ if (m.empty()) {
+ LogError << "Please check the image name format of " << basename <<
+ ". the image name should be xxx_xxx.xxx";
+ continue;
+ }
+ imgId_++;
+ std::shared_ptr data = std::make_shared();
+ data->imgPath = imgPath;
+ data->imgId = imgId_;
+ data->imgTotal = imgTotal;
+ data->imgName = basename;
+ data->saveFileName = Utils::GenerateResName(imgPath);
+ SendToNextModule(MT_DbnetPreProcess, data, data->channelId);
+ }
+
+ imgFile.close();
+ return APP_ERR_OK;
+}
\ No newline at end of file
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/HandOutProcess/HandOutProcess.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/HandOutProcess/HandOutProcess.h
new file mode 100644
index 000000000..6db818ec0
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Processors/HandOutProcess/HandOutProcess.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Crnn infer process file.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_HANDOUTPROCESS_H
+#define CPP_HANDOUTPROCESS_H
+
+#include "ModuleManager/ModuleManager.h"
+#include "ConfigParser/ConfigParser.h"
+#include "DataType/DataType.h"
+#include "Utils.h"
+#include "Signal.h"
+#include "ErrorCode/ErrorCode.h"
+#include "Log/Log.h"
+
+class HandOutProcess : public ascendBaseModule::ModuleBase {
+public:
+ HandOutProcess();
+
+ ~HandOutProcess();
+
+ APP_ERROR Init(ConfigParser &configParser, ascendBaseModule::ModuleInitArgs &initArgs);
+
+ APP_ERROR DeInit(void);
+
+protected:
+ APP_ERROR Process(std::shared_ptr inputData);
+
+private:
+ int imgId_ = 0;
+ std::string deviceType_;
+
+ APP_ERROR ParseConfig(ConfigParser &configParser);
+
+ bool saveInferResult;
+ std::string resultPath;
+};
+
+MODULE_REGIST(HandOutProcess)
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Signal/Signal.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Signal/Signal.cpp
new file mode 100644
index 000000000..c113a7403
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Signal/Signal.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: signal control.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "Signal.h"
+
+static std::mutex g_mtx = {};
+bool Signal::signalRecieved = false;
+double Signal::detInferTime = 0;
+double Signal::recInferTime = 0;
+double Signal::e2eProcessTime = 0;
+
+double Signal::detPreProcessTime = 0;
+double Signal::detPostProcessTime = 0;
+
+double Signal::clsPreProcessTime = 0;
+double Signal::clsInferTime = 0;
+double Signal::clsPostProcessTime = 0;
+
+double Signal::recPreProcessTime = 0;
+double Signal::recPostProcessTime = 0;
+
+double Signal::detInferProcessTime = 0;
+double Signal::recInferProcessTime = 0;
+double Signal::clsInferProcessTime = 0;
+
+Signal &Signal::GetInstance()
+{
+ std::unique_lock lock(g_mtx);
+ static Signal singleton;
+ return singleton;
+}
+
+std::atomic_int &Signal::GetStopedThreadNum()
+{
+ return stopedThreadNum;
+}
+
+int Signal::GetThreadNum() const
+{
+ return threadNum;
+}
+
+void Signal::SetThreadNum(int num)
+{
+ threadNum = num;
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Signal/Signal.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Signal/Signal.h
new file mode 100644
index 000000000..48d6fc812
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Signal/Signal.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: signal control.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_SIGNAL_H
+#define CPP_SIGNAL_H
+
+#include
+#include
+
+class Signal {
+public:
+ Signal(const Signal &) = delete;
+
+ Signal operator = (const Signal &) = delete;
+
+ ~Signal() {}
+
+ static Signal &GetInstance();
+
+ int GetThreadNum() const;
+
+ void SetThreadNum(int num);
+
+ std::atomic_int &GetStopedThreadNum();
+
+ static bool signalRecieved;
+ static double detPreProcessTime;
+ static double detInferTime;
+ static double detPostProcessTime;
+
+ static double clsPreProcessTime;
+ static double clsInferTime;
+ static double clsPostProcessTime;
+
+ static double recPreProcessTime;
+ static double recInferTime;
+ static double recPostProcessTime;
+ static double e2eProcessTime;
+
+ static double detInferProcessTime;
+ static double recInferProcessTime;
+ static double clsInferProcessTime;
+
+private:
+ std::atomic_int threadNum { 0 };
+ std::atomic_int stopedThreadNum { 0 };
+
+ Signal() {}
+};
+
+#endif
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Utils/Utils.cpp b/deploy/infer_pipeline/src/demo/cpp/Modules/Utils/Utils.cpp
new file mode 100644
index 000000000..b6b88ab48
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Utils/Utils.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Util data struct.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#include "Utils.h"
+
+uint32_t Utils::ImageChanSizeF32(uint32_t width, uint32_t height)
+{
+ return width * height * 4;
+}
+
+uint32_t Utils::RgbImageSizeF32(uint32_t width, uint32_t height)
+{
+ return width * height * 3 * 4;
+}
+
+uint8_t *Utils::ImageNchw(std::vector &nhwcImageChs, uint32_t size)
+{
+ uint8_t *nchwBuf = new uint8_t[size];
+ uint32_t channelSize = ImageChanSizeF32(nhwcImageChs[0].rows, nhwcImageChs[0].cols);
+ int pos = 0;
+ for (unsigned int i = 0; i < nhwcImageChs.size(); i++) {
+ memcpy(static_cast(nchwBuf) + pos, nhwcImageChs[i].ptr(0), channelSize);
+ pos += channelSize;
+ }
+
+ return nchwBuf;
+}
+
+APP_ERROR Utils::CheckPath(const std::string &srcPath, const std::string &config)
+{
+ int folderExist = access(srcPath.c_str(), R_OK);
+ if (folderExist == -1) {
+ LogError << config << " doesn't exist or can not read.";
+ return APP_ERR_COMM_INVALID_PARAM;
+ }
+
+ return APP_ERR_OK;
+}
+
+std::string Utils::BaseName(const std::string &filename)
+{
+ if (filename.empty()) {
+ return "";
+ }
+
+ auto len = filename.length();
+ auto index = filename.find_last_of("/\\");
+
+ if (index == std::string::npos) {
+ return filename;
+ }
+
+ if (index + 1 >= len) {
+ len--;
+ index = filename.substr(0, len).find_last_of("/\\");
+
+ if (len == 0) {
+ return filename;
+ }
+
+ if (index == 0) {
+ return filename.substr(1, len - 1);
+ }
+
+ if (index == std::string::npos) {
+ return filename.substr(0, len);
+ }
+
+ return filename.substr(index + 1, len - index - 1);
+ }
+
+ return filename.substr(index + 1, len - index);
+}
+
+void Utils::LoadFromFilePair(const std::string &filename, std::vector> &vec)
+{
+ std::ifstream file(filename, std::ios::in | std::ios::binary);
+ std::pair pair;
+ while (file.read(reinterpret_cast(&pair), sizeof(pair))) {
+ vec.push_back(pair);
+ }
+}
+
+void Utils::SaveToFilePair(const std::string &filename, std::vector> &vec)
+{
+ std::ofstream file(filename, std::ios::out | std::ios::binary);
+ for (auto &inf : vec) {
+ file.write(reinterpret_cast(&inf), sizeof(inf));
+ }
+}
+
+bool Utils::PairCompare(const std::pair p1, const std::pair p2)
+{
+ if (p1.first < p2.first) {
+ return true;
+ } else if (p1.first == p2.first) {
+ return p1.second < p2.second;
+ }
+ return false;
+}
+
+bool Utils::GearCompare(const std::pair p1, const std::pair p2)
+{
+ return p1.first <= p2.first && p1.second <= p2.second;
+}
+
+void Utils::GetAllFiles(const std::string &dirName, std::vector &files)
+{
+ struct stat s;
+ stat(dirName.c_str(), &s);
+ if (!S_ISDIR(s.st_mode)) {
+ if (S_ISREG(s.st_mode)) {
+ files.push_back(dirName);
+ }
+ return;
+ }
+ struct dirent *filename;
+ DIR *dir;
+ dir = opendir(dirName.c_str());
+ if (NULL == dir) {
+ return;
+ }
+ while ((filename = readdir(dir)) != NULL) {
+ if (strcmp(filename->d_name, ".") == 0 || strcmp(filename->d_name, "..") == 0) {
+ continue;
+ }
+ files.push_back(dirName + std::string("/") + std::string(filename->d_name));
+ }
+}
+
+bool Utils::EndsWith(const std::string &value, const std::string &ending)
+{
+ if (ending.size() > value.size())
+ return false;
+ return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
+}
+
+bool Utils::UintCompare(uint64_t num1, uint64_t num2)
+{
+ return num1 < num2;
+}
+
+void Utils::StrSplit(const std::string &str, const std::string &pattern, std::vector &vec)
+{
+ int start, end = -1 * pattern.size();
+ do {
+ start = end + pattern.size();
+ end = str.find(pattern, start);
+ vec.push_back(str.substr(start, end - start));
+ } while (end != -1);
+}
+
+bool Utils::ModelCompare(MxBase::Model *model1, MxBase::Model *model2)
+{
+ std::vector> dynamicGearInfo1 = model1->GetDynamicGearInfo();
+ std::vector> dynamicGearInfo2 = model2->GetDynamicGearInfo();
+ return dynamicGearInfo1[0][0] < dynamicGearInfo2[0][0];
+}
+
+void Utils::MakeDir(const std::string &path, bool replace)
+{
+ if (replace && access(path.c_str(), 0) != -1) {
+ system(("rm -r " + path).c_str());
+ LogInfo << path << " removed!";
+ }
+ if (access(path.c_str(), 0) == -1) {
+ system(("mkdir -p " + path).c_str());
+ LogInfo << path << " create!";
+ }
+}
+
+std::string Utils::GenerateResName(const std::string &basename)
+{
+ std::string rawName = basename;
+ size_t lastIndex = rawName.find_last_of('.');
+ rawName = rawName.substr(0, lastIndex);
+ size_t underscoreIndex = rawName.find_last_of('_');
+ std::string saveName = rawName.substr(underscoreIndex, rawName.length());
+ return "infer_img" + saveName + ".txt";
+}
+
+std::string Utils::BoolCast(const bool b)
+{
+ return b ? "true" : "false";
+}
+
+void Utils::LoadFromFileVec(const std::string &filename, std::vector &vec)
+{
+ std::ifstream file(filename, std::ios::in | std::ios::binary);
+ uint64_t num;
+ while (file.read(reinterpret_cast(&num), sizeof(num))) {
+ vec.push_back(num);
+ }
+}
+
+void Utils::SaveToFileVec(const std::string &filename, std::vector &vec)
+{
+ std::ofstream file(filename, std::ios::out | std::ios::binary);
+ for (auto &inf : vec) {
+ file.write(reinterpret_cast(&inf), sizeof(inf));
+ }
+}
diff --git a/deploy/infer_pipeline/src/demo/cpp/Modules/Utils/Utils.h b/deploy/infer_pipeline/src/demo/cpp/Modules/Utils/Utils.h
new file mode 100644
index 000000000..b0286915a
--- /dev/null
+++ b/deploy/infer_pipeline/src/demo/cpp/Modules/Utils/Utils.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+ * Description: Util data struct.
+ * Author: MindX SDK
+ * Create: 2022
+ * History: NA
+ */
+
+#ifndef CPP_UTILS_H
+#define CPP_UTILS_H
+
+#include
+#include
+#include
+#include
+#include