书接上回,在学习过JPEGD的样例之后,再来看resize的样例,之前提到过的这里就不再赘述,多关注功能本身是怎么实现的
图片缩放的开源样例
https://gitee.com/ascend/samples/tree/master/cplusplus/level2_simple_inference/0_data_process/resize
sample_build.sh中下载的图片是wood_rabbit_1024_1068_nv12.yuv
sample_run.sh中run命令是
./main ../data/wood_rabbit_1024_1068_nv12.yuv 1024 1068 ./output/output.yuv 224 224
第0个参数 ./main
第1个参数 ../data/wood_rabbit_1024_1068_nv12.yuv
第2个参数 1024
第3个参数 1068
第4个参数 ./output/output.yuv
第5个参数 224
第6个参数 224
参考main.cpp分析参数的意义
main第166行调用Initparam()函数解析参数
Initparam第43-45行,尝试打开目录“./output”,如果目录流为空指针,即该目录不存在时,创建目录“./output”
Initparam第46-49行,检查是否传入7个参数
Initparam第50-56行,将第2个参数1024通过atoi()函数转为int类型,保存在inw中;以此类推
inw=1024 输入图片宽
inh=1068 输入图片高
outw=224 输出图片宽
outh=224 输出图片高
inPicDesc={../data/wood_rabbit_1024_1068_nv12.yuv, 1024, 1068} 输入图片描述信息
outPicDesc={./output/output.yuv, 224, 224} 输出图片描述信息
熟悉所有参数之后再来看main.cpp中的main函数
main第154-157行,调用aclInit函数进行初始化
main第159-163行,调用aclrtSetDevice函数初始化device,调用aclrtCreateContext函数初始化context,调用aclrtCreateStream函数初始化Stream,调用aclrtGetRunMode函数获取运行模式为ACL_HOST
为了验证运行模式,我在main.cpp加入了一段打印信息的代码,确认runMode为ACL_HOST
main第166-168行,调用Initparam函数,如前所述解析参数并定义整型常量ModelInputWidth和ModelInputHeight分别描述待缩放图片的宽高
main第171行,调用acldvppCreateChannelDesc函数,创建通道描述符dvppChannelDesc_
main第174行,调用acldvppCreateChannel函数,创建通道
main第177-178行调用ReadBinFile函数
ReadBinFile第89-93行调用ifstream函数,以二进制文件方式打开yuv文件,并检查是否成功打开
ReadBinFile第95行调用seekg函数,从文件末尾位置binFile.end偏移0个单位
ReadBinFile第96-101行调用tellg函数返回当前文件流位置,即文件大小,并定义整型变量binFileBufferLen存放文件大小,然后检查文件是否为空
ReadBinFile第103行调用seekg函数,从文件开始位置binFile.beg偏移0个单位
ReadBinFile第105-110行调用new函数,分配一个char数组,数组中共有binFileBufferLen个char元素,并返回指向第一个char的指针,让指针binFileBufferData指向数组第一个char
ReadBinFile第111行调用read函数,从流当前位置(文件开始位置)开始,读取binFileBufferLen个char,并将其存入binFileBufferData指针所指的位置
ReadbinFile第112行调用close函数关闭读取文件的流
ReadbinFile第113行将binFileBufferLen作为文件大小传递给fileSize,即main中的inputBuffSize
ReadbinFile第114行返回缓存首地址指针binFileBufferData给main中的inputBuff
回到main函数
main第180行根据host侧的内存大小inputBuffSize定义device侧的缓存大小inBufferSize
main第181行调用acldvppMalloc函数,根据inBufferSize,在device侧申请内存,并用指针inBufferDev指向申请到的内存首地址
main第182-187行,由于runMode是ACL_HOST,所以触发if分支,调用aclrtMemcpy函数,将host侧源位置inputBuff上大小为inputBufferSize的内容,复制到device侧位置从inBufferDev开始大小为inBufferSize的内存上
main第188行删除host侧的内存inputBuff
main第190行调用acldvppCreateResizeConfig函数,创建用于存放图片缩放配置数据的变量resizeConfig_
main第193-194行从解析得到的参数中提取原图片宽高信息
main第199-200行,调用AlignmentHelper函数进行对齐,宽对齐到128,高对齐到16,得到对齐后的图片宽高
main第201行根据对齐后的原图宽高计算对齐后的原图内存大小,并存放在inputBufferSize中,该计算公式可从文档中查到
main第202-203行分别创建缩放前后的图片描述符vpcInputDesc和vpcOutputDesc
main第204-212行调用acldvppSetPicDesc系列函数为图片描述符vpcInputDesc_设置参数
其中main第205行提供device侧缓存的地址指针inBufferDev,并以char类型作为读取方式,读取device侧图片数据
然后,指定图片格式、原图宽高、对齐后宽高、缩放前对齐后图片内存大小
main第215-216行调用AlignmentHelper函数进行对齐,将缩放后的目标宽度对齐到16,缩放后的目标宽度对齐到2,详情参见文档约束说明
main第217行根据对齐后的缩放后的宽高计算缩放后输出图片的内存大小,并存放在outputBufferSize中,该计算公式可从文档中查到
main第218行调用aclrtMalloc函数,在device侧申请大小为vpcOutBufferSize的内存,用于存放缩放后的数据
main第219-228行调用acldvppSetPicDesc系列函数为图片描述符vpcOutputDesc_设置参数,设置了图片内存、格式、目标宽高、对齐后的目标宽高、缩放后对齐后图片内存大小
main第230-235行,调用acldvppVpcResizeAsync函数,传入通道描述符dvppChannelDesc_,传入缩放前输入图片描述符vpcInputDesc_,传入缩放后输出图片描述符vpcOutputDesc_,传入图片缩放配置数据resizeConfig_,传入流stream_,执行异步缩放
main第237-241行,调用aclrtSynchronizeStream函数,阻塞程序直到流stream_内所有操作完成
main第244-252行,释放图片缩放配置数据、释放缩放前输入图片描述符、释放缩放后输出图片描述符、释放device侧缩放前数据缓存
main第254-258行,调用SaveDvppOutputData函数,将device侧的数据搬运到host侧,并保存成输出图片yuv文件
main第259-261行,释放通道、释放通道描述符
main第263行调用DestroyResource函数,释放stream、释放context、释放device、调用aclFinalize去初始化
至此,main.cpp结束
最后,附上文档中对resize流程的描述