V1与V2版本的差别
模型卸载
关于模型卸载的接口调用流程,请参见AscendCL接口调用流程。
基本原理
在模型推理结束后,还需要通过aclmdlUnload接口卸载模型,并销毁aclmdlDesc类型的模型描述信息、释放模型运行的工作内存和权值内存。
示例代码
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br> | <br>// 1. 卸载模型<br>aclError ret = aclmdlUnload(modelId_);<br>// 2. 释放模型描述信息<br>if (modelDesc_ != nullptr) {<br> (void)aclmdlDestroyDesc(modelDesc_);<br> modelDesc_ = nullptr;<br>}<br>// 3. 释放模型运行的工作内存<br>if (modelWorkPtr_ != nullptr) {<br> (void)aclrtFree(modelWorkPtr_);<br> modelWorkPtr_ = nullptr;<br> modelWorkSize_ = 0;<br>}<br>// 4. 释放模型运行的权值内存<br>if (modelWeightPtr_ != nullptr) {<br> (void)aclrtFree(modelWeightPtr_);<br> modelWeightPtr_ = nullptr;<br> modelWeightSize_ = 0;<br>}<br> |
|---|
父主题: 模型推理
媒体数据处理视频课程
通过在线视频课程学习该功能,请参见AscendCL DVPP媒体数据处理。
父主题: 媒体数据处理(含图像/视频等)
媒体数据处理基础知识
本章主要介绍图像/视频/音频数据处理的具体功能、接口调用流程以及示例代码。
图像/视频/音频数据处理的典型功能介绍
图1 图像/视频数据处理

各功能的介绍如下表所示,昇腾AI处理器对这些功能的支持度请参见功能支持度说明(AIPP当前各版本均支持)。
功能 | 子功能模块 | 描述 |
|---|---|---|
获取视频数据 | ISP(Image Signal Processing)系统控制 | 系统控制部分用于注册3A算法、注册Sensor驱动、初始化ISP firmware、运行ISP firmware、退出ISP firmware、配置ISP属性等功能。 |
MIPI Rx ioctl命令字 | MIPI Rx是一个支持多种差分视频输入接口的采集单元,通过combo-PHY接收MIPI/LVDS/sub-LVDS/HiSPi接口的数据,通过不同的功能模式配置,MIPI Rx可以支持多种速度和分辨率的数据传输需求,支持多种外部输入设备。 | |
VI(Vedio Input) | VI模块捕获视频图像,可对其做裁剪、防抖、颜色优化、亮度优化、噪声去除等处理,并输出YUV或RAW格式的图像数据。 | |
展示视频数据 | VO(Vedio Output) | VO模块接收VPSS处理后的输出图像,可进行播放控制等处理,最后按用户配置的输出协议(当前仅支持HDMI)输出给外围视频设备。 VO可配合TDE(Two Dimensional Engine)模块、HIFB(Hisilicon Framebuffer)模块,利用硬件分别进行图形绘制、叠加图形层管理。 |
HDMI(High Definition Multimedia Interfac) | HDMI是全数字化影像和声音发送接口,可以发送未压缩的音频及视频信号。 | |
TDE(Two Dimensional Engine) | TDE是图形二维加速引擎,它利用硬件为 OSD(On Screen Display)和 GUI(Graphics User Interface)提供快速的图形绘制功能,主要有快速拷贝、快速色彩填充、模式填充(当前仅支持Alpha Blending操作)。 | |
HIFB(Hisilicon Framebuffer) | HIFB用于管理叠加图形层,它不仅提供Linux Framebuffer的基本功能,还在Linux Framebuffer的基础上增加图层显示起始位置修改、层间Alpha等扩展功能。 | |
区域管理 | Region | 叠加在视频上的OSD (On Screen Display)和遮挡在视频上的色块统称为区域。区域管理模块,用于统一管理这些区域资源,用于在视频上显示一些特定信息(如通道号、时间戳等)、或在视频中填充色块用于遮挡,当前该功能需配合VPSS一起使用。 |
图像/视频数据处理 | VPSS(Video Process Sub-System) | VPSS模块支持对输入图像进行统一预处理,如去噪、去隔行、裁剪等,然后再对各通道分别进行处理,如缩放、加边框等。 |
AIPP(Artificial Intelligence Pre-Processing) | AIPP人工智能预处理,在AI Core上完成数据预处理,主要功能包括改变图像尺寸(抠图、填充等)、色域转换(转换图像格式)、减均值/乘系数(改变图像像素)等。
AIPP区分为静态AIPP和动态AIPP。您只能选择静态AIPP或动态AIPP中的一种来处理图片,不能同时配置静态AIPP和动态AIPP两种方式。
| |
DVPP(Digital Vision Pre-Processing) | DVPP是昇腾AI处理器内置的图像处理单元,通过AscendCL媒体数据处理接口提供强大的媒体处理硬加速能力,主要功能包括以下功能: AIPP、DVPP可以分开独立使用,也可以组合使用。组合使用场景下,一般先使用DVPP对图片/视频进行解码、抠图、缩放等基本处理,但由于DVPP硬件上的约束,DVPP处理后的图片格式、分辨率有可能不满足模型的要求,因此还需要再经过AIPP进一步做色域转换、抠图、填充等处理。 | |
音频数据获取和输出 | AI(Audio Input) | AI模块捕获音频数据 。 |
AO(Audio Output) | 通过ADEC模块解码后的音频数据,AO模块支持播放音频。 | |
音频数据编解码 | AENC(Audio Encoder) | 通过AI模块获取的音频数据,AENC模块支持对其进行编码,输出音频码流。 |
ADEC(Audio Decoder) | ADEC支持解码G.711a、G.711u等协议的音频码流,再通过AO模块播放音频。 |
DVPP图像/视频数据处理的典型使用场景
如果源图或视频的分辨率、格式等与模型的要求不一致时,我们可以将源图或视频处理成符合模型的要求。如下为典型场景的举例。
-
视频解码、缩放
使用Yolov3模型实现目标检测的场景下,用户提供的输入视频为H264/H265编码格式、分辨率为1920*1080,但Yolov3模型要求的输入图片格式为RGB/YUV、分辨率为416*416,两者不一致,此时可对视频执行以下一系列处理。
图2 视频解码、缩放使用场景图

-
图片解码、缩放、格式转换
使用Resnet50模型实现图片分类的场景下,用户提供的输入图片为JPEG编码格式、分辨率为1280*720,但Resnet50模型要求的输入图片格式为RGB、分辨率为224*224,两者不一致,此时可对图片执行以下一系列处理。
图3 图片解码、缩放、格式转换使用场景图

-
抠图、缩放、格式转换
使用Resnet50模型实现图片分类的场景下,用户提供的输入图片格式为YUV420SP、分辨率为1280*720,但Resnet50模型要求的输入图片格式为RGB、分辨率为224*224,两者不一致,此时对图片执行以下一系列处理。
图4 抠图、缩放、格式转换使用场景图

媒体数据处理功能开发流程
图5 开发流程

-
准备环境。
请参见。
-
创建代码目录。
在开发应用前,您需要先创建目录,存放代码文件、编译脚本、测试图片数据、模型文件等
如下仅是示例,供参考:
├App名称├── model // 该目录下存放模型文件│ ├── xxx.json├── data│ ├── xxxxxx // 测试数据├── inc // 该目录下存放声明函数的头文件│ ├── xxx.h├── out // 该目录下存放输出结果├── src│ ├── xxx.json // 系统初始化的配置文件│ ├── CMakeLists.txt // 编译脚本│ ├── xxx.cpp // 实现文件 -
(可选)构建模型。
模型推理场景下,必须要有适配昇腾AI处理器的离线模型(*.om文件),请参见模型构建。
:::note 说明 如果应用中涉及模型推理,则需要构建模型。 :::
-
开发应用。
依赖的头文件和库文件的说明请参见调用接口依赖的头文件和库文件说明。
-
编译运行应用,请参见应用调试。
父主题: 媒体数据处理(含图像/视频等)
V1与V2版本的差别
本手册中媒体数据处理V1版本与媒体数据处理V2版本的接口都是描述处理媒体数据的接口,用于实现抠图、图片缩放、格式转换等功能,但两套接口不能混用。
V2版本的功能比V1版本更多,如下:
- JPEGE:V2版本接口支持高级的参数配置,如huffman表配置。
- VENC:V2版本接口支持更加细化的码控参数配置和效果调优,如I/P帧QP、宏块码控等。
- VDEC:V2版本接口支持更细化的内存控制,如设置输入码流缓存。
- 视频数据获取功能(ISP系统控制&MIPI命令字&VI功能):仅V2版本接口支持。
- VPSS视频处理:仅V2版本接口支持。
- 音频相关功能,包括录音、播音、音量调节:仅V2版本接口支持。
- 视频数据展示功能(VO功能&HDMI外设):仅V2版本接口支持。
昇腾AI处理器对V2版本各功能的支持度,请参见功能支持度说明。
须知
Atlas 200/500 A2推理产品上,支持V1和V2两个版本的媒体数据处理接口,建议使用V2版本中的接口,保证后续版本接口功能以及业务的连续演进。
父主题: 媒体数据处理(含图像/视频等)
功能支持度说明
昇腾AI处理器对媒体数据处理V1版本各功能的支持度如下表所示。
| 昇腾AI处理器 | VPC | JPEGD | JPEGE | PNGD | VDEC | VENC |
|---|---|---|---|---|---|---|
| Atlas 200/500 A2推理产品 | √ | √ | √ | √ | √ | √ |
父主题: 媒体数据处理V1
VPC图像处理典型功能
VPC(Vision Preprocessing Core)负责图像处理功能,支持对图片做抠图、缩放、格式转换等操作。关于VPC功能的详细介绍请参见功能说明,关于VPC功能对输入、输出的约束要求,请参见约束说明。
本节以抠图、缩放为例说明VPC图像处理时的接口调用流程,同时配合以下典型功能的示例代码辅助理解该接口调用流程:
接口调用流程(以抠图、缩放为例)
开发应用时,如果涉及抠图、缩放等图片处理,则应用程序中必须包含图片处理的代码逻辑,关于图片处理的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 抠图缩放流程

关键接口的说明如下(以抠图、缩放处理为例):
-
调用acldvppCreateChannel接口创建图片数据处理的通道。
创建图片数据处理的通道前,需先调用acldvppCreateChannelDesc接口创建通道描述信息。
-
调用acldvppCreateRoiConfig接口、acldvppCreateResizeConfig接口分别创建抠图区域位置的配置、缩放配置。
-
实现抠图、缩放功能前,若需要申请Device上的内存存放输入或输出数据,需调用acldvppMalloc申请内存。
-
执行抠图、缩放。
- 关于抠图:
-
调用acldvppVpcCropAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片存放到输出内存中,作为输出图片。
输出图片区域与抠图区域cropArea不一致时会对图片再做一次缩放操作。
-
当前系统还提供了acldvppVpcCropAndPasteAsync异步接口,支持按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片。
- 抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。
- 如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
-
- 关于缩放
- 调用acldvppVpcResizeAsync异步接口,将输入图片缩放到输出图片大小。
- 缩放后输出图片内存根据YUV420SP格式计算,计算公式:对齐后的宽*对齐后的高*3/2
- 对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
- 关于抠图:
-
调用acldvppFree接口释放输入、输出内存。
-
调用acldvppDestroyRoiConfig接口、acldvppDestroyResizeConfig接口分别销毁抠图区域位置的配置、缩放配置。
-
调用acldvppDestroyChannel接口销毁图片数据处理的通道。
销毁图片数据处理的通道后,再调用acldvppDestroyChannelDesc接口销毁通道描述信息。
图片缩放示例代码
调用acldvppSetResizeConfigInterpolation接口指定缩放算法,再调用acldvppVpcResizeAsync异步接口,将输入图片缩放到输出图片大小。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建图片缩放配置数据、指定缩放算法<br>// resizeConfig_是acldvppResizeConfig类型<br>acldvppResizeConfig *resizeConfig_ = acldvppCreateResizeConfig();<br>aclError ret = acldvppSetResizeConfigInterpolation(resizeConfig, 0);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t resizeInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(resizeInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, resizeInBufferSize);<br> // 申请Device内存resizeInDevBuffer_<br> aclRet = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(resizeInDevBuffer_, resizeInBufferSize, vpcInHostBuffer, resizeInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存resizeInDevBuffer_<br> ret = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, resizeInDevBuffer_, resizeInBufferSize);<br>}<br>// 7. 申请缩放输出内存resizeOutBufferDev_,内存大小resizeOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t resizeOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&resizeOutBufferDev_, resizeOutBufferSize_)<br>// 8. 创建缩放输入图片的描述信息,并设置各属性值<br>// resizeInputDesc_是acldvppPicDesc类型<br>resizeInputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(resizeInputDesc_, resizeInDevBuffer_);<br>acldvppSetPicDescFormat(resizeInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(resizeInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(resizeInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(resizeInputDesc_, inputWidthStride);<br>acldvppSetPicDescHeightStride(resizeInputDesc_, inputHeightStride);<br>acldvppSetPicDescSize(resizeInputDesc_, resizeInBufferSize);<br>// 9. 创建缩放输出图片的描述信息,并设置各属性值<br>// 如果缩放的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// resizeOutputDesc_是acldvppPicDesc类型<br>resizeOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(resizeOutputDesc_, resizeOutBufferDev_);<br>acldvppSetPicDescFormat(resizeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); <br>acldvppSetPicDescWidth(resizeOutputDesc_, resizeOutputWidth_);<br>acldvppSetPicDescHeight(resizeOutputDesc_, resizeOutputHeight_);<br>acldvppSetPicDescWidthStride(resizeOutputDesc_, resizeOutputWidthStride);<br>acldvppSetPicDescHeightStride(resizeOutputDesc_, resizeOutputHeightStride);<br>acldvppSetPicDescSize(resizeOutputDesc_, resizeOutBufferSize_);<br>// 10. 执行异步缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcResizeAsync(dvppChannelDesc_, resizeInputDesc_,<br> resizeOutputDesc_, resizeConfig_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 11. 缩放结束后,释放资源,包括缩放输入/输出图片的描述信息、缩放输入/输出内存<br>acldvppDestroyPicDesc(resizeInputDesc_);<br>acldvppDestroyPicDesc(resizeOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(resizeOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, resizeOutBufferSize_, resizeOutBufferDev_, resizeOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(resizeInDevBuffer_);<br> (void)acldvppFree(resizeOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(resizeInDevBuffer_);<br> (void)acldvppFree(resizeOutBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 12. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 13.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
格式转换示例代码
格式转换支持以下两种实现方式:
- 在实现抠图、缩放等功能时,调用对应的接口(例如acldvppVpcCropAsync接口)时,通过将输入图片和输出图片的格式设置成不同的,达到转换图片格式的目的。
- 如果仅仅做图片格式转换,也可以直接调用acldvppVpcConvertColorAsync接口。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 4. 创建图片数据处理的通道。<br>aclError ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 5. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t inBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST){ <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(inBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, inBufferSize);<br> // 申请Device内存inDevBuffer_<br> aclRet = acldvppMalloc(&inDevBuffer_, inBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(inDevBuffer_, inBufferSize, vpcInHostBuffer, inBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存inDevBuffer_<br> ret = acldvppMalloc(&inDevBuffer_, inBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inDevBuffer_, inBufferSize);<br>}<br>// 6. 申请色域转换输出内存outBufferDev_,内存大小outBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t outBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2<br>ret = acldvppMalloc(&outBufferDev_, outBufferSize_)<br>// 7. 创建色域转换输入图片的描述信息,并设置各属性值<br>// inputDesc_是acldvppPicDesc类型<br>inputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(inputDesc_, inDevBuffer_);<br>acldvppSetPicDescFormat(inputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(inputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(inputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(inputDesc_, inputWidthStride);<br>acldvppSetPicDescHeightStride(inputDesc_, inputHeightStride);<br>acldvppSetPicDescSize(inputDesc_, inBufferSize);<br>// 8. 创建色域转换的输出图片的描述信息,并设置各属性值, 输出的宽和高要求和输入一致<br>// 如果色域转换的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// outputDesc_是acldvppPicDesc类型<br>outputDesc_= acldvppCreatePicDesc();<br>acldvppSetPicDescData(outputDesc_, outBufferDev_);<br>acldvppSetPicDescFormat(outputDesc_, PIXEL_FORMAT_YUV_400); <br>acldvppSetPicDescWidth(outputDesc_, outputWidth_);<br>acldvppSetPicDescHeight(outputDesc_, outputHeight_);<br>acldvppSetPicDescWidthStride(outputDesc_, outputWidthStride);<br>acldvppSetPicDescHeightStride(outputDesc_, outputHeightStride);<br>acldvppSetPicDescSize(outputDesc_, outBufferSize_);<br>// 9. 执行异步色域转换,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcConvertColorAsync(dvppChannelDesc_, inputDesc_, outputDesc_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 10. 色域转换结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存<br>acldvppDestroyPicDesc(inputDesc_);<br>acldvppDestroyPicDesc(outputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(outBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, outBufferSize_, outBufferDev_, outBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(outBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(outBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 11. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 12.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
抠图缩放(一图一框)示例代码
调用acldvppVpcCropResizeAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片存放到输出内存中,作为输出图片,此外,还支持指定缩放算法。当输出图片区域与抠图区域cropArea不一致时会对图片再做一次缩放操作。
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建缩放配置数据,并指定抠图区域的位置<br>// resizeConfig_是acldvppResizeConfig类型<br>resizeConfig_ = acldvppCreateResizeConfig();<br>aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0);<br>// cropArea_是acldvppRoiConfig类型<br>cropArea_ = acldvppCreateRoiConfig(550, 749, 480, 679);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t cropInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* cropInHostBuffer = nullptr;<br> cropInHostBuffer = malloc(cropInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, cropInHostBuffer, cropInBufferSize);<br> // 申请Device内存cropInDevBuffer_<br> aclRet = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize);<br> // 通过aclrtMemcpy接口图片数据传输到Device<br> aclRet = aclrtMemcpy(cropInDevBuffer_, cropInBufferSize, cropInHostBuffer, cropInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(cropInHostBuffer);<br>} else { <br> // 申请Device输入内存cropInDevBuffer_<br> ret = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, cropInDevBuffer_, cropInBufferSize);<br>}<br>// 7. 申请Device输出内存cropOutBufferDev_,内存大小cropOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t cropOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&cropOutBufferDev_, cropOutBufferSize_)<br>// 8. 创建输入图片的描述信息,并设置各属性值,cropInputDesc_是acldvppPicDesc类型<br>cropInputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(cropInputDesc_, cropInDevBuffer_);<br>acldvppSetPicDescFormat(cropInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(cropInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(cropInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(cropInputDesc_, inputWidthStride);<br>acldvppSetPicDescHeightStride(cropInputDesc_, inputHeightStride);<br>acldvppSetPicDescSize(cropInputDesc_, cropInBufferSize);<br>// 9. 创建输出图片的描述信息,并设置各属性值,cropOutputDesc_是acldvppPicDesc类型<br>// 如果抠图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>cropOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(cropOutputDesc_, cropOutBufferDev_);<br>acldvppSetPicDescFormat(cropOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(cropOutputDesc_, OutputWidth_);<br>acldvppSetPicDescHeight(cropOutputDesc_, OutputHeight_);<br>acldvppSetPicDescWidthStride(cropOutputDesc_, OutputWidthStride);<br>acldvppSetPicDescHeightStride(cropOutputDesc_, OutputHeightStride);<br>acldvppSetPicDescSize(cropOutputDesc_, cropOutBufferSize_);<br>// 10. 执行异步抠图缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcCropResizeAsync(dvppChannelDesc_, cropInputDesc_,<br> cropOutputDesc_, cropArea_, resizeConfig_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 11. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等<br>acldvppDestroyRoiConfig(cropArea_);<br>acldvppDestroyResizeConfig(resizeConfig_);<br>acldvppDestroyPicDesc(cropInputDesc_);<br>acldvppDestroyPicDesc(cropOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* cropOutHostBuffer = nullptr;<br> cropOutHostBuffer = malloc(cropOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(cropOutHostBuffer, cropOutBufferSize_, cropOutBufferDev_, cropOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(cropInDevBuffer_);<br> (void)acldvppFree(cropOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(cropOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作抠图结果后,释放Device侧内存<br> (void)acldvppFree(cropInDevBuffer_);<br> (void)acldvppFree(cropOutBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 12. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 13.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
抠图贴图缩放(一图一框)示例代码
调用acldvppVpcCropResizePasteAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片,此外,还支持指定缩放算法。当抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br>114<br>115<br>116<br>117<br>118<br>119<br>120<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建缩放配置数据,并指定抠图区域的位置、指定贴图区域的位置<br>// resizeConfig_是acldvppResizeConfig类型<br>resizeConfig_ = acldvppCreateResizeConfig();<br>aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0);<br>// cropArea_和pasteArea_是acldvppRoiConfig类型<br>cropArea_ = acldvppCreateRoiConfig(512, 711, 512, 711);<br>pasteArea_ = acldvppCreateRoiConfig(16, 215, 16, 215);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize);<br> // 申请Device内存vpcInDevBuffer_<br> aclRet = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存vpcInDevBuffer_<br> ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize);<br>}<br>// 7. 申请输出内存vpcOutBufferDev_,内存大小vpcOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_)<br>// 8. 创建输入图片的描述信息,并设置各属性值<br>// 此处示例将解码的输出内存作为抠图贴图的输入,vpcInputDesc_是acldvppPicDesc类型<br>vpcInputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); <br>acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride);<br>acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride);<br>acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize);<br>// 9. 创建输出图片的描述信息,并设置各属性值<br>// 如果抠图贴图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// vpcOutputDesc_是acldvppPicDesc类型<br>vpcOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_);<br>acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth);<br>acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight);<br>acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride);<br>acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride);<br>acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_);<br>// 10. 执行异步抠图贴图缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcCropResizePasteAsync(dvppChannelDesc_, vpcInputDesc_,<br> vpcOutputDesc_, cropArea_, pasteArea_, resizeConfig_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 11. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等<br>acldvppDestroyRoiConfig(cropArea_);<br>acldvppDestroyRoiConfig(pasteArea_);<br>acldvppDestroyResizeConfig(resizeConfig_);<br>acldvppDestroyPicDesc(vpcInputDesc_);<br>acldvppDestroyPicDesc(vpcOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(vpcOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(vpcInDevBuffer_);<br> (void)acldvppFree(vpcOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(vpcInDevBuffer_);<br> (void)acldvppFree(vpcOutBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 12. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 13.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
抠图贴图(一图多框)示例代码
调用acldvppVpcBatchCropAndPasteAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片。当抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br>114<br>115<br>116<br>117<br>118<br>119<br>120<br>121<br>122<br>123<br>124<br>125<br>126<br>127<br>128<br>129<br>130<br> | cpp<br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.指定批量抠图区域的位置、指定批量贴图区域的位置,cropAreas_和pasteAreas_是acldvppRoiConfig类型<br>acldvppRoiConfig *cropAreas_[2], pasteAreas_[2];<br>cropAreas_[0] = acldvppCreateRoiConfig(512, 711, 512, 711);<br>cropAreas_[1] = acldvppCreateRoiConfig(512, 711, 512, 711);<br>pasteAreas_[0] = acldvppCreateRoiConfig(16, 215, 16, 215);<br>pasteAreas_[1] = acldvppCreateRoiConfig(16, 215, 16, 215);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>aclError ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize);<br> // 申请Device内存vpcInDevBuffer_<br> aclRet = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> <br> aclRet = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存vpcInDevBuffer_<br> ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize);<br>}<br>// 7. 申请输出内存vpcOutBufferDev_,内存大小vpcOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_)<br>// 8. 创建输入图片的描述信息,并设置各属性值<br>// 此处示例将解码的输出内存作为抠图贴图的输入,vpcInputDesc_是acldvppPicDesc类型<br>vpcInputBatchDesc_ = acldvppCreateBatchPicDesc(1);<br>vpcInputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, 0);<br>acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); <br>acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride);<br>acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride);<br>acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize);<br>// 9. 创建批量输出图片的描述信息,并设置各属性值<br>// 如果抠图贴图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// vpcOutputDesc_是acldvppPicDesc类型<br>vpcOutputBatchDesc_ = acldvppCreateBatchPicDesc(2);<br>for (index=0; index<2; ++index){<br> vecOutPtr_.push_back(vpcOutBufferDev_);<br> vpcOutputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, index);<br> acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_);<br> acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br> acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth);<br> acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight);<br> acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride);<br> acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride);<br> acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_);<br>}<br>// 10. 创建roiNums,每张图对应需要抠图和贴图的数量<br>uint32_ttotalNum = 0;<br>std::unique_ptr<uint32_t[]> roiNums(new (std::nothrow) uint32_t[1]);<br>roiNums[0]=2;<br>// 11. 执行异步抠图贴图,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcBatchCropAndPasteAsync(dvppChannelDesc_, vpcInputBatchDesc_, roiNums.get(), 1,<br> vpcOutputBatchDesc_, cropAreas_, pasteAreas_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 12. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等<br>acldvppDestroyRoiConfig(cropAreas_[0]);<br>acldvppDestroyRoiConfig(cropAreas_[1]);<br>acldvppDestroyRoiConfig(pasteAreas_[0]);<br>acldvppDestroyRoiConfig(pasteAreas_[1]);<br>(void)acldvppFree(vpcInDevBuffer_);<br>for(index=0; index<2; ++index){<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(vpcOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(vpcOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> <br> (void)acldvppFree(vpcOutBufferDev_);<br>}<br>}<br>acldvppDestroyBatchPicDesc(vpcInputDesc_);<br>acldvppDestroyBatchPicDesc(vpcOutputDesc_);<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 13. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 14.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
父主题: 媒体数据处理V1
JPEGD图像解码
JPEGD(JPEG Decoder)负责完成图像解码功能,将.jpg、.jpeg、.JPG、.JPEG图片解码成YUV格式图片。关于JPEGD功能的详细介绍及约束请参见功能及约束说明。
本节介绍JPEGD图片解码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。
接口调用流程
开发应用时,如果涉及对JPEG图片的解码,则应用程序中必须包含图片解码的代码逻辑,关于图片解码的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 JPEG图片解码

当前系统支持.jpg、.jpeg、.JPG、.JPEG图片的解码,针对不同的源图编码格式,输出不同编码格式的图片,关键接口的说明如下:
-
调用acldvppCreateChannel接口创建图片数据处理的通道。
创建图片数据处理的通道前,需先调用acldvppCreateChannelDesc接口创建通道描述信息。
-
实现JPEG图片解码功能前,若需要申请Device上的内存存放输入或输出数据,需调用acldvppMalloc申请内存。
在申请输出内存前,可根据存放JPEG图片数据的内存,调用acldvppJpegPredictDecSize接口预估JPEG图片解码后所需的输出内存的大小。
实际输出内存大小可能与调用acldvppJpegPredictDecSize接口预估的内存大小存在差异,如果用户需要获取解码后的实际输出内存大小,需调用acldvppPicDesc类型下的acldvppGetPicDescSize接口获取。
-
调用acldvppJpegDecodeAsync异步接口进行解码。
对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
-
在解码结束后,需及时调用acldvppFree接口释放输入、输出内存。
-
调用acldvppDestroyChannel接口销毁图片数据处理的通道。
销毁图片数据处理的通道后,再调用acldvppDestroyChannelDesc接口销毁通道描述信息。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>89<br>90<br>91<br>92<br>93<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 4.创建图片数据处理的通道。<br>aclError ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 5. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>if(runMode == ACL_HOST){<br> <br> void* inputHostBuff = nullptr;<br> inputHostBuff = malloc(inDevBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inputHostBuff, inDevBufferSize);<br> // 申请Device内存inDevBuffer_<br> aclRet = acldvppMalloc(&inDevBuffer_, inDevBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(inDevBuffer_, inDevBufferSize, inputHostBuff, inDevBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br>} else {<br> // 申请Device输入内存inDevBuffer_<br> ret = acldvppMalloc(&inDevBuffer_, inBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inDevBuffer_, inBufferSize);<br>}<br>// 6. 申请解码输出内存decodeOutDevBuffer_<br>// 预估JPEGD处理结果所需的内存大小<br>uint32_t decodeOutBufferSize = 0;<br>ret = acldvppJpegPredictDecSize(inputHostBuff, inDevBufferSize, PIXEL_FORMAT_YVU_SEMIPLANAR_420,&decodeOutBufferSize)<br>ret = acldvppMalloc(&decodeOutDevBuffer_, decodeOutBufferSize)<br>// 及时释放内存<br>free(inputHostBuff);<br>// 7. 创建解码输出图片的描述信息,设置各属性值<br>// decodeOutputDesc是acldvppPicDesc类型<br>decodeOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(decodeOutputDesc_, decodeOutDevBuffer_);<br>acldvppSetPicDescFormat(decodeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); <br>acldvppSetPicDescWidth(decodeOutputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(decodeOutputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(decodeOutputDesc_, decodeOutWidthStride);<br>acldvppSetPicDescHeightStride(decodeOutputDesc_, decodeOutHeightStride);<br>acldvppSetPicDescSize(decodeOutputDesc_, decodeOutBufferSize);<br>// 8. 执行异步解码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppJpegDecodeAsync(dvppChannelDesc_, inDevBuffer_, inDevBufferSize, decodeOutputDesc_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 9. 解码结束后,释放资源,包括解码输出图片的描述信息、解码输出内存、通道描述信息、通道等<br>acldvppDestroyPicDesc(decodeOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(decodeOutBufferSize);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, decodeOutBufferSize, decodeOutDevBuffer_, decodeOutBufferSize, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(decodeOutDevBuffer_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(decodeOutDevBuffer_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 10. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 11.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
父主题: 媒体数据处理V1
在线提单