专栏算法工具链【J6】crop输入解读与代码详解

【J6】crop输入解读与代码详解

Jade-self2024-12-16
120
0

1. crop方案解读

1.1 引言

在OE/samples/ucp_tutorial/dnn/basic_samples/code/02_advanced_samples/crop路径下,提供了一个crop示例,该示例主要帮助您熟悉如何对图像进行裁剪并作为模型的输入进行推理。

示例代码的整体流程与 00_quick_start 相同,差异主要在于输入数据的准备,对整体流程感兴趣的可见文章J6 C++模型推理快速上手代码解读

crop裁剪的原理:通过已存在图像的内存地址,进行偏移到ROI左上角点,通过控制stride的大小将图像多余的部分进行屏蔽从而准备好模型的输入。此时最大的疑问可能是:如何实现内存地址偏移?

1.2 使用限制

  • 原始图像:要求原始图像分辨率较大,至少要大于模型的真实输入,并且提前将原始图像读入到BPU内存中。

  • 模型输入:要求模型的真实输入validShape为固定的,stride为动态的,这样能通过控制stride的大小对原始图像进行裁剪。

  • 裁剪位置:裁剪是对图像内存进行偏移,对于输入内存的首地址要求 32 对齐,因此对偏移的大小有限制。另外,需要注意不能发生 mem 越界,下文会介绍可能发生mem越界的场景。

1.3 示例描述

  • 原始图像:斑马图片的实际大小为376x376,将图片读入转化为Y和UV输入,进行 width 32 对齐后分别存在两块BPU内存中, 32 对齐后斑马图片的宽 image_width_stride = 384。

  • 模型输入:模型有两个真实输入

    • y: validShape = (1,224,224,1), stride = (-1,-1, 1,1)

    • uv: validShape = (1,112,112,2), stride = (-1,-1,2,1)

  • 裁剪方案:在图像中裁剪出一块224x224大小的区域作为模型输入,选择起点(crop_left,crop_top)=(64,50)作为左上角点,224x224的裁剪shape可以获取到大部分斑马图像,并且偏移后的内存首地址(往下看)正好 32 对齐,满足要求,如下图所示。

Description
  • 输入张量准备:

    • Y输入的stride为[224 * image_width_stride,image_width_stride,1,1],裁剪图像左上角点对应的坐标[0,crop_top,crop_left,0]为[0,50,64,0],则地址偏移为 50 * image_width_stride + 64 * 1 = 50 * 384 + 64 * 1 =19264;

    • UV输入的stride为[112 * image_width_stride,image_width_stride,2,1],裁剪图像左上角点对应的坐标[0,crop_top,crop_left,0]为[0,25,32,0],则地址偏移为 25 * image_width_stride + 32 * 2 = 25 * 384 + 32 * 2 =9664;

2. 代码解读

对整体流程感兴趣的可见文章J6 C++模型推理快速上手代码解读。本节将重点介绍:输入数据的准备,

输入参数:

  • input_tensor:一个包含 hbDNNTensor 的向量,用于存储模型输入张量。

  • image_mem:包含图像内存地址的向量(虚拟地址 virAddr 和物理地址 phyAddr)。

  • image_width_stride:图像数据的行步幅(字节单位),需要满足 32 字节对齐。

  • dnn_handle:DNN(Deep Neural Network)句柄,用于获取模型输入张量属性。

主要功能:

  • 获取模型输入属性:调用 hbDNNGetInputTensorProperties 获取 Y 和 UV 输入张量的属性。

  • 更新步幅(stride):根据 image_width_stride 和输入张量的形状,设置 stride。

  • 裁剪图像区域:从输入图像中裁剪出特定区域,确定内存偏移量。

  • 更新输入张量的内存地址:将输入张量的 virAddr 和 phyAddr 偏移到裁剪区域的起始地址。

  • 内存对齐检查:确保输入张量的地址满足 32 字节对齐 的要求。

编译后,示例运行可以进入 02_advanced_samples 目录,执行 sh run_crop.sh 即可。脚本执行成功后会打印置信度最高的5个分类结果,分类结果置信度最高的编号 340 表明是斑马。

3. crop中的内存越界

正常准备输入 tensor 时,input_memSize 会基于 stride[0] * validShape.dimensionSize[0] 计算

但对于首地址偏移去做抠图的情况,需要注意不能发生 mem 越界。
此时,应该:减去 crop_left*input_properties.stride[2] ,举个例子:
  • 原图大小 HxW=400x512

  • 裁剪起始点 [80, 192],那么y_offset为

  • y_valid_shape = [1, 320, 320, 1]

结合:

那么y_stride = [512*320, 512, 1, 1]。
如果按照常规的计算方式:
那么:y_mem.memSize = 5123201 = 163840
此时:y_offset + y_mem.memSize = (80512 + 1921) + 5123201 > 400x512,会发生内存越界。
解决方案:减去 crop_left*input_y_properties.stride[2] = 192 即可!
Description
算法工具链
社区征文征程6杂谈技术深度解析
评论0
0/1000