基于Hi3519AV100 AF的研究与实现
我们将基于Hi3519AV100 SDK包 已有sample_ist 模块二次实现AF 功能。使用被动式对焦,被动式自动对焦一般是通过分析图像特征得出图像清晰度值 FV(Focus Value), 通过驱动对焦马达调节焦点到最佳位置。
1.AF 模块框架
hi_sample_ist 模块的使用
sample_ist 本质是一个标准 LINUK内核模块(MODULE),编译后生成.ko文件。
.ko是kernel object文件(内核模块),该文件的意义就是把内核的一些功能移动到内核外边, 需要的时候插入内核,不需要时卸载。
在Hi3519AV100 系统之中,可以使用标准模块插入命令:
insmod extdrv/hi_sample_ist.ko
删除命令:
rmmod extdrv/hi_sample_ist.ko
该模块使用前需要确保 ISP 驱动已加载。
可以在load3519av100 文件按中直接添加
AF 同步回调
当一帧图像最后一个 pixel 通过 AF 模块后,统计值即更新,如果用户使用的是 LINUX 系统,因为 user space 任务调度不能保证一致的实时性,建议将需要保证实时性的驱动配置放在 kernel space 完成。ISP 提供同步回调接口的注册,可以实现与 VD 同步。在本章有相应的接口使用描述,用户可以将实时性要求较高的任务放在同步回调里面,底层提供 HwIRQ,Workqueue 两种方式实现,可以选择相应的实现方式以确定实时级别。HiwIRQ 是指任务放在中断服务中实现,实时性最高;Workqueue 的实时性取决于 linux 系统调用。
所以将在模块初始化的时刻,向ISP 进行同步回调函数的注册。
hi_sample_ist 模块的初始化
//定义同步回调节点信息。
ISP_SYNC_TASK_NODE_S syncNode[MAX_TEST_NODES] =
{
{
.enMethod = ISP_SYNC_TSK_METHOD_HW_IRQ,
.pfnIspSyncTskCallBack = sync_af_calc,
.u64Data = 0,
.pstFocusStat = &stFocusStat,
.pszId = "hw_0"
},
{
.enMethod = ISP_SYNC_TSK_METHOD_HW_IRQ,
.pfnIspSyncTskCallBack = sync_call_back,
.u64Data = 1,
.pstFocusStat = NULL,
.pszId = "hw_1"
},
{
.enMethod = ISP_SYNC_TSK_METHOD_WORKQUE,
.pfnIspSyncTskCallBack = sync_call_back,
.u64Data = 3,
.pstFocusStat = NULL,
.pszId = "wq_0"
},
{
.enMethod = ISP_SYNC_TSK_METHOD_WORKQUE,
.pfnIspSyncTskCallBack = sync_call_back,
.u64Data = 4,
.pstFocusStat = NULL,
.pszId = "wq_1"
}
};
//sample_ist 模块初始化
static int __init sample_ist_init(void)
{
int i, ret;
ret = misc_register(&sample_ist_dev);
if (ret != 0)
{
printk("register sample_ist device failed with %#x!\n", ret);
return -1;
}
for (i = 0; i < MAX_TEST_NODES; i++)
{
//hi_isp_sync_task_register(0, &syncNode[i]);向 ISP 注册同步回调接口。
if (CKFN_ISP_RegisterSyncTask())
{
CALL_ISP_RegisterSyncTask(ViPipe, &syncNode[i]);//向 ISP 注册同步回调接口。
printk("register sample_ist device %#x!\n", i);
}
}
//init af pos
return 0;
}
sample_ist 模块向ISP 注册同步回调函数后,ISP 同步任务调度(ISP Synchronize Task Schedule)将会向注册时定义的函数接口进行回调。
2.FV 值计算
被动式自动对焦一般是通过分析图像特征得出图像清晰度值 FV(Focus Value), 通过驱动对焦马达调节焦点到最佳位置,如图 13-4 所示,图像越清晰 FV 值越大,Peak 点对应聚焦清晰点。获取图像清晰度算法有多种,如灰度梯度法,高频分量法等,本文采用高频分量法来计算 FV,即图像越清晰的时候高频部分幅值越大,将图像通过高通滤波器便可以得到高频分量,一共提供四个滤波器和亮度信息,分别为水平方向滤波 H1,H2,垂直方向滤波 V1,V2,以及 Y 和高亮计数器 HlCnt。
Hi3519AV100 最大支持 17*15 个blocks的AF统计值的计算。
FV1 使用在低照度场合,FV2 使用在正常照度场合。
对于每一个 block,FV1,FV2 的计算方式为:FV 的计算方式为:
FV1_n = α ∗ H1_n+(1 − α) ∗ V1_n
FV2_n = β ∗ H2_n+(1 − β) ∗ V2_n
u32Fv1_n = (u32H1 * ALPHA + u32V1 * ((1 << BLEND_SHIFT) - ALPHA)) >> BLEND_SHIFT;
u32Fv2_n = (u32H2 * BELTA + u32V2 * ((1 << BLEND_SHIFT) - BELTA)) >> BLEND_SHIFT;
H1,H2,V1,V2 分别为水平垂直四组滤波器的统计值,可设置适当的权重对水平和垂直方向的滤波器输出统计值进行混合。
最中FV的值还需要对每个block 进行加权。
static int AFWeight[15][17] = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
};
HI_S32 sync_af_calc(HI_U64 u64Data)
{
u32SumFv1 += AFWeight[i][j] * u32Fv1_n;
u32SumFv2 += AFWeight[i][j] * u32Fv2_n;
u32WgtSum += AFWeight[i][j];
}
3.AF 控制策略
我们使用被动式对焦,所以我们需要通过马达进行一步一步的尝试,从而确定图像最清晰的位置。
3.1 基于matlab的AF仿真
我们可以使用matlab对 AF马达做一个 爬坡的算法初步验证。
大概流程:
1.首先 生成一个正太分布,用来模拟山峰;
2.随机 产生一个起始点(0 号点)
3.以默认的一个step向左移动
4.如果上两个点的 高度差>0 ,则被认为是上升趋势,则下个点不改变方向;若高度差<0,则下个点改变方向。
if(cur_k > 0)
dir = -dir;
5.如果发现:本次高度差<0,上一次的高度差>0,则判断找到山峰。
if(cur_k > 0)
dir = -dir;
if ((last_k < 0)) %find 峰值
6.找到峰值后将step/10,改变方向,这时候需要将初始值设为 峰值+step。
dir = -dir;
next_pos_x = last_pos_x - step*dir;
通过上述找山峰的方法,一次一次的逼近峰值,最终到达峰值。
以上Matlab 验证无问题后,直接移植至 之前说的hi_sample_ist 模块。
4.AF 驱动
该模组的驱动实现较为简单,控制马达的是通过I2C 写寄存器的方式。
其主要难度,是需要在该模块中 调用到I2C 的驱动,查看手册,实现内核中的I2C 驱动实现。
static int __init sample_ist_init(void)
{
int x = 0;
struct i2c_adapter *i2c_adap;
for (x = 0; x < I2C_MAX_NUM; x++)
{
i2c_adap = i2c_get_adapter(x);
sensor_client[x] = i2c_new_device(i2c_adap, &hi_info);
i2c_put_adapter(i2c_adap);
}
......
}
5.Matlab 源码
x=0:1:1023;
y1=10000*normpdf(x,512,200);
hold on;
plot(x,y1,'g');
% x2 = randi(1023);
init_x = randi(1023)
% init_x = 246;
init_y = 10000*normpdf(init_x,512,200)
scatter(init_x,init_y,'r');
step = 100;
dir = 1;
limit=1;
last_pos_x = init_x;
last_pos_y = init_y;
last_k=0;
flag_findH = 0;
cur_pos_x = last_pos_x - dir*step;
for i=1:10
cur_pos_y = 10000*normpdf(cur_pos_x,512,200);
scatter(cur_pos_x,cur_pos_y,'k');
text(cur_pos_x,cur_pos_y+1,num2cell(i));
plot([last_pos_x,cur_pos_x],[last_pos_y,cur_pos_y],'r');
cur_k = (last_pos_y-cur_pos_y);
if(cur_k > 0)
dir = -dir;
if ((last_k < 0)) %find итох
step = step/10;
% cur_pos_x = last_pos_x;
dir = -dir;
next_pos_x = last_pos_x - step*dir;
cur_pos_x = next_pos_x;
last_k = cur_k;
% cur_pos_x = last_pos_x + 10;
continue;
end;
end;
next_pos_x = cur_pos_x - step*dir;
next_pos_y = -1;
last_pos_x = cur_pos_x;
last_pos_y = cur_pos_y;
cur_pos_x = next_pos_x;
% cur_pos_y = next_pos_y;%-1
last_k = cur_k;
end
plot([last_pos_x,last_pos_x],[last_pos_y,0],'b');
Matlab 源码:
https://download.csdn.net/download/weixin_42190974/15577064
Hi359AV100 源码:
https://download.csdn.net/download/weixin_42190974/15577064