Ascend训练营:yolov5目标检测代码C++版初探(310开发板运行)
一、交叉编译环境安装
以下都是在已经安装好CANN的情况下进行下一步的操作:
(CANN安装参考:Ascend训练营请参考CANN安装指南)
可以从gitee下载华为昇腾的代码样例
下载好后,可参考cplus文件夹下的分设环境安装教程(编译环境为虚拟机,运行环境为昇腾310)
samples-master/cplusplus/environment/separate_environmental_guidance_CN.md

其中安装opencv的库时,从开发板拷回so等库时,编译如果还是出现了找不到opencv相关库头文件的情况,可以修改src/cmakelist.txt中的include_directories选项,并将上述opencv的动态库和头文件分别拷贝到非usr/lib下的别的文件夹,像如下这样:

修改后,进入scripts文件夹输入:
开始编译,因为是交叉编译,实际代码运行位置为310板卡为arm板卡,因此编译也应该选择arm,如是x86环境也可以选择x86

编译完成后显示:

则为编译成功
二、代码初探
1.警告消除:
代码中有几个警告可以消除:
(1).

可以删除在main.c下的此变量! 
(2).
warning: ‘uint32_t aclGetDataBufferSize(const aclDataBuffer*)’ is deprecated: aclGetDataBufferSize is deprecated, use aclGetDataBufferSizeV2 instead [-Wdeprecated-declarations]
这个警告是因为此版本的getsize函数有更新的V2版本,使用新的api即可
size_t bufferSize = aclGetDataBufferSizeV2(dataBuffer);
(3).
warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (int i = 0; i < detectionResults.size(); ++i) {
此警告是类型不同导致的,可以统一为int类型就可以了。
至此代码warning修改完成。
2.代码简单解析
main.c的主函数代码:
`int main(int argc, char *argv[]) {
}`
从上述代码中可得出,该例程的设计分为
- 初始化部分
- 预处理部分
- 推理部分
- 后处理部分
1.初始化部分
初始化dvpp部件(包括acl、上下文,设备,运行模式等)
模型加载:
具体操作流程为申请一段空间,然后调用 aclmdlLoadFromFileWithMem按照名称加载模型,并获取该加载模型的ID,其中模型的名称是由main.c下的命名空间里去指定的,这里我们可以做一下简单优化,如果我们有多个模型加载,参照昇腾的C++版本API手册,我们可知多模型加载只是需要反复调用加载函数即可,我们可以以.为界限提取om的名称,然后加载该模型,最终会获得一个模型ID,我们可以用容器或者结构体去存储这些信息,这样方便随时使用任意模型进行推理
模型执行所需信息初始化(设备、输入输出流等)
参考华为手册准备相关内容 
2.预处理部分
预处理部分的主要思想是运用dvpp部件的接口,高速的将相关格式的图片转换为YUV420SP格式的图片
这里使用的是JPG和PNG的图片,输出图像在 acldvppSetPicDescFormat 在此函数中设置为 PIXEL_FORMAT_YUV_SEMIPLANAR_420 模式,并且通过dvpp接口都回来jpg图片的大小按照需要resize成需要的大小
如果只是普通的灰度图怎么处理呢?
这里在实际应用中,可能我的图片就只是一张普通的灰度图(仅含Y分量),因此我们可以直接在Y分量的数据后面直接添加大小为Y分量图片大小的1/2的0x80填充UV分量,就不需要解码等操作了,可以直接用来推理
3.推理部分
参照应用手册中的流程,只需要准备好输入输出的数据结构,在调用 aclmdlExecute 执行推理并获得结果即可

4.后处理部分
后处理部分主要是运用 aclmdlGetDatasetBuffer将模型的结果读取出来并按照模型设定的内容获取并存储需要的信息
注意!!!!
所有申请的通道、设备一定要记得!销毁!!!!否则内存泄漏会造成严重的问题
ps:该文仅是为了记录CANN训练营的学习过程所用,不参与任何商业用途
Ascend训练营:yolov5目标检测代码C++版初探(310开发板运行)
一、交叉编译环境安装
以下都是在已经安装好CANN的情况下进行下一步的操作:
(CANN安装参考:Ascend训练营请参考CANN安装指南)
可以从gitee下载华为昇腾的代码样例
下载好后,可参考cplus文件夹下的分设环境安装教程(编译环境为虚拟机,运行环境为昇腾310)
samples-master/cplusplus/environment/separate_environmental_guidance_CN.md
其中安装opencv的库时,从开发板拷回so等库时,编译如果还是出现了找不到opencv相关库头文件的情况,可以修改src/cmakelist.txt中的include_directories选项,并将上述opencv的动态库和头文件分别拷贝到非usr/lib下的别的文件夹,像如下这样:
修改后,进入scripts文件夹输入:
开始编译,因为是交叉编译,实际代码运行位置为310板卡为arm板卡,因此编译也应该选择arm,如是x86环境也可以选择x86
编译完成后显示:
则为编译成功
二、代码初探
1.警告消除:
代码中有几个警告可以消除:
(1).
可以删除在main.c下的此变量!
(2).
warning: ‘uint32_t aclGetDataBufferSize(const aclDataBuffer*)’ is deprecated: aclGetDataBufferSize is deprecated, use aclGetDataBufferSizeV2 instead [-Wdeprecated-declarations]这个警告是因为此版本的getsize函数有更新的V2版本,使用新的api即可
size_t bufferSize = aclGetDataBufferSizeV2(dataBuffer);(3).
warning: comparison between signed and unsigned integer expressions [-Wsign-compare] for (int i = 0; i < detectionResults.size(); ++i) {此警告是类型不同导致的,可以统一为int类型就可以了。
至此代码warning修改完成。
2.代码简单解析
main.c的主函数代码:
`int main(int argc, char *argv[]) {
if((argc < 3) || (argv[1] == nullptr)){ ERROR_LOG("Please input: ./main <image_path>`<saveImg>`(0/1)"); return FAILED; } char image_names[5000][100]; string image_dir = string(argv[1]); int fnum = readFileList(argv[1],image_names); string image_path; // string imgFormat = image_path.substr(image_path.size()-3,image_path.size()); // if ((imgFormat !="jpg") && (imgFormat !="png")){ // ERROR_LOG("Only support JPG or PNG img!!"); // return FAILED; // } string imgFormat = string("jpg"); ObjectDetect detect(modelPath,modelWidth,modelHeight); aclError ret = detect.Init(); if (ret != ACL_SUCCESS) { ERROR_LOG("Init resource failed %d", ret); return FAILED; } struct timeval tstart,tend; double timeuse; gettimeofday(&tstart,NULL); aclmdlDataset* inferenceOutput; for(int i =0;i<fnum;i++) { // printf("run %d times\n",i); image_path = image_dir+image_names[i]; Image image; image.imgFormat = imgFormat; image.modelWidth = modelWidth; image.modelHeight = modelHeight; ret = detect.Preprocess(image_path, image); if (ret != ACL_SUCCESS) { ERROR_LOG("Preprocess failed %d", ret); return FAILED; } ret = detect.Inference(inferenceOutput, image); if (ret != ACL_SUCCESS) { ERROR_LOG("Inference model inference output data failed"); return FAILED; } ret = detect.Postprocess(image, inferenceOutput, image_path); if (ret != ACL_SUCCESS) { ERROR_LOG("Process model inference output data failed"); return FAILED; } } gettimeofday(&tend,NULL); timeuse = 1000000*(tend.tv_sec - tstart.tv_sec) + (tend.tv_usec - tstart.tv_usec); INFO_LOG("whole time: %f ms",timeuse/1000); detect.DestroyResource(); return SUCCESS;}`
从上述代码中可得出,该例程的设计分为
1.初始化部分
初始化dvpp部件(包括acl、上下文,设备,运行模式等)
模型加载:
具体操作流程为申请一段空间,然后调用
aclmdlLoadFromFileWithMem按照名称加载模型,并获取该加载模型的ID,其中模型的名称是由main.c下的命名空间里去指定的,这里我们可以做一下简单优化,如果我们有多个模型加载,参照昇腾的C++版本API手册,我们可知多模型加载只是需要反复调用加载函数即可,我们可以以.为界限提取om的名称,然后加载该模型,最终会获得一个模型ID,我们可以用容器或者结构体去存储这些信息,这样方便随时使用任意模型进行推理模型执行所需信息初始化(设备、输入输出流等)
参考华为手册准备相关内容
2.预处理部分
预处理部分的主要思想是运用dvpp部件的接口,高速的将相关格式的图片转换为YUV420SP格式的图片
这里使用的是JPG和PNG的图片,输出图像在
acldvppSetPicDescFormat在此函数中设置为PIXEL_FORMAT_YUV_SEMIPLANAR_420模式,并且通过dvpp接口都回来jpg图片的大小按照需要resize成需要的大小如果只是普通的灰度图怎么处理呢?
这里在实际应用中,可能我的图片就只是一张普通的灰度图(仅含Y分量),因此我们可以直接在Y分量的数据后面直接添加大小为Y分量图片大小的1/2的0x80填充UV分量,就不需要解码等操作了,可以直接用来推理
3.推理部分
参照应用手册中的流程,只需要准备好输入输出的数据结构,在调用
aclmdlExecute执行推理并获得结果即可4.后处理部分
后处理部分主要是运用
aclmdlGetDatasetBuffer将模型的结果读取出来并按照模型设定的内容获取并存储需要的信息注意!!!!
所有申请的通道、设备一定要记得!销毁!!!!否则内存泄漏会造成严重的问题
ps:该文仅是为了记录CANN训练营的学习过程所用,不参与任何商业用途