【2023 · CANN训练营第一季】数据预处理-JPEG数据解码

文档参考:CANN文档社区版: 6.0.RC1.alpha001

我们的模型输入是固定的图片格式、大小,但是实际上我们的想要进行推理的图片是各种各样的,在应用中,我们常使用NV12的图片作为模型的输入。如果输入是仅有Y分量的灰度图,我们便可以通过将UV分量的部分补充为灰色而满足我们的使用,但是如果我们的输入为JPEG图片,我们需要使用到ACL提供的媒体数据处理了相关API,对我们的图片进行预处理,把jpg图片进行解码成YUV格式的内容,并且获得其图片信息。

一、媒体数据处理API的V1

note:媒体数据处理V1版本与媒体数据处理V2版本的接口功能范围相同,都是描述处理媒体数据的接口,用于实现抠图、图片缩放、格式转换等功能,但两套接口不能混用


(资料图片)

在Device侧,我们对要进行媒体数据处理的相关数据的内存的申请和释放,就不可以简单的使用malloc,new或者aclrtmalloc等申请的内存了,我们需要使用dvpp接口。并且,从性能角度,为了减少拷贝,媒体数据处理的输出作为模型推理的输入,实现内存复用。我们尽量申请足够大的内存进行反复使用,尽可能避免反复使用dvpp的接口申请内存和释放,造成一定的性能损耗。

1.dvpp内存和通道

(1)内存申请与释放

note:调用该接口申请大页内存失败,仅表示系统内的大页内存不够

(2)通道的创建与释放

2.JPEGD相关接口

性能指标:

JPEGD性能指标是基于硬件解码的性能,JPEGD硬件解码不支持3个SOS的图片解码,对于硬件不支持的格式,会使用软件解码,软件解码性能参考为1080P 15fps。JPEGD解码的输出图片如果涉及旋转,则性能指标低于软件解码的参考值,例如对于1080P的图片,性能指标低于15fps。

以下性能数据,是基于一个stream上下发1个异步媒体数据处理任务后,执行一次aclrtSynchronizeStream接口。

在我们代码使用的过程中,其实最先需要了解的是我们所用的接口的性能,这直接影响到我们的使用方案,可以防止我们的代码设计直接超越了模块处理的性能。实际和官方标量有的时候会有一点实测的出入,不过最好还是按照手册中的描述进行预先规划,以下为手册中的指标:

功能说明:

JPEGD在解码图片时,支持对图片进行旋转。

JPEGD在解码图片时,支持按源图片格式解码。

图片分辨率约束:

输入图片分辨率:最大分辨率:8192x8192,最小分辨率:32x32。

输出图片分辨率:JPEGD只对图片解码,不会改变图片分辨率,因此输出与输入的图片分辨率保持一致。

输出的宽高对齐:

这里我仅写出了我们下方代码输出的yuv420SP(NV12 8bit)的情况

宽stride为宽128对齐后的值。

高stride为高16对齐后的值。

内存大小(单位Byte)≥ 宽stride * 高stride * 3/2

接口说明:

二、代码验证与学习

代码思路:

1.初始化好后,读取一个jpg图片并获得其图像信息,存入aclrtMalloc存入的内存中

2.创建dvpp通道,并将其解码为获取到的图像信息大小的yuv图片

3.按照次序销毁相关创建

好啦!让我们编译它!

有报错,查看错误代码,和该处代码:

发现是销毁时销毁顺序有问题,把Device和context都销毁了,才销毁通道。

所以,一定要注意销毁顺序!!!之前也提到过了,先创建->后销毁,后创建->先销毁!!!

修改后:

代码:

附上调试好的正确的代码:

runDecode.cpp(主函数文件)

dvpp_decode.cpp(decode处理文件)

dvpp_decode.h

cmakelist可以参考我之前的文章里有。

到这里就结束啦,想要存下来看看结果的同学也可以存成.yuv文件用yuvplayer打开看看哦!

ps:该文仅是为了记录CANN训练营的学习过程所用,不参与任何商业用途,有任何代码问题可以和我一起讨论修改

推荐内容