图像处理典型功能(抠图/缩放等)
抠图缩放(一图一框)
关于抠图的接口调用流程,请依次参见主要接口调用流程、抠图/缩放。
基本原理
- 调用acldvppCreateChannel接口创建图片数据处理的通道、调用acldvppDestroyChannel接口销毁图片数据处理的通道。
- 调用acldvppVpcCropResizeAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片存放到输出内存中,作为输出图片。对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
调用acldvppVpcCropResizeAsync接口实现抠图缩放时,支持指定缩放算法。
- 输出图片区域与抠图区域cropArea不一致时会对图片再做一次缩放操作。
- 输入、输出相关的约束要求,请参见功能及约束说明。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
//1.AscendCL初始化 //2.运行管理资源申请,包括Device、Context、Stream //3. 创建缩放配置数据,并指定抠图区域的位置 //resizeConfig_是acldvppResizeConfig类型 resizeConfig_ = acldvppCreateResizeConfig(); aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0); //cropArea_是acldvppRoiConfig类型 cropArea_ = acldvppCreateRoiConfig(550, 749, 480, 679); //4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 dvppChannelDesc_ = acldvppCreateChannelDesc(); //5. 创建图片数据处理的通道。 ret = acldvppCreateChannel(dvppChannelDesc_); //6. 申请输入内存(区分运行状态) //调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将Host的图片数据传输到Device,数据传输完成后,需及时释放Host内存;否则直接申请Device的内存 aclrtRunMode runMode; ret = aclrtGetRunMode(&runMode); //inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t cropInBufferSize = inputPicWidth * inputPicHeight * 3 / 2; if(runMode == ACL_HOST) { //申请Host内存cropInHostBuffer void* cropInHostBuffer = nullptr; cropInHostBuffer = malloc(cropInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, cropInHostBuffer, cropInBufferSize); //申请Device内存cropInDevBuffer_ aclRet = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize); //通过aclrtMemcpy接口将Host的图片数据传输到Device aclRet = aclrtMemcpy(cropInDevBuffer_, cropInBufferSize, cropInHostBuffer, cropInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE); //数据传输完成后,及时释放Host内存 free(cropInHostBuffer); } else { //申请Device输入内存cropInDevBuffer_ ret = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, cropInDevBuffer_, cropInBufferSize); } //7. 申请Device输出内存cropOutBufferDev_,内存大小cropOutBufferSize_根据计算公式得出 //outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t cropOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2; ret = acldvppMalloc(&cropOutBufferDev_, cropOutBufferSize_) //8. 创建输入图片的描述信息,并设置各属性值,cropInputDesc_是acldvppPicDesc类型 cropInputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(cropInputDesc_, cropInDevBuffer_); acldvppSetPicDescFormat(cropInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(cropInputDesc_, inputWidth_); acldvppSetPicDescHeight(cropInputDesc_, inputHeight_); acldvppSetPicDescWidthStride(cropInputDesc_, inputWidthStride); acldvppSetPicDescHeightStride(cropInputDesc_, inputHeightStride); acldvppSetPicDescSize(cropInputDesc_, cropInBufferSize); //9. 创建输出图片的描述信息,并设置各属性值,cropOutputDesc_是acldvppPicDesc类型 //如果抠图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致 cropOutputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(cropOutputDesc_, cropOutBufferDev_); acldvppSetPicDescFormat(cropOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(cropOutputDesc_, OutputWidth_); acldvppSetPicDescHeight(cropOutputDesc_, OutputHeight_); acldvppSetPicDescWidthStride(cropOutputDesc_, OutputWidthStride); acldvppSetPicDescHeightStride(cropOutputDesc_, OutputHeightStride); acldvppSetPicDescSize(cropOutputDesc_, cropOutBufferSize_); //10. 执行异步抠图,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 ret = acldvppVpcCropResizeAsync(dvppChannelDesc_, cropInputDesc_, cropOutputDesc_, cropArea_, resizeConfig_, stream_); ret = aclrtSynchronizeStream(stream_); //11. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等 acldvppDestroyRoiConfig(cropArea_); acldvppDestroyResizeConfig(resizeConfig_); acldvppDestroyPicDesc(cropInputDesc_); acldvppDestroyPicDesc(cropOutputDesc_); if(runMode == ACL_HOST) { //此时运行在host侧,处理结果在Device侧,如果需要在Host直接展示处理结果,则需要将Device的数据传回Host,释放Device侧内存 //申请Host内存cropOutHostBuffer void* cropOutHostBuffer = nullptr; cropOutHostBuffer = malloc(cropOutBufferSize_); //通过aclrtMemcpy接口将Device的处理结果数据传输到Host aclRet = aclrtMemcpy(cropOutHostBuffer, cropOutBufferSize_, cropOutBufferDev_, cropOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST); //释放掉输入输出的device内存 (void)acldvppFree(cropInDevBuffer_); (void)acldvppFree(cropOutBufferDev_); //在Host侧回传数据使用完成后,释放Host内存 free(cropOutHostBuffer); } else { //此时运行在device侧,处理结果也在Device侧,可以根据需要操作抠图结果后,释放Device侧内存 (void)acldvppFree(cropInDevBuffer_); (void)acldvppFree(cropOutBufferDev_); } acldvppDestroyChannel(dvppChannelDesc_); (void)acldvppDestroyChannelDesc(dvppChannelDesc_); dvppChannelDesc_ = nullptr; //12. 释放运行管理资源 //13. AscendCL去初始化 //....
抠图贴图缩放(一图一框)
基本原理
- 调用acldvppCreateChannel接口创建图片数据处理的通道、调用acldvppDestroyChannel接口销毁图片数据处理的通道。
- 调用acldvppVpcCropResizePasteAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片。对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
调用acldvppVpcCropResizePasteAsync实现抠图缩放贴图时,支持指定缩放算法。
- 抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。
- 如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
- 输入、输出相关的约束要求,请参见功能及约束说明。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
//1.AscendCL初始化 //2.运行管理资源申请,包括Device、Context、Stream //3. 创建缩放配置数据,并指定抠图区域的位置、指定贴图区域的位置 //resizeConfig_是acldvppResizeConfig类型 resizeConfig_ = acldvppCreateResizeConfig(); aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0); //cropArea_和pasteArea_是acldvppRoiConfig类型 cropArea_ = acldvppCreateRoiConfig(512, 711, 512, 711); pasteArea_ = acldvppCreateRoiConfig(16, 215, 16, 215); //4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 dvppChannelDesc_ = acldvppCreateChannelDesc(); //5. 创建图片数据处理的通道。 ret = acldvppCreateChannel(dvppChannelDesc_); //6. 申请输入内存(区分运行状态) //调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将Host的图片数据传输到Device,数据传输完成后,需及时释放Host内存;否则直接申请Device的内存 aclrtRunMode runMode; ret = aclrtGetRunMode(&runMode); //inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2; if(runMode == ACL_HOST) { //申请Host内存vpcInHostBuffer void* vpcInHostBuffer = nullptr; vpcInHostBuffer = malloc(vpcInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize); //申请Device内存vpcInDevBuffer_ aclRet = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize); //通过aclrtMemcpy接口将Host的图片数据传输到Device aclRet = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE); //数据传输完成后,及时释放Host内存 free(vpcInHostBuffer); } else { //申请Device输入内存vpcInDevBuffer_ ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize); } //7. 申请输出内存vpcOutBufferDev_,内存大小vpcOutBufferSize_根据计算公式得出 //outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2; ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_) //8. 创建输入图片的描述信息,并设置各属性值 //此处示例将解码的输出内存作为抠图贴图的输入,vpcInputDesc_是acldvppPicDesc类型 vpcInputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_); acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_); acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride); acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride); acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize); //9. 创建输出图片的描述信息,并设置各属性值 //如果抠图贴图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致 //vpcOutputDesc_是acldvppPicDesc类型 vpcOutputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_); acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth); acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight); acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride); acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride); acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_); //10. 执行异步缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 ret = acldvppVpcCropResizePasteAsync(dvppChannelDesc_, vpcInputDesc_, vpcOutputDesc_, cropArea_, pasteArea_, resizeConfig_, stream_); ret = aclrtSynchronizeStream(stream_); //11. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等 acldvppDestroyRoiConfig(cropArea_); acldvppDestroyRoiConfig(pasteArea_); acldvppDestroyResizeConfig(resizeConfig_); acldvppDestroyPicDesc(vpcInputDesc_); acldvppDestroyPicDesc(vpcOutputDesc_); if(runMode == ACL_HOST) { //此时运行在host侧,处理结果在Device侧,如果需要在Host直接展示处理结果,则需要将Device的数据传回Host,释放Device侧内存 //申请Host内存vpcOutHostBuffer void* vpcOutHostBuffer = nullptr; vpcOutHostBuffer = malloc(vpcOutBufferSize_); //通过aclrtMemcpy接口将Device的处理结果数据传输到Host aclRet = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST); //释放掉输入输出的device内存 (void)acldvppFree(vpcInDevBuffer_); (void)acldvppFree(vpcOutBufferDev_); //在Host侧回传数据使用完成后,释放Host内存 free(vpcOutHostBuffer); } else { //此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存 (void)acldvppFree(vpcInDevBuffer_); (void)acldvppFree(vpcOutBufferDev_); } acldvppDestroyChannel(dvppChannelDesc_); (void)acldvppDestroyChannelDesc(dvppChannelDesc_); dvppChannelDesc_ = nullptr; //12. 释放运行管理资源 //13. AscendCL去初始化 //....
抠图贴图(一图多框)
基本原理
- 调用acldvppCreateChannel接口创建图片数据处理的通道、调用acldvppDestroyChannel接口销毁图片数据处理的通道。
- 调用acldvppCreateBatchPicDesc接口创建批量图片的描述信息,一图多框仅支持batchSize为1。
- 调用acldvppGetPicDesc获取指定图片的描述信息,填充对应的图片数据。
- 调用acldvppCreateRoiConfig创建框位置区域的描述信息,并调用acldvppSetRoiConfig系列接口设置框的位置。
- 调用acldvppVpcBatchCropAndPasteAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片。对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
- 抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。
- 如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
- 输入、输出相关的约束要求,请参见功能及约束说明。
示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
//1.AscendCL初始化 //2.运行管理资源申请,包括Device、Context、Stream //3.指定批量抠图区域的位置、指定批量贴图区域的位置,cropAreas_和pasteAreas_是acldvppRoiConfig类型 acldvppRoiConfig *cropAreas_[2], pasteAreas_[2]; cropAreas_[0] = acldvppCreateRoiConfig(512, 711, 512, 711); cropAreas_[1] = acldvppCreateRoiConfig(512, 711, 512, 711); pasteAreas_[0] = acldvppCreateRoiConfig(16, 215, 16, 215); pasteAreas_[1] = acldvppCreateRoiConfig(16, 215, 16, 215); //4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 dvppChannelDesc_ = acldvppCreateChannelDesc(); //5. 创建图片数据处理的通道。 aclError ret = acldvppCreateChannel(dvppChannelDesc_); //6. 申请输入内存(区分运行状态) //调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将Host的图片数据传输到Device,数据传输完成后,需及时释放Host内存;否则直接申请Device的内存 aclrtRunMode runMode; ret = aclrtGetRunMode(&runMode); //inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2; if(runMode == ACL_HOST) { //申请Host内存vpcInHostBuffer void* vpcInHostBuffer = nullptr; vpcInHostBuffer = malloc(vpcInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize); //申请Device内存vpcInDevBuffer_ aclRet = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize); //通过aclrtMemcpy接口将Host的图片数据传输到Device aclRet = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE); //数据传输完成后,及时释放Host内存 free(vpcInHostBuffer); } else { //申请Device输入内存vpcInDevBuffer_ ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize); } //7. 申请输出内存vpcOutBufferDev_,内存大小vpcOutBufferSize_根据计算公式得出 //outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2; ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_) //8. 创建输入图片的描述信息,并设置各属性值 //此处示例将解码的输出内存作为抠图贴图的输入,vpcInputDesc_是acldvppPicDesc类型 vpcInputBatchDesc_ = acldvppCreateBatchPicDesc(1); vpcInputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, 0); acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_); acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_); acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride); acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride); acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize); //9. 创建批量输出图片的描述信息,并设置各属性值 //如果抠图贴图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致 //vpcOutputDesc_是acldvppPicDesc类型 vpcOutputBatchDesc_ = acldvppCreateBatchPicDesc(2); for (index=0; index<2; ++index){ vecOutPtr_.push_back(vpcOutBufferDev_); vpcOutputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, index); acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_); acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth); acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight); acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride); acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride); acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_); } //10 创建roiNums,每张图对应需要抠图和贴图的数量 uint32_ttotalNum = 0; std::unique_ptr<uint32_t[]> roiNums(new (std::nothrow) uint32_t[1]); roiNums[0]=2; //11. 执行异步缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 ret = acldvppVpcBatchCropAndPasteAsync(dvppChannelDesc_, vpcInputBatchDesc_, roiNums.get(), 1, vpcOutputBatchDesc_, cropAreas_, pasteAreas_, stream_); ret = aclrtSynchronizeStream(stream_); //12. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等 acldvppDestroyRoiConfig(cropAreas_[0]); acldvppDestroyRoiConfig(cropAreas_[1]); acldvppDestroyRoiConfig(pasteAreas_[0]); acldvppDestroyRoiConfig(pasteAreas_[1]); (void)acldvppFree(vpcInDevBuffer_); for(index=0; index<2; ++index){ if(runMode == ACL_HOST) { //此时运行在host侧,处理结果在Device侧,如果需要在Host直接展示处理结果,则需要将Device的数据传回Host,释放Device侧内存 //申请Host内存vpcOutHostBuffer void* vpcOutHostBuffer = nullptr; vpcOutHostBuffer = malloc(vpcOutBufferSize_); //通过aclrtMemcpy接口将Device的处理结果数据传输到Host aclRet = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST); //释放掉输入输出的device内存 (void)acldvppFree(vpcOutBufferDev_); //在Host侧回传数据使用完成后,释放Host内存 free(vpcOutHostBuffer); } else { //此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存 (void)acldvppFree(vpcOutBufferDev_); } } acldvppDestroyBatchPicDesc(vpcInputDesc_); acldvppDestroyBatchPicDesc(vpcOutputDesc_); acldvppDestroyChannel(dvppChannelDesc_); (void)acldvppDestroyChannelDesc(dvppChannelDesc_); dvppChannelDesc_ = nullptr; //13. 释放运行管理资源 //14. AscendCL去初始化 //....
图片缩放
关于缩放的接口调用流程,请依次参见主要接口调用流程、抠图/缩放。
基本原理
- 调用acldvppCreateChannel接口创建图片数据处理的通道、调用acldvppDestroyChannel接口销毁图片数据处理的通道。
- 调用acldvppVpcResizeAsync异步接口,将输入图片缩放到输出图片大小。对于异步接口,还需调用aclrtSynchronizeStream接口阻塞Host运行,直到指定Stream中的所有任务都完成。
- 调用acldvppCreateResizeConfig接口创建图片缩放配置数据,默认缩放算法为“华为自研的高阶滤波算法”。
如果不想使用默认缩放算法,也可以调用acldvppSetResizeConfigInterpolation接口指定缩放算法。
- 输入、输出相关的约束要求,请参见功能及约束说明。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
//1.AscendCL初始化 //2.运行管理资源申请,包括Device、Context、Stream //3. 创建图片缩放配置数据、指定缩放算法 //resizeConfig_是acldvppResizeConfig类型 acldvppResizeConfig *resizeConfig_ = acldvppCreateResizeConfig(); aclError ret = acldvppSetResizeConfigInterpolation(resizeConfig_, 0); //4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 dvppChannelDesc_ = acldvppCreateChannelDesc(); //5. 创建图片数据处理的通道。 ret = acldvppCreateChannel(dvppChannelDesc_); //6. 申请输入内存(区分运行状态) //调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将Host的图片数据传输到Device,数据传输完成后,需及时释放Host内存;否则直接申请Device的内存 aclrtRunMode runMode; ret = aclrtGetRunMode(&runMode); //inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t resizeInBufferSize = inputPicWidth * inputPicHeight * 3 / 2; if(runMode == ACL_HOST) { //申请Host内存vpcInHostBuffer void* vpcInHostBuffer = nullptr; vpcInHostBuffer = malloc(resizeInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, vpcInHostBuffer, resizeInBufferSize); //申请Device内存resizeInDevBuffer_ aclRet = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize); //通过aclrtMemcpy接口将Host的图片数据传输到Device aclRet = aclrtMemcpy(resizeInDevBuffer_, resizeInBufferSize, vpcInHostBuffer, resizeInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE); //数据传输完成后,及时释放Host内存 free(vpcInHostBuffer); } else { //申请Device输入内存resizeInDevBuffer_ ret = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize); //将输入图片读入内存中,该自定义函数ReadPicFile由用户实现 ReadPicFile(picName, resizeInDevBuffer_, resizeInBufferSize); } //7. 申请缩放输出内存resizeOutBufferDev_,内存大小resizeOutBufferSize_根据计算公式得出 //outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t resizeOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2; ret = acldvppMalloc(&resizeOutBufferDev_, resizeOutBufferSize_) //8. 创建缩放输入图片的描述信息,并设置各属性值 //resizeInputDesc_是acldvppPicDesc类型 resizeInputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(resizeInputDesc_, resizeInDevBuffer_); acldvppSetPicDescFormat(resizeInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(resizeInputDesc_, inputWidth_); acldvppSetPicDescHeight(resizeInputDesc_, inputHeight_); acldvppSetPicDescWidthStride(resizeInputDesc_, inputWidthStride); acldvppSetPicDescHeightStride(resizeInputDesc_, inputHeightStride); acldvppSetPicDescSize(resizeInputDesc_, resizeInBufferSize); //9. 创建缩放输出图片的描述信息,并设置各属性值 //如果缩放的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致 //resizeOutputDesc_是acldvppPicDesc类型 resizeOutputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(resizeOutputDesc_, resizeOutBufferDev_); acldvppSetPicDescFormat(resizeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(resizeOutputDesc_, resizeOutputWidth_); acldvppSetPicDescHeight(resizeOutputDesc_, resizeOutputHeight_); acldvppSetPicDescWidthStride(resizeOutputDesc_, resizeOutputWidthStride); acldvppSetPicDescHeightStride(resizeOutputDesc_, resizeOutputHeightStride); acldvppSetPicDescSize(resizeOutputDesc_, resizeOutBufferSize_); //10. 执行异步缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 ret = acldvppVpcResizeAsync(dvppChannelDesc_, resizeInputDesc_, resizeOutputDesc_, resizeConfig_, stream_); ret = aclrtSynchronizeStream(stream_); //11. 缩放结束后,释放资源,包括缩放输入/输出图片的描述信息、缩放输入/输出内存 acldvppDestroyPicDesc(resizeInputDesc_); acldvppDestroyPicDesc(resizeOutputDesc_); if(runMode == ACL_HOST) { //此时运行在host侧,处理结果在Device侧,如果需要在Host直接展示处理结果,则需要将Device的数据传回Host,释放Device侧内存 //申请Host内存vpcOutHostBuffer void* vpcOutHostBuffer = nullptr; vpcOutHostBuffer = malloc(resizeOutBufferSize_); //通过aclrtMemcpy接口将Device的处理结果数据传输到Host aclRet = aclrtMemcpy(vpcOutHostBuffer, resizeOutBufferSize_, resizeOutBufferDev_, resizeOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST); //释放掉输入输出的device内存 (void)acldvppFree(resizeInDevBuffer_); (void)acldvppFree(resizeOutBufferDev_); //在Host侧回传数据使用完成后,释放Host内存 free(vpcOutHostBuffer); } else { //此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存 (void)acldvppFree(resizeInDevBuffer_); (void)acldvppFree(resizeOutBufferDev_); } //12. 释放运行管理资源 //13. AscendCL去初始化 //....