下面随笔系列将对Hi3559AV100 RFCN实现细节进行解析,整个过程涉及到VI、VDEC、VPSS、VGS、VO、NNIE,其中涉及的内容,大家可以参考之前我写的博客:
基于Hi3559AV100 RFCN实现细节解析-(3)系统输入VI分析一 :
https://www.cnblogs.com/iFrank/p/14481080.html
整个的RFCN VI实现过程在上一篇随笔已经介绍了,函数具体含义也通过注释进行了一一的说明,而在VI初始化过程中,用到了ISP(Image Signal Processing) 图像信号处理的相关知识,海思也为其定义了API接口,下面随笔将介绍ISP相关概念,具体参考《HiISP开发参考》,方便大家对VI整个过程进行了更为清晰的认识。
1、基本概述
ISP 通过一系列数字图像处理算法完成对数字图像的效果处理。主要包括 3A、坏点校正、去噪、强光抑制、背光补偿、色彩增强、镜头阴影校正等处理。ISP 包括逻辑部分以及运行在其上的 firmware。1.1、功能描述
ISP 的控制结构如图 1所示,lens 将光信号投射到 sensor 的感光区域后,sensor 经过光电转换,将 Bayer 格式的原始图像送给 ISP,ISP 经过算法处理,输出 RGB 空间域的图像给后端的视频采集单元。在这个过程中,ISP 通过运行在其上的 firmware 对 ISP逻辑,lens 和 sensor 进行相应控制,进而完成自动光圈、自动曝光、自动白平衡等功能。其中,firmware 的运转靠视频采集单元的中断驱动。PQ Tools 工具通过网口或者串口完成对 ISP 的在线图像质量调节。 图1 ISP控制结构示意图 ISP 由 ISP 逻辑及运行在其上的 Firmware 组成,逻辑单元除了完成一部分算法处理外,还可以统计出当前图像的实时信息。Firmware 通过获取 ISP 逻辑的图像统计信息,重新计算,反馈控制 lens、sensor 和 ISP 逻辑,以达到自动调节图像质量的目的。1.2、ISP构架
ISP 的 Firmware 包含三部分,一部分是 ISP 控制单元和基础算法库,一部分是AE/AWB 算法库,一部分是 sensor 库。Firmware 设计的基本思想是单独提供 3A 算法库,由 ISP 控制单元调度基础算法库和 3A 算法库,同时 sensor 库分别向 ISP 基础算法库和 3A 算法库注册函数回调,以实现差异化的 sensor 适配。ISP firmware 架构如图 2 所示。
图2 ISP firmware构架
1.3、Firmware内部流程
Firmware 内部流程分两部分,一部分是初始化任务,主要完成 ISP 控制单元的初始化、ISP 基础算法库的初始化、3A 算法库的初始化,包括调用 sensor 的回调获取 sensor 差异化的初始化参数;另一部分是动态调节过程,在这个过程中, firmware 中的 ISP 控制单元调度 ISP 基础算法库和 3A 算法库,实时计算并进行相应控制。Firmware 的软件结构如图 3 所示。图3 ISP firmware 软件结构
2、软件流程
ISP 作为前端采集部分,需要和视频采集单元(VIU)协同工作。ISP 初始化和基本配置完成后,需要 VIU 进行接口时序匹配。一是为了匹配不同 sensor 的输入时序,二是为 ISP 配置正确的输入时序。待时序配置完成后,ISP 就可以启动 Run 来进行动态图像质量调节。此时输出的图像被 VIU 采集,进而送去显示或编码。软件使用流程如图4所示。 图4 ISP firmware 使用流程PQ Tools 工具主要完成在 PC 端进行动态图像质量调节,可以调节多个影响图像质量的因子,如去噪强度、色彩转换矩阵、饱和度等。
如果用户调试好图像效果后,可以使用 PQ Tools 工具提供的配置文件保存功能进行配 置参数保存。在下次启动时系统可以使用 PQ Tools 工具提供的配置文件加载功能加载 已经调节好的图像参数。 下面给出代码示例:1 HI_S32 s32Ret; 2 ALG_LIB_S stAeLib; 3 ALG_LIB_S stAwbLib; 4 ISP_PUB_ATTR_S stPubAttr; 5 pthread_t isp_pid; 6 VI_PIPE ViPipe = 0; 7 8 /* 注册sensor库 */ 9 s32Ret = sensor_register_callback(ViPipe, &stAeLib, &stAwbLib); 10 if (HI_SUCCESS != s32Ret) { 11 printf(”register sensor failed!\n”); 12 return s32Ret; 13 } 14 /* 注册海思AE算法库 */ 15 stAeLib.s32Id = 0; 16 strcpy(stAeLib.acLibName, HI_AE_LIB_NAME); 17 s32Ret = HI_MPI_AE_Register(ViPipe, &stAeLib); 18 19 if (HI_SUCCESS != s32Ret) { 20 printf(”register ae lib failed!\n”); 21 return s32Ret; 22 } 23 /* 注册海思AWB算法库 */ 24 stAwbLib.s32Id = 0; 25 strcpy(stAwbLib.acLibName, HI_AWB_LIB_NAME); 26 27 s32Ret = HI_MPI_AWB_Register(ViPipe, &stAwbLib); 28 if (HI_SUCCESS != s32Ret) { 29 printf(”register awb lib failed!\n”); 30 return s32Ret; 31 } 32 /* 初始化ISP外部寄存器 */ 33 s32Ret = HI_MPI_ISP_MemInit(ViPipe); 34 if (s32Ret != HI_SUCCESS) 35 { 36 printf("%s: HI_MPI_ISP_Init failed!\n", __FUNCTION__); 37 return s32Ret; 38 } 39 40 /* 配置图像公共属性 */ 41 s32Ret = HI_MPI_ISP_SetPubAttr(ViPipe, &stPubAttr); 42 if (s32Ret != HI_SUCCESS) 43 { 44 printf("%s: HI_MPI_ISP_SetPubAttr failed with %#x!\n", __FUNCTION__, 45 s32Ret); 46 return s32Ret; 47 } 48 /* 初始化ISP Firmware */ 49 s32Ret = HI_MPI_ISP_Init(ViPipe); 50 if (HI_SUCCESS != s32Ret) { 51 printf(”isp init failed!\n”); 52 return s32Ret; 53 } 54 55 /* HI_MPI_ISP_Run单独启动线程运行 */ 56 if (0 != pthread_create(&isp_pid, 0, ISP_Run, NULL)){ 57 printf("create isp running thread failed!\n"); 58 return HI_FAILURE; 59 } 60 /* 启动VI/VO等业务 */ 61 //…… 62 63 /* 停止VI/VO等业务 */ 64 s32Ret = HI_MPI_ISP_Exit(ViPipe); 65 if (HI_SUCCESS != s32Ret) { 66 printf(”isp exit failed!\n”); 67 return s32Ret; 68 } 69 70 pthread_join(isp_pid, 0); 71 return HI_SUCCESS;