专栏算法工具链J5 全流程示例解读

J5 全流程示例解读

颜值即正义2022-12-22
984
14
  地平线征程5芯片(Jounery 5,以下简称J5)已经被越来越多的合作伙伴和开发者所使用,用于面向智能驾驶场景应用的开发。智驾应用是一个非常复杂的开发场景,不仅仅涉及到神经网络的训练和部署, 也覆盖到传感器的接入、图像处理和工程调优的大量工作,开发复杂度很高,有一定的上手门槛。

  千里之行始于足下,从一个最简化的全流程示例完成从Camera接入到目标检测输出的应用开发,将是进行复杂应用场景开发的第一步。为此,在地平线芯片算法工具链的工具包中提供了一个全流程的应用示例(ai_forward_view_sample),以源码的形式呈现了一个Hello World级别的视觉目标检测场景应用的Demo。下面和大家一起对该示例进行解读。

  为了更顺畅地理解此全流程示例的实现原理,希望大家对J5芯片、J5媒体系统接口、J5视频通路配置、算法工具链等背景知识已经有所了解。

1. 基础原理

1.1 硬件通路

  在解读代码之前,有必要了解一下J5芯片的视频通路硬件设计,了解J5芯片的硬件特性可以更好的理解如何高效的进行应用开发。

J5视频通路架构图


主要名词解释

名词

释义

VPS *

Video Process System 图像处理系统

VIN *

Video IN 图像输入

VPM*

Video Process Manager 图像处理管理

DVP

Digital Video Port 数字视频接口

CIM

Camera Interface Manager 图像数据通道管理

CIM-DMA

Camera Interface Manager(DMA output)图像数据通道管理(DMA输出)

ISP

Image Signal Processor 图像处理器

PYM

PYraMid 图像金字塔处理单元

GDC

Geometry Distortion Correction 几何畸变矫正

BPU

Brain Process Unit 地平线神经网络加速处理单元

*VPS/VIN/VPM 是虚拟概念,其他是实体硬件单元


  J5支持4路MIPI RX 和 2路MIPI TX,Camara通过MIPI 接口接入,通过配置实现On-line 模式或Off-line模式的数据处理流程(RX0/RX1支持配置成On-line模式,RX2/RX3支持配置成Off-line模式)。支持2路ISP和3路PYM,其中PYM2只支持off-line模式。
On-line模式:
相机RAW data直接从MIPI接口经过CIM接入到ISP模块,经过ISP处理后,直接进入金字塔模块进行图片的resize/crop操作,输出写入DDR中。在金字塔之前的链路上数据不需要经过DDR,避免了内存的写入读取开销,用于极低延时要求的场景。
Off-line模式:
相机RAW data 经过CIM-DMA模块写入DDR,ISP/PYM/BPU等模块都从DDR上读取数据进行处理后再写入DDR。

  从Camera接入,到神经网络处理的最基本的数据流如下所示,每个硬件模块的工作模式通过JSON配置文件进行配置,重点会涉及到三个重要的配置文件:mipi config、cim config、vpm config,后文将有更多的解读。

数据流图


  Camera通过MIPI TX 接入后,可配置经过On-line 或 Off-line的模式,将RAW data直接送入到ISP 或是DDR。在这一阶段通过mipi config 和 cim config 两个配置文件来配置实现。

  RAW data经过ISP的处理后可以配置直接送入金字塔(PYM)进行crop/resize操作,将图像处理成算法模型所需的尺寸大小。在这一阶段通过vpm config 配置文件进行配置完成。

视频通路支持多种灵活的pipeline配置, 详细的配置说明请参考《MU-3020-12-J5-视频通路配置指南》


  图像数据经过金字塔(PYM)处理后输出的是YUV420格式(NV12),该数据格式可以被BPU直接处理。BPU支持在模型中将该数据格式高效的转换成算法模型所需的输入格式(例如RGB/BGR等),并且由于在整个通路上是共享DDR,数据不需搬运即可被BPU所处理,实现零拷贝,最大化的降低了整个处理流程的延时。


1.2 软件Pipeline

  在软件层面如何初始化各硬件模块,并实现从Camera->ISP->PYM的数据流处理,除了上面所述的几个重要的配置文件外,还需要依赖J5平台所提供的Auto媒体系统接口(VIO APIs)进行配置的加载和运行,实现数据流pipeline的的运行和图像数据的获取。下面对流程中核心的API进行简要说明。

详细的VIO APIs接口说明请参考《MU-3020-5-J5-图像媒体模块调试指南》

视频通路调用流程图


1.3 模型推理

  从金字塔(PYM) 输出的YUV420数据送给BPU作为视觉感知算法模型的输入,BPU上进行模型推理使用libDNN推理库提供的APIs,下图对推理的流程及使用的API做简要的介绍。

详细的接口使用说明可以参考《地平线征程5 算法工具链:5.2 BPU SDK API手册》

模型推理调用流程图


2. 示例功能

  在J5 算法工具链开发包(OpenExplorer)的“ddk/samples/ai_forward_view_sample”目录下提供了一个从Camera接入到检测算法推理,再到将结构化结果在图像上渲染的全流程示例,是打通视频通路和模型推理的有效参考实现。建议大家在深入示例代码前先编译、运行该示例,体验示例的功能,有一个感性的认识。

全流程示例主要呈现了如下的功能:
1. Camera接入
目前Camera支持max9296+ar0233 和max96712+ar0233。不同的摄像头模组通过配置文件进行配置。

2. ISP/PYM配置使用
通过配置文件实现将Camera数据处理成算法模型推理所需要的输入数据,包括crop/resize功能。

3. 网络图像回灌
实现通过网络发送/接收图像数据作为数据源,完成检测算法推理和可视化渲染功能。

4. 检测模型BPU推理
集成了一个目标检测模型(fcos_efficientnetb0),在BPU上执行图像推理,实现对输入图像中的目标进行检测,输出目标bounding box。

5. 检测结果可视化渲染
将目标检测结果渲染在输入图像上,通过后台uws服务提供web方式的可视化渲染能力。

本文重点对视频通路、模型推理的部分进行解读,网络回灌和可视化渲染只是为了提供更完整、丰富的示例功能,不做详细分解


3. 实现框架

  整个示例涉及到Camera的接入、图像数据处理、算法模型推理、检测结果后处理、图像编码、结果可视化渲染多个功能,为了代码实现更加清晰和解耦,设计了多个不同模块分别完成不同阶段的功能,并最大化减少相互间的依赖。

模块框架图


整个示例设计了5个模块来实现不同的任务,做到功能解耦。

模块

功能说明

VIOModule

视频输入模块。对Camera、网络回灌不同的输入模式进行了实现封装,根据配置文件创建不同的子模块实例(CameraInputModule, NetworkInputModule)

InferenceModule

模型推理模块。加载目标检测模型在BPU上实现对视频通路的图像数据进行推理执行

PostProcessModel

后处理模块。实现目标检测模型的后处理逻辑,主要是NMS算法的后处理实现

CodecModule

编解码模块。实现将从金字塔输出的YUV420的图像数据转换编码成JPEG格式数据,用于可视化渲染

WebDisplayModule

Web渲染模块。实现检测目标Box与图像进行合成渲染,通过UWS服务提供可以Web访问的可视化能力


  不同的Module里显式的调用下游Module的接口进行数据流的处理,在上面的框架图中已标记出相应的接口。下图对整个示例的运行流程进行详细拆解。

模块调用时序图



4. 模块分析

  对整个流程中的三个重点模块进行详细解读,这三个模块构成了在J5开发板上完成一个完整通路的必要流程。


4.1 VIOModule

  VIOModule 封装应用数据源的实现,包含了从Camera输入和网络回灌输入两种模式,通过配置文件(j5_vio_config.json)进行输入模式指定,运行时根据模式类别创建相应InputModule实例,加载不同的配置。
“config_index" 指定示例应用启用何种配置,不同的相机模组可增加不同的配置项,当前示例配置中描述了三种配置选项,config_0 用于max9296 camera模组的接入配置;config_1 用于网络回灌的接入配置;config_2 用于max96712 camera模组的接入配置。
"data_source" 用于指定当前config的数据源类型,分为mipi和network两种。摄像头接入配置为:“mipi_camera”; 网络回灌配置为: “network_feedback”。VIOModule在运行时,根据data_source 的配置创建 CameraInputModule 或 NetworkInputModule的实例。本文将只对CameraInputModule进行解读,如果有更多同学对网络回灌有兴趣,后期再对NetworkInputModule进行解读。
"source_cfg_file" 指定数据源的配置文件路径。对于camera输入,该配置文件中将在CameraInputModule或NetworkInputModule中解析。对于Camera输入,将包含对mipi config 和 cim config的配置文件指定。对于Network输入,主要配置端口号和回灌图像的size信息。
"vpm_cfg_file" 指定视频通路pipeline的配置文件路径。该配置文件中将对ISP/PYM/GDC器件进行配置,在CameraInputModule的初始化中作为hb_vio_init() 的参数,用于VIO通路的初始化。示例中未使用到GDC。


4.2 CameraInputModule

  该Module主要实现摄像头的接入配置、VIO Pipeline的启动、图像数据的获取,并调用下游Modules进行图像数据的处理。 源码实现路径:src/modules/input/camera_input_module.cc


4.2.1 配置分析

  视频通路主要由VIN/VPM模块覆盖,硬件通路的配置主要是VIN 和 VPM相关配置文件,先对配置进行分析。

  VIN负责Camera接入部分功能,其中包括Sensor/Serdes、MIPI、CIM/CIM DMA及同步LPWM等,对用户提供统一的API,各中Camera的差异性则通过JSON方式配置,用以适配各类接入场景。

  VIN部分的配置共有3个JSON 配置文件,配置结构如下:

VIN Config 结构


Mipi config: 该配置文件在示例代码的 configs/vio/vin/camera/hb_j5dev.json 中指定,如下所示:

Cim config:该配置文件在示例代码的 configs/vio/vin/camera/hb_j5dev.json 中指定,如下所示:

两个子配置文件都可以在J5 板上环境相应目录找到,详细的配置项不做展开。

配置参数详解可以参考系统软件手册《MU-3020-12-J5-视频通路配置指南》


VPM 数据通路主要包含ISP、PYM,和其他模块(GDC、Stitch等)的配置,配置文件结构如下:

VPM Config 结构


VPM config:该配置文件在示例代码的 configs/vip/vpm/vpm_config.json , 对ISP和PYM进行了配置。

isp_stream_output_format 配置了ON-LINE 直连到PYM

示例中配置了Downscale的第一层,从原图中的[0,0, 960,540]的ROI区域缩放到[512, 512]的图像大小,该大小是后续推理模型的输入尺寸。


4.2.2 运行模式

到此时可以深入代码进行解读CameraInputModule的运行机制。首先看类图理解继承关系和接口。

输入Module类图


InputModule在被Start后将创建一个工作线程(produce_thread_),该线程持续的获取输入数据(CameraInputModule从金字塔读取Frame data,NetworkInputModule从网络接收Image data),并将数据传递给下游Module(如InferenceModule,CodecModule)


4.3 InferenceModule

  模型推理模块主要实现目标检测模型的推理,如何在J5上部署模型,可以参考OpenExplorer中的参考示例(ddk/samples/ai_toolchain/horizon_runtime_sample/code/00_quick_start),这里对使用推理库(libDNN) APIs进行模型部署的流程不做太多介绍,重点说明在通过视频通路金字塔作为输出时的数据处理。


4.3.1 检测模型信息

  示例中集成了一个编译好的目标检测模型(configs/model/fcos_efficientnetb0_mscoco.hbm),该模型是efficientnetb0为backbone的FCOS模型,提供对车辆、行人等目标的检测能力。该模型在交付包中提供了实现源码(ddk/samples/ai_toolchain/horion_model_train_sample/release_modles/fcos_efficientnetb0_mscoco)。

模型的基本信息:

model name: fcos_effb0_test_model
input[0]:
name: arg0[img]
input source: HB_DNN_INPUT_FROM_PYRAMID
valid shape: (1,3,512,512,)
aligned shape: (1,3,512,512,)
aligned byte size: 393216

  从模型信息看到,input source是HB_DNN_INPUT_FROM_PYRAMID, 输入源是金字塔,输入类型是NV12。Valid shape 表示模型输入的有效shape是 1x3x512x512, 所以上面介绍的金字塔配置部分,配置了从Camera输入原图Downscale到512x512的尺寸,直接可作为模型的推理输入数据。


4.3.2 异步处理机制

  在InferenceModule中实现了数据异步处理的机制,创建了一个queue,用于缓存从上游Feed的Frame Data,在Module Start时创建的工作线程(produce_thread),从queue读取数据进行模型推理,实现上下游的执行解耦。该机制在其他Module(例如PostProcessModule)中都有使用,将不再赘述。

异步处理机制


4.3.3 Zero-Copy

  从视频通路金字塔输出的数据需要传递给BPU作为算法模型推理的输入,是否需要内存复制?回答是否,因为金字塔与BPU可以共享DDR,金字塔的输出内存地址可以直接给BPU进行处理,实现Zero-Copy,实现极致的性能。
  从金字塔输出的图像格式是NV12_SEPARATE,模型输入Tensor 内存数据需要将Y和UV分量数据分开赋值,因为共享内存,只需要将相应的物理地址和虚拟地址赋值到Input Tensor memory中即可,无需memory copy。具体的实现逻辑可以阅读DoInference()中的实现代码。
  在上面的分析中看到,在金字塔的配置中配置的是DownScale的第0层,所以获取输出数据的来源是roi_ds_[0]
其中的y_offset/c_offset 是为了支持对图像进行crop,本示例中无需crop,所以运行时这两个变量为0,无需考虑。
推理的输出output_tensor 进行简单封装后传递给下游PostProcessModule进行后处理。


4.4 PostprocessModule

  后处理模块的运行机制与InferenceModule类似,功能上实现了NMS(non maximum suppression,非极大值抑制算法),此处不做更多解读,网络上有很多材料可以学习。
通过后处理的配置文件(configs/model/postprocess_config.json)可以微调部分参数,例如score_threshold, iou_threshold等,用于改善误检或漏检的效果。

  该模块将BBox数据传递给WebDisplayModule,用于与CodecModule编码输出后的JPEG进行合并渲染,并提供可视化功能。


5.渲染效果

  到此处,主要的模块解读完成,最后根据示例代码中的README,根据接入的摄像头型号的不同简单的调整一下config,运行一下示例,既可在浏览器中查看检测输出的可视化效果。如下图,是通过示例中集成的图片回灌得到的渲染效果,后处理配置中的score_threshold微调到0.61。

渲染效果

算法工具链
征程5官方教程
+11
评论6
0/1000
  • 辰池剑影
    Lv.1

    1. MIPI RX0通过CIM直连到ISP0,如果MIPI RX0可以接4路sensor,那么这四个sensor如何直连的,ISP0端开了四组接收信号口?ISP在处理四个sensor的数据时候,如何区分哪个sensor?

    2. DVP接口目前的使用场景是啥?主要用在哪些车载设备?

    2023-04-24
    0
    4
    • 新手村回复辰池剑影:

      您好:

      1. RX0接入4路sensor,需要通过加串器和解串器进行接入;ISP能够同时接收4路sensor数据后,会先下到DDR进行缓存,再frame by frame 分时处理;由于是frame by frame的处理,是可以进行区分的;

      2. DVP目前没有应用场景;

      望知悉

      2023-04-24
      0
    • 辰池剑影回复新手村:

      1. RX0接入4路sensor,需要通过加串器和解串器进行接入;ISP能够同时接收4路sensor数据后,会先下到DDR进行缓存,再frame by frame 分时处理;由于是frame by frame的处理,是可以进行区分的;

      —— RX0接的是CIM,RX2接的是CIM-DMA,图中CIM-DMA也是写DDR的形式,这样看CIM和CIM-DMA都是写DDR分时处理,他们的区别主要是什么?
      2023-04-25
      0
    • dengxiao回复辰池剑影:

      我的理解是,如果RX0接了1路Raw sensor,是可以使用CIM在线方式送给ISP处理,不需要写DDR,如果是接了4路,没法使用CIM在线方式,只能通过写DDR离线方式给ISP分时处理.

      2023-06-26
      0
    • 新手村回复辰池剑影:

      CIM只能硬件直连的方式传输数据给后级,CIMDMA只能先把数据下到DDR,再M2M的方式给到后级

      2023-08-03
      0
  • higher
    Lv.1

    zero copy模式

    模型如何配置才能使用,正常模型配置是NV12的格式,输入tensor的y和uv数据在一块bufer指针 input_tensor->sysMem[0], 如何指定配置模型,让模型可以理解NV12_SEPARATE模式?
    2023-02-27
    0
    3
    • 颜值即正义回复higher:
      你好,目前 PTQ 转换生成的 nv12.bin 模型确实是 NV12 类型(y和uv连续存储),但可以在部署代码中,显式地修改模型输入节点的属性 NV12_SEPARATE 类型,就可以适配了
      2023-02-27
      0
    • higher回复颜值即正义:

      如何在部署代码中显式配置 输入节点属性为NV12_SEPARATE? 是否有参考代码,感谢

      2023-02-27
      0
    • 颜值即正义回复higher:
      没有单独的参考代码,但可以说一下处理逻辑,就是我们先通过 hbDNNGetInputTensorProperties 接口获取到模型输入节点的属性,其中 hbDNNTensorProperties.tensorType 就可以从 HB_DNN_IMG_TYPE_NV12 更改为 HB_DNN_IMG_TYPE_NV12_SEPARATE
      2023-03-07
      0
  • samliu
    Lv.1

    期待讲解NetworkInputModule这个模块,并详细讲解搭建网络数据回灌的环境和具体方法。

    2022-12-28
    2
    0
  • freepeasantry
    Lv.1

    整个这部分的消息处理,有没有统一的?类似DDS,FDDS?

    2023-08-02
    0
    1
    • 新手村回复freepeasantry:

      DDS目前项目上用的比较少;

      一般情况下:
      1.感知数据通过shm分发给多进程;

      2.感知结果通过proto+zmq分配

      2023-08-03
      0
  • zhangleixbj
    Lv.1
    "ds_roi":[{"ds_roi_layer":0,
    "ds_roi_sel":1,
    "ds_roi_start_top":0,
    "ds_roi_start_left":0,
    "ds_roi_region_width":960,//原图ROI [0,0,960,540]
    "ds_roi_region_height":540,"ds_roi_stride_y":512,"ds_roi_stride_uv":512,"ds_roi_out_width":512,// Downscale to [512,512]"ds_roi_out_height":512},
    我觉得不应该是原图ROI,应该是bilinear_info里等比例缩小后的ROI 960x540 对应原图1920x1080
    2023-09-04
    0
    0
  • 默认94720
    Lv.1

    你好,文章里的图都加载不出来了

    2025-02-12
    0
    0