IS(Image Stabilization) 用户指南¶
REVISION HISTORY¶
| Revision No. | Description |
Date |
|---|---|---|
| 1.0 | 10/09/2023 | |
| 01/10/2024 | ||
| 03/26/2024 | ||
int (*early_init)(struct gyro_dev * dev); int (*final_deinit)(struct gyro_dev * dev); int (*get_group_delay)(struct gyro_dev *dev, struct gyro_arg_group_delay * delay); int (*get_noise_bandwidth)(struct gyro_dev *dev, struct gyro_arg_noise_bandwidth *nbw); |
05/30/2024 | |
| 06/19/2024 | ||
| 07/11/2024 | ||
| 10/15/2024 | ||
| 08/11/2025 | ||
| 09/22/2025 |
1. 前言¶
受各种因素影响,摄像机拍摄的视频易出现抖动现象,影响视频观感。为了增强视频稳定性,提高观感,需要进行防抖处理。目前防抖模式支持DIS-GME、DIS-GYRO和DIS-CUST,以下将详细介绍三种模式。
2. DIS-GME 工作模式¶
2.1 基本概念¶
该防抖模式对应为数字图像防抖(Digital Image Stabilization, DIS),不同于机械防抖、光学防抖、电子防抖,其利用图像特征对产生抖动的视频帧进行几何变换,从而起到防抖作用。
2.2 基本原理¶
视频产生抖动,即视频帧之间产生运动偏移,可以用二维变换模型描述:
其中 (x,y) 表示原来图像的坐标,3\times3 矩阵 H 包含了运动偏移信息, ({\Large \frac{u}{w}} ,{\Large \frac{v}{w}} ) 表示偏移后的图像坐标。
DIS的基本原理即为利用相邻视频帧计算出矩阵 H,然后再根据矩阵 H 做运动补偿去除偏移。但对视频帧做运动补偿后,会产生无内容区域,为去除无内容区域,需要对视频帧进行裁剪并放大,显示出相邻帧间的共有内容区域。
DIS基本原理 |
2.3 调试指南¶
2.3.1 视频质量和应用场景需求¶
为达到理想的DIS效果,视频质量和应用场景应满足以下需求。
2.3.1.1 Rolling Shutter¶
输入视频的Rolling Shutter会影响DIS效果,因此需要调节系统参数(如曝光时间等),控制Rolling Shutter在可接受范围。
2.3.1.2 视频清晰度¶
相机抖动产生的运动模糊会影响DIS的特征点检测,导致矩阵估计不准确,也会导致最终输出的结果中有拖影,因此需要调节IQ(Image Quality)保证相机在静止和抖动情况下视频帧均清晰,不产生运动模糊。如下图所示为相机抖动情况下调节IQ前后。
调IQ前含运动模糊的视频帧 |
调IQ后清晰的视频帧 |
2.3.1.3 畸变¶
视频畸变对DIS效果也存在影响,建议使用畸变尽量小的镜头,或进行畸变校正,以消除视频畸变对DIS效果的影响。如下图所示为畸变校正前后。
畸变的视频帧 |
畸变校正后的视频帧 |
2.3.1.4 视差¶
具有较大视差(即前景和背景具有明显深度差异)的场景,可能会造成DIS输出的视频扭曲。因此,不建议DIS应用在视差大的场景。
视差大的视频帧 |
2.3.1.5 低照度场景¶
在一定的暗光范围内,DIS仍可正常工作。但是在极低照度环境下,DIS会检测不到特征点,导致效果变差。因此,不建议DIS应用在极低照度环境,如下图:
极低照度的视频帧 |
注意:
在串流开始时,ISP 模块会收敛,默认会丢掉10张图片,该过程正是从暗到亮的过程,若收敛次数不够,可能也会导致送给DIS模块的图片亮度信息在变化(有可能依旧很暗),如下图:
ISP收敛过程极低照度的视频帧 |
ISP收敛过程低照度的视频帧 |
2.3.1.6 视频宽高比¶
IS正常支持16:9的视频,对于9:16的视频,效果可能略微受到影响。
2.3.2 参数设置¶
2.3.2.1 eMode¶
DIS算法模式。
| 成员名称 | 描述 |
|---|---|
| MI_LDC_DIS_GME_6DOF | 6自由度防抖,不使用陀螺仪 |
| MI_LDC_DIS_GME_8DOF(默认) | 8自由度防抖,不使用陀螺仪 |
DIS是对产生抖动(几何变换)的帧做逆变换。6自由度防抖支持的图像变换有平移、旋转、缩放、拉伸、剪切。8自由度支持的图像变换有平移、旋转、缩放、拉伸、剪切和透视。在某些具有复杂抖动的场景中,8自由度防抖会比6自由度防抖效果更好一些,但同时计算量也会增大。
2.3.2.2 eSceneType¶
DIS应用场景类型。
| 成员名称 | 描述 |
|---|---|
| MI_LDC_DIS_FIX_SCENE(默认) | 固定场景,如固定在建筑物上的安防监控摄像机。 |
| MI_LDC_DIS_MOVE_SCENE | 运动场景,如手持、车载或机载摄像机。 |
2.3.2.3 u8CropRatio¶
DIS输出图像裁剪比,取值范围为[50, 98],即裁剪后保留的图像区域比例为50%~98%。默认的裁剪比为70,即若输入图像宽高为1920×1080,则裁剪后图像宽为1920×70%=1344,高为1080×70%=756。
一般来说,视频抖动幅度越大,相邻帧间的共有内容区域越小,为了维持较好的防抖效果,需要设置u8CropRatio越小。但u8CropRatio太小又会损失过大视场。因此,u8CropRatio的设置应根据实际场景中的抖动幅度来调节,平衡防抖效果和视场大小。
2.3.2.4 eMotionLevel¶
相机的抖动幅度级别。
| 成员名称 | 描述 |
|---|---|
| MI_LDC_DIS_MOTION_LEVEL0 | 抖动幅度较小 |
| MI_LDC_DIS_MOTION_LEVEL1(默认) | 抖动幅度较大 |
2.3.3 问题排查流程¶
DIS效果变差或输出warning时,请按照如下流程依次排查。
2.3.3.1 查看输入视频质量和场景¶
| 现象 | 可能的原因及解决办法 |
|---|---|
| 输出视频有拖影闪烁 | 逐帧检查输入的视频是否存在运动模糊,如果有运动模糊需要调IQ消除运动模糊 |
| 输出视频不防抖或有扭曲 | 1. 查看输入视频中的场景是否缺少特征(极低照度、大物体遮挡等原因均有可能导致缺少特征) 2. 查看输入视频中前景和背景是否具有明显深度差异(大视差) 3. 查看输入的抖动视频中是否有大运动前景 4. 查看输入的视频是否有明显rolling shutter (以上原因导致的DIS效果变差是算法固有缺陷,属正常现象) |
2.3.3.2 查看参数配置¶
排除以上可能的原因后,检查参数设置是否合理,请参考章节《2.3.2 参数设置》。另外,未开放的参数中,请按照默认配置,不能更改。
3. DIS-GYRO 工作模式¶
3.1 基本概念¶
该防抖模式对应为电子图像防抖(Electronic Image Stabilization, EIS),其陀螺仪算法根据陀螺仪产生的数据计算当前帧的图像的运动偏移情况,进行几何变换,从而起到防抖作用。 目前EIS支持X、Y、Z轴的补偿(X/Y/Z轴的旋转),并且支持叠加畸变矫正功能。
3.2 基本原理¶
EIS的原理是通过在图像处理过程中对影像进行补偿和校正,以消除由于相机晃动引起的影像不稳定。一般的EIS的工作如下:
- 感知晃动:相机内部的加速度计或陀螺仪等传感器会监测相机的晃动和移动;
- 储存影像:相机会持续地捕捉影像并将其存储在缓冲区中,通常是以连续的帧(frames)形式;
- 分析影像:通过分析连续的影像帧,EIS可以检测到相机的晃动和移动轨迹;
- 补偿校正:根据晃动和移动的数据,EIS会对影像进行补偿和校正。它会计算出相机的位移量,并在图像处理过程中对影像进行位移和变形补偿;
- 产生稳定影像:通过补偿和校正影像,EIS可以生成更稳定的影像,减少手部晃动对影像质量的影响。
EIS效果示意图 |
3.3 调试指南¶
3.3.1 客制型号的Gyro Driver适配¶
对于Gyro Driver,公司所提供的kernel source code适配了一套通用的框架,客户可在该框架的基础上添加对应型号的陀螺仪驱动代码。
3.3.1.1 Gyro Driver Framework说明¶
|
Gyro Driver Framework示意图 |
Gyro Driver Framework的结构如上图所示,其主要分为三部分:
-
Major Stucture
整个Gyro Driver的核心部分,由如下五个文件构成:
文件 描述 备注 gyro_module.c 该文件会根据下层提供的API,在module_init和module_exit阶段,完成对必选配置(gyro_core,gyro_sensor_xxx,gyro_i2c/spi)与可选配置(ioctl chrdev和sysfs node)的初始化和反初始工作。 该文件客户不需修改 gyro_core.c 该文件为中间层,主要构建了一系列Gyro Sensor Operation API,对下层提供统一的Function Callback供其实例化,对上层提供统一的API供其对Gyro Sensor进行初始与相关硬件操作。 该文件客户不需修改 gyro_manager.c 该文件为中间层,主要统一管理transfer、sensor、device三类资源,提供宏定义的接口,在编译时确定具体需要的transfer与sensor资源,并提供API在接口drv-dev probe/remove时,将dev与sensor和transfer资源进行attach与detach。 该文件客户不需修改 gyro_control_group.c 该文件为中间层,主要管理每个device的使用者信息,包括但不限于读写权限控制、写者fifo资源供读者共享等。 - 若以写权限使用设备资源(DIS_GYRO工作模式下,默认占用),在open fd时,需配置写权限标志位,并可操作相关读写权限的ioctl,但只允许同时存在一个写者;
- 若以读权限使用设备资源,在open fd时,需配置读权限标志位,并只可操作相关读权限的ioctl,且允许同时存在多个读者的情况。
该文件客户不需修改 gyro_sensor_icg20660/icm40607.c 该文件包含各型号的具体差异化,主要体现为Register Setting。其会实现gyro_core.h中需要的Function Callback,若客户需移植其他型号的Gyro Sensor,可参考公版所使用的icg20660与icm40607两款型号的代码进行编写。 该文件客户需修改 gyro_i2c/spi.c 该文件为传输层,可根据menuconfig的配置决定使用I2C或SPI对Gyro Sensor Register进行读写操作。 该文件客户不需修改 -
ioctl chrdev
主要为user space提供ioctl interface,根据ioctl number最终调用gyro_core.c的对应API。
-
sysfs node
为公司所提供的一套简单测试Gyro Sensor的功能性代码。
3.3.1.2 Gyro Driver Ioctl接口说明¶
关于Ioctl Number的定义在kernel/drivers/sstar/include/gyro_ioctl.h中,如下是其介绍:
| Ioctl Number Macro | 功能 | 参数类型 | 参数原型说明 |
|---|---|---|---|
| GYRO_IOC_CMD_SET_SAMPLE_RATE | 设定时钟的分频,如公版使用的icg20660支持设定为500,1000Hz | gyro_arg_sample_rate_t * | typedef struct gyro_arg_sample_rate { unsigned int rate; } gyro_arg_sample_rate_t; 该结构中的rate成员为分频,单位为Hz |
| GYRO_IOC_CMD_SET_GYRO_RANGE | 设定陀螺仪传感器的量程,如公版使用的icg20660支持设定 ±125, ±250, ±500 °/sec | gyro_arg_gyro_range_t * | typedgef struct gyro_arg_gyro_range { unsigned int range; } gyro_arg_gyro_range_t; 该结构中的range成员为量程的绝对值,单位为°/sec。 |
| GYRO_IOC_CMD_SET_ACCEL_RANGE | 设定陀加速度传感器的量程,如公版使用的icg20660支持设定±2,±4,±8,±16g | gyro_arg_accel_range_t * * | typedef struct gyro_arg_accel_range { unsigned int range; } gyro_arg_accel_range_t; 该结构中的range成员为量程的绝对值,单位为g。 |
| GYRO_IOC_CMD_SET_DEV_MODE | 设定硬件的模式 | gyro_arg_dev_mode_info_t * | typedef struct gyro_arg_dev_mode { char fifo_mode; /* 1 or 0 */ unsigned char fifo_type; } gyro_arg_dev_mode_t; enum gyro_fifo_type { GYROSENSOR_ALL_ACCEL_FIFO_EN = 0x08, GYROSENSOR_ZG_FIFO_EN = 0x10, GYROSENSOR_YG_FIFO_EN = 0x20, GYROSENSOR_XG_FIFO_EN = 0x40, GYROSENSOR_TEMP_FIFO_EN = 0x80, GYROSENSOR_FIFO_MAX_EN = 0xFF, }; |
| GYRO_IOC_CMD_GET_SAMPLE_RATE | 获取时钟分频 | gyro_arg_sample_rate_t * | 参考上述描述 |
| GYRO_IOC_CMD_GET_GYRO_RANGE | 获取陀螺仪传感器的量程 | gyro_arg_gyro_range_t * | 参考上述描述 |
| GYRO_IOC_CMD_GET_GYRO_SENSITIVITY | 获取陀螺仪传感器的灵敏度 | gyro_arg_sensitivity_t * | typedef struct gyro_arg_sensitivity { unsigned short num; unsigned short den; } gyro_arg_sensitivity_t; 该参数表示陀螺仪的灵敏度,这里同时可以表示陀螺仪传感器和加速度传感器的灵敏度。 灵敏度的计算采用如下公式:sensitivity = num/den |
| GYRO_IOC_CMD_GET_ACCEL_RANGE | 获取加速度传感器的量程 | gyro_arg_accel_range_t * | 参考上述描述 |
| GYRO_IOC_CMD_GET_ACCEL_SENSITIVITY | 获取加速度传感器的灵敏度 | gyro_arg_sensitivity_t * | 参考上述描述 |
| GYRO_IOC_CMD_READ_FIFOCNT | 读取Gyro Sensor中fifo buf中有效数据的大小 | u16 * | fifo buf中有效数据的大小,单位为bytes。 |
| GYRO_IOC_CMD_READ_FIFODATA | 读取fifo数据 | gyro_fifo_data_info_t * | typedef struct gyro_fifo_data_info_s { __u8 *pfifo_data; __u16 data_cnt; } gyro_fifo_data_info_t; |
| GYRO_IOC_CMD_READ_GYRO_XYZ | 读取陀螺仪传感器信息 | gyro_arg_gyro_xyz_t * | typedef struct gyro_arg_gyro_xyz { short x; short y; short z; } gyro_arg_gyro_xyz_t; 表示陀螺仪传感器的三个轴(x,y,z)的数值 |
| GYRO_IOC_CMD_READ_ACCEL_XYZ | 读取加速度传感器信息 | gyro_arg_accel_xyz_t * | typedef struct gyro_arg_accel_xyz { short x; short y; short z; } gyro_arg_accel_xyz_t; 表示加速度传感器的三个轴(x,y,z)的数值 |
| GYRO_IOC_CMD_READ_TEMP | 读取温度信息 | gyro_arg_temp_t * | typedef struct gyro_arg_temp { short temp; }gyro_arg_temp_t; 表示温度传感器的值,单位为degC。 |
| GYRO_IOC_CMD_WHOAMI_VERIFY | 校验SPI通讯是否正常 | void *(不需要传) | 目前的实现上,不需要传入该参数 |
| GYRO_IOC_CMD_RESET_FIFO | 复位fifo寄存器 | void *(不需要传) | 目前的实现上,不需要传入该参数 |
| GYRO_IOC_CMD_GET_GROUP_DELAY | 读取群延迟信息,该值需查阅具体型号的陀螺仪数据手册得知 | gyro_arg_group_delay_t * | typedef struct gyro_arg_group_delay { unsigned int delay_us; }gyro_arg_group_delay_t; 表示群延迟的值,注意单位为us |
| GYRO_IOC_CMD_GET_DEV_MODE | 获取设备模式信息 | gyro_arg_dev_mode_info_t * | typedef struct gyro_arg_dev_mode { char fifo_mode; /* 1 or 0 */ unsigned char fifo_type; } gyro_arg_dev_mode_t; enum gyro_fifo_type { GYROSENSOR_ALL_ACCEL_FIFO_EN = 0x08, GYROSENSOR_ZG_FIFO_EN = 0x10, GYROSENSOR_YG_FIFO_EN = 0x20, GYROSENSOR_XG_FIFO_EN = 0x40, GYROSENSOR_TEMP_FIFO_EN = 0x80, GYROSENSOR_FIFO_MAX_EN = 0xFF, }; |
3.3.1.3 Gyro Sensor 移植说明¶
根据章节《3.3.1.1 Gyro Driver Framework说明》的章节介绍,客户只需要根据使用的Gyro Sensor,参考gyro_sensor_icg20660/icm40607.c作为范例,构建对应的驱动文件gyro_sensor_xxxx.c,将该驱动文件适配到kernel/drivers/sstar/gyro/Kconfig的编译结构,并在对应的dts文件中添加对应的节点(可仿照已添加的gyro节点)。
对于移植gyro_sensor_xxx.c文件,需要做如下两件事情:
- 实例化该gyro的gyro_sensor_context_t结构体,并实现该结构体中的struct gyro_sensor_ops callback function;
- 使用ADD_SENSOR_CONTEXT(SENSOR_TYPE, xxx_context)宏,将上述实例化的gyro_sensor_context_t结构体添加到gyro_manager.c的对应数据结构中。
如下为struct gyro_sensor_ops中Function Callback与Gyro Ioctl Number Macro的对应关系:
| Function Callback | Gyro Ioctl Number Macro | |
|---|---|---|
| int (*init)(struct gyro_dev *dev); | 无对应的Ioctl,其会在open Ioctl chrdev的fd的时被调用,主要完成的是Gyro Sensor的初始化硬件操作,如复位,使能相关配置 | |
| void (*deinit)(struct gyro_dev *dev); | 无对应的Ioctl,其会在close Ioctl chrdev的fd的时被调用,主要完成的是Gyro Sensor的断电或陷入低功耗状态硬件操作,如复位,并将其进入low power状态 | |
| int (*enable_fifo)(struct gyro_dev *dev, struct gyro_arg_dev_mode mode, struct gyro_arg_fifo_info *fifo_info); | GYRO_IOC_CMD_SET_DEV_MODE | |
| int (*set_sample_rate)(struct gyro_dev *dev, struct gyro_arg_sample_rate rate); | GYRO_IOC_CMD_SET_SAMPLE_RATE | |
| int (*get_sample_rate)(struct gyro_dev *dev, struct gyro_arg_sample_rate *rate); | GYRO_IOC_CMD_GET_SAMPLE_RATE | |
| int (*set_gyro_range)(struct gyro_dev *dev, struct gyro_arg_gyro_range range); | GYRO_IOC_CMD_SET_GYRO_RANGE | |
| int (*get_gyro_range)(struct gyro_dev *dev, struct gyro_arg_gyro_range *range); | GYRO_IOC_CMD_GET_GYRO_RANGE | |
| int (*get_gyro_sensitivity)(struct gyro_dev *dev, struct gyro_arg_sensitivity *sensitivity); | GYRO_IOC_CMD_GET_GYRO_SENSITIVITY | |
| int (*set_accel_range)(struct gyro_dev *dev, struct gyro_arg_accel_range range); | GYRO_IOC_CMD_SET_ACCEL_RANGE | |
| int (*get_accel_range)(struct gyro_dev *dev, struct gyro_arg_accel_range *range); | GYRO_IOC_CMD_GET_ACCEL_RANGE | |
| int (*get_accel_sensitivity)(struct gyro_dev *dev, struct gyro_arg_sensitivity *sensitivity); | GYRO_IOC_CMD_GET_ACCEL_SENSITIVITY | |
| int (*read_fifo_cnt)(struct gyro_dev *dev, u16 *cnt); | GYRO_IOC_CMD_READ_FIFOCNT | |
| int (*reset_fifo)(struct gyro_dev *dev); | GYRO_IOC_CMD_RESET_FIFO | |
| int (*whoami_verify)(struct gyro_dev *dev); | GYRO_IOC_CMD_WHOAMI_VERIFY | |
| int (*read_fifo_data)(struct gyro_dev *dev, u8 *data, u16 cnt); | GYRO_IOC_CMD_READ_FIFODATA | |
| int (*read_temp)(struct gyro_arg_temp *arg); | GYRO_IOC_CMD_READ_TEMP | |
| int (* early_init)(struct gyro_dev *dev); | 无对应的Ioctl,其会在module init期间被调用,主要用于提前完成与外设上电无关的操作,如内存资源的提前开辟。 注意:该回调无强制要求实例化,客户可根据自身所需实例化 |
|
| int (* final_deinit)(struct gyro_dev *dev); | 无对应的Ioctl,其会在module exit期间被调用,主要用于完成与外设下电无关的操作,如内存资源的释放。 注意:该回调无强制要求实例化,客户可根据自身所需实例化 |
|
| int (*get_group_delay)(struct gyro_dev *dev, struct gyro_arg_group_delay *delay); | GYRO_IOC_CMD_GET_GROUP_DELAY | |
| int (*get_noise_bandwidth)(struct gyro_dev *dev, struct gyro_arg_noise_bandwidth *nbw); | 注意:该回调目前为提前保留在代码中,客户不需实例化 |
如下提供了Gyro Sensor的移植伪代码,方便客户快速对接公司提供的框架:
/*
* gyro_sensor_xxxx.c- Sigmastar
*
* Copyright (c) [2019~2020] SigmaStar Technology.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*
*/
#include <linux/delay.h>
#include "gyro_core.h"
#include "gyro.h"
enum GSEN_Register_Addr_e
{
GSEN_xxxx_SELF_TEST_X_GYRO = 0x00,
GSEN_xxxx_SELF_TEST_Y_GYRO = 0x01,
GSEN_xxxx_SELF_TEST_Z_GYRO = 0x02,
GSEN_xxxx_XG_OFFS_TC_H = 0x04,
GSEN_xxxx_XG_OFFS_TC_L = 0x05,
GSEN_xxxx_YG_OFFS_TC_H = 0x06,
GSEN_xxxx_YG_OFFS_TC_L = 0x07,
GSEN_xxxx_ZG_OFFS_TC_H = 0x08,
GSEN_xxxx_ZG_OFFS_TC_L = 0x09,
GSEN_xxxx_XG_OFFS_USRH = 0x13,
GSEN_xxxx_XG_OFFS_USRL = 0x14,
GSEN_xxxx_YG_OFFS_USRH = 0x15,
GSEN_xxxx_YG_OFFS_USRL = 0x16,
GSEN_xxxx_ZG_OFFS_USRH = 0x17,
GSEN_xxxx_ZG_OFFS_USRL = 0x18,
GSEN_xxxx_SMPLRT_DIV = 0x19,
GSEN_xxxx_CONFIG = 0x1A,
GSEN_xxxx_GYRO_CONFIG = 0x1B,
GSEN_xxxx_ACCEL_CONFIG = 0x1C,
GSEN_xxxx_ACCEL_CONFIG2 = 0x1D,
GSEN_xxxx_FIFO_EN = 0x23,
GSEN_xxxx_FSYNC_INT_STATUS = 0x36,
GSEN_xxxx_INT_PIN_CFG = 0x37,
GSEN_xxxx_INT_ENABLE = 0x38,
GSEN_xxxx_INT_STATUS = 0x3A,
GSEN_xxxx_ACCEL_XOUT_H = 0x3B,
GSEN_xxxx_ACCEL_XOUT_L = 0x3C,
GSEN_xxxx_ACCEL_YOUT_H = 0x3D,
GSEN_xxxx_ACCEL_YOUT_L = 0x3E,
GSEN_xxxx_ACCEL_ZOUT_H = 0x3F,
GSEN_xxxx_ACCEL_ZOUT_L = 0x40,
GSEN_xxxx_TEMP_OUT_H = 0x41,
GSEN_xxxx_TEMP_OUT_L = 0x42,
GSEN_xxxx_GYRO_XOUT_H = 0x43,
GSEN_xxxx_GYRO_XOUT_L = 0x44,
GSEN_xxxx_GYRO_YOUT_H = 0x45,
GSEN_xxxx_GYRO_YOUT_L = 0x46,
GSEN_xxxx_GYRO_ZOUT_H = 0x47,
GSEN_xxxx_GYRO_ZOUT_L = 0x48,
GSEN_xxxx_SIGNAL_PATH_RESET = 0x68,
GSEN_xxxx_ACCEL_INTEL_CTRL = 0x69,
GSEN_xxxx_USER_CTRL = 0x6A,
GSEN_xxxx_PWR_MGMT_1 = 0x6B,
GSEN_xxxx_PWR_MGMT_2 = 0x6C,
GSEN_xxxx_FIFO_COUNTH = 0x72,
GSEN_xxxx_FIFO_COUNTL = 0x73,
GSEN_xxxx_FIFO_R_W = 0x74,
GSEN_xxxx_WHO_AM_I = 0x75,
GSEN_xxxx_XA_OFFSET_H = 0x77,
GSEN_xxxx_XA_OFFSET_L = 0x78,
GSEN_xxxx_YA_OFFSET_H = 0x7A,
GSEN_xxxx_YA_OFFSET_L = 0x7B,
GSEN_xxxx_ZA_OFFSET_H = 0x7D,
GSEN_xxxx_ZA_OFFSET_L = 0x7E
};
static int xxxx_reset_fifo(struct gyro_dev *dev);
static int xxxx_init(struct gyro_dev *dev)
{
int ret = 0;
u8 val = 0;
ret = dev->reg_ops->write_reg(dev, GSEN_xxxx_PWR_MGMT_1, 0x80);
if (ret < 0)
{
GYRO_ERR("GSEN_xxxx_PWR_MGMT_1, ret:[%d]\n", ret);
return ret;
}
/*!
* Note: Need waiting for the reset operation done
*/
msleep(10);
ret = dev->reg_ops->write_reg(dev, GSEN_xxxx_PWR_MGMT_1, 0x01);
if (ret < 0)
{
GYRO_ERR("GSEN_xxxx_PWR_MGMT_1 fail, ret:[%d]\n", ret);
return ret;
}
/* Config the gyro sensor */
return 0;
}
static void xxxx_deinit(struct gyro_dev *dev)
{
int ret = 0;
xxxx_reset_fifo(dev);
msleep(10);
// reset the gyro device
ret = dev->reg_ops->write_reg(dev, GSEN_xxxx_PWR_MGMT_1, 0x80);
if (ret < 0)
{
GYRO_ERR("GSEN_xxxx_PWR_MGMT_1, ret:[%d]\n", ret);
return;
}
/*!
* Note: Need waiting for the reset operation done
*/
msleep(10);
// gyro sleep mode
ret = dev->reg_ops->write_reg(dev, GSEN_xxxx_PWR_MGMT_1, 0x40);
if (ret < 0)
{
GYRO_ERR("GSEN_xxxx_PWR_MGMT_1 fail, ret:[%d]\n", ret);
return;
}
}
static int xxxx_enable_fifo(struct gyro_dev *dev, struct gyro_arg_dev_mode mode,
struct gyro_arg_fifo_info *fifo_info)
{
int ret = 0;
return ret;
}
static int xxxx_set_sample_rate(struct gyro_dev *dev, struct gyro_arg_sample_rate rate)
{
return dev->reg_ops->write_reg(dev, GSEN_xxxx_SMPLRT_DIV, div);
}
static int xxxx_get_sample_rate(struct gyro_dev *dev, struct gyro_arg_sample_rate *rate)
{
int ret = 0;
return ret;
}
static int xxxx_set_gyro_range(struct gyro_dev *dev, struct gyro_arg_gyro_range range)
{
return dev->reg_ops->write_reg(dev, GSEN_xxxx_GYRO_CONFIG, val);
}
static int xxxx_set_accel_range(struct gyro_dev *dev, struct gyro_arg_accel_range range)
{
return dev->reg_ops->write_reg(dev, GSEN_xxxx_ACCEL_CONFIG, val);
}
static int xxxx_get_gyro_range(struct gyro_dev *dev, struct gyro_arg_gyro_range *range)
{
int ret = 0;
return ret;
}
static int xxxx_get_gyro_sensitivity(struct gyro_dev *dev, struct gyro_arg_sensitivity *sensitivity)
{
int ret = 0;
return ret;
}
static int xxxx_get_accel_range(struct gyro_dev *dev, struct gyro_arg_accel_range *range)
{
int ret = 0;
return ret;
}
static int xxxx_get_accel_sensitivity(struct gyro_dev *dev, struct gyro_arg_sensitivity *sensitivity)
{
int ret = 0;
return ret;
}
static int xxxx_read_fifo_cnt(struct gyro_dev *dev, u16 *fifo_cnt)
{
return 0;
}
static int xxxx_read_fifo_data(struct gyro_dev *dev, u8 *fifo_data, u16 fifo_cnt)
{
return 0;
}
static int xxxx_reset_fifo(struct gyro_dev *dev)
{
return 0;
}
static int xxxx_whoami_verify(struct gyro_dev *dev)
{
int ret = 0;
return ret;
}
static int xxxx_get_group_delay(struct gyro_dev *dev, struct gyro_arg_group_delay *arg)
{
int ret = 0;
return ret;
}
gyro_sensor_context_t xxxx_context = {
.list_head =
{
.next = NULL,
.prev = NULL,
},
.ops =
{
.early_init = NULL, //客户根据自身需求决定是否实例化
.final_deinit = NULL, //客户根据自身需求决定是否实例化
.init = xxxx_init,
.deinit = xxxx_deinit,
.enable_fifo = xxxx_enable_fifo,
.set_sample_rate = xxxx_set_sample_rate,
.get_sample_rate = xxxx_get_sample_rate,
.set_gyro_range = xxxx_set_gyro_range,
.set_accel_range = xxxx_set_accel_range,
.get_gyro_range = xxxx_get_gyro_range,
.get_gyro_sensitivity = xxxx_get_gyro_sensitivity,
.get_accel_range = xxxx_get_accel_range,
.get_accel_sensitivity = xxxx_get_accel_sensitivity,
.read_fifo_data = xxxx_read_fifo_data,
.read_fifo_cnt = xxxx_read_fifo_cnt,
.reset_fifo = xxxx_reset_fifo,
.whoami_verify = xxxx_whoami_verify,
.group_delay = xxxx_get_group_delay,
.get_noise_bandwidth = NULL, //为保留接口,客户不需实例化
},
};
ADD_SENSOR_CONTEXT(SENSOR_TYPE, xxxx_context);
注意:
- 当客户使用DIS-GYRO 模式工作时,只需要实现上述要求的API,对于Gyro Sensor的具体控制流程在驱动内部已通过Ioctl的方式做好,客户只需实现相关的函数即可;
- 由于需通过Ioctl的方式进行Gyro 的控制,故在使用DIS-GYRO 模式前确认是否开启Enable gyro ioctl,确认方式如下:
$ cd kernel $ make menuconfig $ 选中 SStar Gyro Driver Support,并enable gyro ioctl,最终如下: # [*] SStar SoC platform drivers ---> # <*> SStar MSPI driver # <M> SStar Gyro Driver Support ---> # GYRO transfer choice (Use SPI) ---> # GYRO chip choice (ICG20660) ---> # [*] Enable gyro ioctl # [ ] Enable gyro sysfs # [ ] Show debug info
3.3.1.4 Gyro Sensor 外设连接¶
该章节以公版所使用硬件作为例子,介绍Gyro Sensor的硬件连接,使用到的硬件信息如下:
-
SSM000A-S01A-S EVB Board
-
SSCDB-S043B IMX317 Sensor Board ( With ICG20660 Gyro Sensor SPI Interface)
硬件连接如下图:
|
3.3.1.5 Gyro Demo 运行¶
在kernel/drivers/sstar/gyro/demo路径下,提供了一套通过ioctl控制gyro运行的sample code,具体测项有:
-
gyro range test:
- 测试逻辑:将 ±125、±250、±500、1000、2000 °/sec对应的设定值下到gyro config register中,后读出来查看是否与设定值一致;
-
accel range test:
- 测试逻辑:将±2g, ±4g, ±8g,±16g对应的设定值下到accel config register中,后读出来查看是否与设定值一致;
-
sample rate test:
- 测试逻辑:根据不同型号的传感器,配置采样率的设定,后读出来查看是否与设定值一致;
-
gyro_set_dev_mode:
- 测试逻辑:根据fifo enable register和User Control reigster设定,将fifo data读出;
客户可按照如下步骤运行demo:
cd kernel/drivers/sstar/gyro/demo/;
#声明对应平台对应的toolchain
make;
#将编译后的产物sstar_gyro_demo放置到板子上
#注意,demo会持续不断的拿fifo data,若要停止运行需输入ctrl+c
./sstar_gyro_demo -d devid #这里的devid取值为dtsi中gyro节点配置的devid,默认从0开始计数
运行如上命令后,会出现部分error的log,可按照如下步骤检查:
- 写入与读回的值是否一致;
- 对应测项的设定,该型号的gyro是否支持,若不支持,出现error log为正常现象;
3.3.1.5.1 Gyro Recorder 功能说明¶
gyro demo新增了gyro record功能,支持在DIS_GYRO工作模式下,利用该APP进行传感器fifo数据采集,核心代码实现位于kernel/drivers/sstar/gyro/gyro_record.c文件中。
-
实现简单说明:
- 以O_RDONLY模式打开gyroX(X根据实际的devid填写)设备节点,并通过select api监控底层驱动是否有数据可读取;
- 当底层驱动有数据时,select api会被唤醒时,APP通过一系列读权限的ioctl来获取设备的配置类信息以及fifo数据;
- 对于不使能传感器内部时间戳的fifo数据,目前写者会为每批次fifo data的最后一笔数据打上时间戳,读者可自行根据采样率反推出每批次数据中每笔fifo对应的时间戳;
- App会以csv格式将采集到的数据保存到指定文件夹的config.csv文件中。
-
config.csv文件格式说明,以开启陀螺仪与温度传感器为例。
IMU_DATASET_RECORD # 头信息 s8Date,1970-01-01 00:37:16.077420 # 日期信息 s8From,Sgs # 头信息 IMU_Cfg # IMU配置 eMode,240 # IMU开启的模式,使用bitmask,bit(bit0-GYROSENSOR_ZA_FIFO_EN bit1-GYROSENSOR_YA_FIFO_EN bit2-GYROSENSOR_XA_FIFO_EN bit4-GYROSENSOR_ZG_FIFO_EN bit5-GYROSENSOR_YG_FIFO_EN bit6-GYROSENSOR_XG_FIFO_EN bit7-GYROSENSOR_TEMP_FIFO_EN) GYRO_Cfg # GYRO Sensor配置 ,stRange_ + -dps,2000 # 量程,单位为±dps ,stRate_HZ,800 # 采样率,单位为Hz ,stSensitivity.num,164 # 灵敏度分子部分 ,stSensitivity.den,10 # 灵敏度分母部分 ACC_Cfg # Accel Sensor配置 ,stRange_ + -g,0 # 量程,单位为±g ,stRate_HZ,0 # 采样率,单位为Hz ,stSensitivity.num,0 # 灵敏度分子部分 ,stSensitivity.den,0 # 灵敏度分母部分 MISC_Cfg # 其他配置 ,bEnableLowPassFilter,1 # 是否开启低通滤波,1-开启,0-未开启 ,stDelay_us,2000 # 群延时,单位us FIFO_PACKET_Cfg # FIFO Data封包格式 ,gx_start,1 # 表示每笔fifo data中对应陀螺仪X轴数据的起始偏移index,每个偏移量为1 byte ,gx_end,2 # 表示每笔fifo data中对应陀螺仪X轴数据的结束偏移index,每个偏移量为1 byte ,gy_start,3 # 表示每笔fifo data中对应陀螺仪Y轴数据的起始偏移index,每个偏移量为1 byte ,gy_end,4 # 表示每笔fifo data中对应陀螺仪Y轴数据的结束偏移index,每个偏移量为1 byte ,gz_start,5 # 表示每笔fifo data中对应陀螺仪Z轴数据的起始偏移index,每个偏移量为1 byte ,gz_end,6 # 表示每笔fifo data中对应陀螺仪Z轴数据的结束偏移index,每个偏移量为1 byte ,ax_start,255 # 表示每笔fifo data中对应加速度X轴数据的起始偏移index,每个偏移量为1 byte ,ax_end,255 # 表示每笔fifo data中对应加速度X轴数据的结束偏移index,每个偏移量为1 byte ,ay_start,255 # 表示每笔fifo data中对应加速度Y轴数据的起始偏移index,每个偏移量为1 byte ,ay_end,255 # 表示每笔fifo data中对应加速度Y轴数据的结束偏移index,每个偏移量为1 byte ,az_start,255 # 表示每笔fifo data中对应加速度Z轴数据的起始偏移index,每个偏移量为1 byte ,az_end,255 # 表示每笔fifo data中对应加速度Z轴数据的结束偏移index,每个偏移量为1 byte ,temp_start,7 # 表示每笔fifo data中对应温度数据的起始偏移index,每个偏移量为1 byte ,temp_end,7 # 表示每笔fifo data中对应温度数据的结束偏移index,每个偏移量为1 byte ,bytes_pre_data,8 # 表示每笔fifo data数据的大小,单位为bytes ,is_big_endian,1 # 表示数据的大小端存储,1-大端,0-小端 ,max_fifo_cnt,2304 # 表示IMU传感器最大的fifo buffer size,单位bytes IMUMETA_Data # IMU Fifo数据值 # App打的每笔Fifo Data时间戳,GyroX轴的fifo值,GyroY轴的fifo值,GyroZ轴的fifo值,AccelX轴的fifo值,AccelY轴的fifo值,AccelZ轴的fifo值,Temp的fifo值 u64AppFifoPts,s16GyroX,s16GyroY,s16GyroZ,s16AccelX,s16AccelY,s16AccelZ,s16Temp 16222942847851986892, -2, 6, 10,,,, 12, 16222942847851988142, -2, -1, 3,,,, 11, 16222942847851989392, 0, -1, 5,,,, 13, -
运行说明:
cd kernel/drivers/sstar/gyro/demo/; #声明对应平台对应的toolchain make; #将编译后的产物sstar_gyro_demo放置到板子上 #注意,demo会持续不断的录制fifo data,若要停止运行需输入ctrl+c # devid:采集的gyro device id # output_folder:录制数据保存的文件夹目录 ./sstar_gyro_demo -r devid -f output_folder
3.3.1.6 Gyro self_check 运行¶
针对kernel mode下传感器的测试,提供了一套根据sysfs节点控制测试的方法,具体测项有:
-
gyro range test:
- 测试逻辑:将 ±125、±250、±500、1000、2000 °/sec对应的设定值下到gyro config register中,后读出来查看是否与设定值一致;
-
accel range test:
- 测试逻辑:将±2g, ±4g, ±8g,±16g对应的设定值下到accel config register中,后读出来查看是否与设定值一致;
-
sample rate test:
- 测试逻辑:根据不同型号的传感器,配置采样率的设定,后读出来查看是否与设定值一致;
-
gyro_set_dev_mode:
- 测试逻辑:根据fifo enable register和User Control reigster设定,将fifo data读出;
客户可按照如下步骤运行self_check:
#step1: 打开sysfs 编译选项,选中 SStar Gyro Driver Support,并Enable gyro sysfs
cd kernel
make menuconfig
# [*] SStar SoC platform drivers --->
# <*> SStar MSPI driver
# <M> SStar Gyro Driver Support --->
# GYRO transfer choice (Use SPI) --->
# GYRO chip choice (ICG20660) --->
# [*] Enable gyro ioctl
# [*] Enable gyro sysfs
# [ ] Show debug info
#step2:编译ko
make modules -j16;
#step3:将gyro.ko放置到板子上并insmod
insmod gyro.ko
#step4:开始测试,不同的平台,self_check节点位置可能不同,若按如下方式提示无节点,可通过命令查找:find /sys/ -name self_check
cat /sys/class/sstar/gyro0/self_check
运行如上命令后,会出现部分failed的log,可按照如下步骤检查:
- 写入与读回的值是否一致;
- 对应测项的设定,该型号的gyro是否支持,若不支持,出现failed log为正常现象;
- 执行cat /proc/kmsg或dmesg命令,查看fifo data的连续性,忽略第一次读取的数据,剩余数据一般浮动在±15为正常,如下例子:
------------------------------------------------------------------------- | gx: 40 | gy: -40 | gz: -9 | te: 40 | | gx: 42 | gy: -44 | gz: -14 | te: 42 | | gx: 36 | gy: -47 | gz: -4 | te: 36 | | gx: 34 | gy: -50 | gz: -4 | te: 34 | | gx: 36 | gy: -47 | gz: -5 | te: 36 | | gx: 30 | gy: -47 | gz: -5 | te: 30 | | gx: 28 | gy: -49 | gz: -12 | te: 28 | | gx: 36 | gy: -48 | gz: -9 | te: 36 | | gx: 36 | gy: -44 | gz: -9 | te: 36 | | gx: 44 | gy: -44 | gz: -13 | te: 44 | | gx: 46 | gy: -40 | gz: -11 | te: 46 | | gx: 46 | gy: -47 | gz: -9 | te: 46 | | gx: 44 | gy: -40 | gz: -9 | te: 44 | | gx: 36 | gy: -45 | gz: -12 | te: 36 | | gx: 36 | gy: -49 | gz: -10 | te: 36 | | gx: 38 | gy: -47 | gz: -12 | te: 38 | | gx: 34 | gy: -40 | gz: -6 | te: 34 | | gx: 40 | gy: -48 | gz: -8 | te: 40 | | gx: 40 | gy: -44 | gz: -10 | te: 40 | | gx: 34 | gy: -51 | gz: -11 | te: 34 | | gx: 34 | gy: -43 | gz: -9 | te: 34 | | gx: 40 | gy: -41 | gz: -6 | te: 40 | | gx: 38 | gy: -41 | gz: -13 | te: 38 | | gx: 40 | gy: -43 | gz: -22 | te: 40 | | gx: 36 | gy: -46 | gz: -10 | te: 36 | | gx: 28 | gy: -44 | gz: -2 | te: 28 | | gx: 42 | gy: -45 | gz: -2 | te: 42 | | gx: 44 | gy: -45 | gz: -7 | te: 44 | | gx: 36 | gy: -45 | gz: -6 | te: 36 | | gx: 30 | gy: -43 | gz: -11 | te: 30 |
3.3.2 参数设置¶
3.3.2.1 eMode¶
DIS算法模式。
| 成员名称 | 描述 |
|---|---|
| MI_LDC_DIS_GYRO | 基于陀螺仪算法的防抖模式。该模式可叠加LDC的畸变矫正功能 |
3.3.2.2 as32RotationMatrix¶
其定义陀螺仪角位与CMOS Sensor正摆之对应矩阵,必须输入正确的3x3补偿矩阵,若是输入错误,会造成DIS(MI_LDC_DIS_GYRO)补偿到错误方向。
3.3.2.2.1 设定推导说明¶
假设图像的坐标系如下:
|
Gyro外设坐标系如下(对于不同型号的Gyro,需要在对应的datasheet中确认,如下使用的为ICM-40607):
|
二者坐标系之间的转换为:图像的坐标系 = as32RotationMatrix * Gyro外设坐标系,根据上述例子,as32RotationMatrix的最终结果如下:
|
3.3.2.2.2 例子¶
|
|
|
|---|---|
Sensor正摆(陀螺仪位于红框位置,红点为陀螺仪的PIN 1位置) |
陀螺仪传感器 ICG-20660 的轴线方向和旋转极性 |
|
|
|
|
0, -1, 0, 0, 0, 1] |
|
1, 0, 0, 0, 0, -1] |
|
1, 0, 0, 0, 0, 1] |
|
0, -1, 0, 0, 0, -1] |
|
0, 1, 0, 0, 0, 1] |
|
-1, 0, 0, 0, 0, -1] |
|
-1, 0, 0, 0, 0, 1] |
|
0, 1, 0, 0, 0, -1] |
3.3.2.3 u32UserSliceNum¶
此输入参数决定LDC要切分多少水平切片进行DIS(MI_LDC_DIS_GYRO)补偿。若输出高度(由MI_LDC_SetOutputPortAttr设置)为1512,则每个水平切片由上到下为1512/6=252。在设置时需注意切片高度是否接近对齐32的数值,避免多余的CPU资源被占用。目前该值推荐设定为6,允许设定范围为[1, 12]。
3.3.2.4 u32FocalLengthX与u32FocalLengthY¶
该参数对应为X和Y轴方向上焦距设置,在输入前需将焦距换算到pixel单位。
换算公式为:u32FocalLengthX/Y(pixels) = (FocalLength(mm)/CMOS_Unit_CellSize(μm)) * 10^5,其中FocalLength与CMOS_Unit_CellSize可以在Sensor的Lensspec与datasheet中找到,如下为例子:
|
|
|
|
|
当 进行变焦场景 时,需根据镜头配置文件中不同焦段的HFOV和VFOV来计算u32FocalLengthX/Y(pixels),公式如下:
- u32FocalLengthX(pixels) = 100*(0.5*InputImageWidth(pixels))/(tan(HFOV(degree)*PI/180/2)),PI为圆周率
- u32FocalLengthY(pixels) = 100*(0.5*InputImageHeight(pixels))/(tan(VFOV(degree)*PI/180/2)),PI为圆周率
示例如下:在部分镜头配置文件中HFOV称为fov_h,VFOV称为fov_v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- NOTE: 当前级ISP模块对图像进行了rot 90/270操作时,LDC输入的W/H较与rot前会调换,此时FocalLengthX/Y也务必进行调换。
3.3.3 镜头参数配置¶
DIS-GYRO工作模式下,需要依赖前级Sensor传入镜头的nRowTime与nMinFrameLengthLine信息,故在运行前,也需要确认在sdk/driver/SensorDriver/目录下所使用镜头的配置参数是否有填写,否则会造成如下错误:
SensorInfo get failed!!! Current: u32ShutterDuration[0], u32RowTime[0], u16TotalLines[0]
除了上述两个参数外,若SensorDriver中存在该部分参数——w_x、h_y、ori_w、ori_h以及binning_mode,则也需填写正确,以保证防抖效果的正确性。填写说明如下:
- w_x:较于ori_w与ori_h区域的裁剪起始点x坐标,需居中裁剪,否则算法会报错;
- h_y:较与ori_w与ori_h区域的裁剪起始点y坐标,需居中裁剪,否则算法会报错;
-
ori_w:
- 未做binning处理时,为sensor输出最大有效分辨率(部分手册称为active full size)的宽值,如下示例中的4032;
-
做binning处理时,为sensor输出最大有效分辨率的宽值/binning倍数,若为2X2 binnning mode setting,则最终配置值为4032/2=2016。
-
ori_h:
- 未做binning处理时,为sensor输出最大有效分辨率(部分手册称为active full size)的高值,如下示例中的3024;
-
做binning处理时,为sensor输出最大有效分辨率的高值/binning倍数,若为2X2 binnning mode setting,则最终配置值为3024/2=1512。
-
binning_mode:按对应的binning mode配置即可。
3.3.4 叠加畸变矫正功能说明¶
该模式的使用需要合理使能 MI_LDC_WORKMODE_DIS_LDC 模式,以及需提供正确的镜头校准参数,可参考如下文档索引说明:
- 使能 MI_LDC_WORKMODE_DIS_LDC 模式:该模式的开启在API的调用顺序上有要求,请查看MI LDC API说明;
- 镜头校准参数:需先对镜头进行标定,请参考标定工具使用文档《SigmaStar_Camera_Calibration_User_Guide》,可从 SourceCode/project/tools/cvtool/doc 获得。
4. DIS-CUST 工作模式¶
4.1 基本概念¶
该防抖模式为客户客制化算法模式,实际调用的是客户注册的回调函数。
4.2 基本原理¶
客户需通过MI_LDC_SetChnDISAttr接口注册用户态回调函数,在调用该函数时,驱动内部会提供输入参数MI_LDC_IsMatrixInParam_t给算法帮助计算防抖矩阵。该计算出的防抖矩阵需用户填写到输出参数MI_LDC_IsMatrixInParam_t中,考虑到客户计算出的矩阵带有浮点数的情况,故需要按如下步骤做归一化和定点化。
4.3 调试指南¶
4.3.1 客制型号的Gyro Driver适配¶
在使用该模式时,客户可能也需要利用gyro传感器来进行防抖矩阵的计算,具体移植步骤可参考客制型号的Gyro Driver适配。
4.3.2 参数设置¶
4.3.2.1 eMode¶
DIS算法模式。
| 成员名称 | 描述 |
|---|---|
| MI_LDC_DIS_CUST | 基于客制化算法的防抖模式 |
4.3.2.2 pCalIsMatrixCb¶
客制化回调函数。
类型定义为:typedef MI_S32 (*MI_LDC_CalIsMatrixCb_t)(const MI_LDC_IsMatrixInParam_t * const pstInParam, MI_LDC_IsMatrixOutParam_t * const pstOutParam);
其中pstInParam对于用户而言只读,不需要填写。pstOutParam结构体变量中的as32Matrix数组,需要做归一化与定点化的流程,参考如下步骤。
4.3.2.3 MI_LDC_IsMatrixOutParam_t中as32Matrix数组元素的归一化与定点化的流程¶
该矩阵为客户计算出来的数学矩阵,可利用该矩阵完成对于图像的平面几何变换,生成输出图像。
常见的平面几何变换类型有:平移变换、旋转变换、剪切(错切)变换、缩放变换、透视变换。每种变换均可进行相互叠加使用。叠加的过程就是矩阵点乘。
刚性变换:平移变换、旋转变换
线性变换:缩放变换、剪切(错切)变换、旋转变换
仿射变换:线性变换、刚性变换
投影变换:仿射变换、透视变换
4.3.2.3.1 矩阵使用说明¶
该矩阵 (m33) 描述的是从输出坐标到输入坐标的映射关系。矩阵中各项与投影变换的对应关系如下所示。 不同的投影变换之间,项的数值会相互影响,所以一般都需要通过工具计算得到变换矩阵, 只有简单的单一变换可通过手动调整来实现。
|
|
矩阵的计算方法如下:
矩阵的计算按照需求可分为如下几种类型,注意这里提供的矩阵模板是从输入图到输出图(xy->uv)的映射,根据此模板直接计算出来的结果需要求其逆矩阵(uv->xy),方可作为API的m33~origin的值。
-
平移矩阵模板: 沿着原点向右平移Δy(右为正向),向下平移Δy(下为正向)。
-
旋转矩阵模板:围绕原点(输入图左上角)逆时针旋转θ度。
-
缩放矩阵模板:将图像横向缩放Scalex倍、纵向缩放Scaley倍(可实现镜像、翻转效果)。
-
剪切矩阵模板:将图像沿着横轴倾斜α度,沿着纵轴倾斜β度。
-
透视矩阵需要通过目标平面的四个点和在当前图像中的坐标,求出变换矩阵。
m33_origin矩阵(uv->xy)的使用需要经过量化和定点化两个步骤,操作如下: 1.量化: 其中m_8为量化因子,求出初始的M33后需要每个项除以m_8得出量化后的M33'。
<table class="padding_table" width="90%">
<tr>
<td>
<img src="mymedia/IS_user_guide/Formula/formula_m33_quantify.svg">
</td>
</tr>
</table>
2.定点化: 为了符合具体算法的要求,需要将每个m33进行定点化,将其统一转化为如下精度的定点数进行表示,定点化规则如下,将每项乘对应的元素。
|
|
4.3.2.3.2 单一变换示例¶
输入图像800x800 |
|
| 平移变换 | |
|---|---|
|
向右平移200pixel,向下平移100pixel
Origin m33 (uv->xy): [1,0,-200,0,1,-100,0,0,1] as32Matrix: [16384, 0, -1600, 0, 16384, -800, 0, 0, 1] |
|
| 旋转变换 | |
|
围绕原点逆时针旋转10°
Origin m33 (uv->xy): [0.984808,-0.173648,0,0.173648,0.984808,0,0,0,1] as32Matrix: [16135, -2845, 0, 2845, 16135, 0, 0, 0, 1] |
|
| 缩放变换 | |
|
横轴缩小为原来的0.5,纵轴扩大为原来的1.5
Origin m33 (uv->xy): [2,0,0,0,0.666667,0,0,0,1] as32Matrix: [32768, 0, 0, 0, 10922, 0, 0, 0, 1] |
|
| 剪切(错切)变换 | |
|
横轴方向剪切(错切)15°,纵轴方向剪切(错切)5°
Origin m33 (uv->xy): [1.024005,-0.274381,0,-0.089589,1.024005,0,0,0,1] as32Matrix: [16777, -4495, 0, -1467, 16777, 0, 0, 0, 1] |
|