端侧AWB算法落地细节学习

AWB主流程

完整做了窗口配置、默认参数、Golden/Calibration 初始化和内存准备
是标准落地链路:参数更新检查 → 统计数据接入 → 环境量(LV/ISO/BVstep)更新 → AWB_RunAlgo → 结果回填
参数热更新不是“变量改一下”,而是共享缓冲标志位驱动(Attr/AttrEx/Calib)

核心算法能力

统计输入为分区 R/G/B 均值,支持线性与WDR双帧(LE/SE)数据切换:
样本筛选是“曲线+边界+多规则”体系:CT曲线区间、LV/ISO边界、额外光源、天空过滤、人脸区域剔除、位置权重、亮度直方图权重
估计器是多路并行并融合:低成本灰点、CT-bin主峰/次峰、多光源户外bin、wide域、SE估计,最后得到 stFinalWB:
抗干扰是“实算法”不是开关:双峰场景下做干扰色/肤色簇检测并降权
收敛控制含快/慢双模式、速度比例、稳定场景降速、每帧步进限幅、RunInterval平滑补偿:

标定,色温与输出联动

标定支持新旧两套曲线建模(含二次/线性退化路径),并构建 CT↔R/B 查表
输出阶段支持 Auto/Manual/Bypass 三态,且真实写入 au32WhiteBalanceGain、u32ColorTemp、bStable、u8Saturation[]
多光源场景下有 CA/CCM 饱和度联动调节(含WDR与线性分支)opencleaesdsdasa xxfdffdfsadsadsadsadsadsadsadsadsadsadsadsd xc sdasdasfdfadsadsadsadsad

端侧AE算法落地细节学习

基础架构

所有代码来源于aealgo.c/.h,通过接口得知,他不仅有init/run/ctrl/exit,还覆盖了路线表、WDR、统计配置、平滑、Iris/DCIris、RawReplay、AEB、仿真、人脸联动等能力.

主流程框架

顺序是 参数更新检查 → 统计采集 → 防闪烁检测 → 条件早退/平滑输出 → 跑核心算法 → 下发曝光 → 写回结果。

其中,核心决策代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void AE_RunAlgo(CVI_U8 sID)
{
#if CHECK_AE_SIM
AE_HLprintf("RUN____AE\n");
#endif
sID = AE_CheckSensorID(sID);

if (AeInfo[sID].stStitchAttr.enable && !AeInfo[sID].stStitchAttr.bMainPipe &&
pstAeExposureAttrInfo[sID]->enOpType != OP_TYPE_MANUAL) {
CVI_U8 mainID = AE_SENSOR_NUM, i;

for (i = 0; i < AE_SENSOR_NUM; i++) {
if (AeInfo[i].stStitchAttr.bMainPipe &&
AeInfo[i].stStitchAttr.u8Group == AeInfo[sID].stStitchAttr.u8Group) {
mainID = i;
break;
}
}

if (mainID != AE_SENSOR_NUM) {
memcpy(AeInfo[sID].stExp, AeInfo[mainID].stExp, sizeof(AE_EXPOSURE) * AE_MAX_WDR_FRAME_NUM);
AE_UpdateFps(sID, AeInfo[sID].stExp[AE_LE].u32ExpTime);
return;
}
}
AE_CalculateFrameLuma(sID);
AE_AdjustTargetY(sID);
AE_CalculateBvStep(sID);
AE_CalFaceDetectLuma(sID);
AE_CalFaceDetectBvStep(sID);
AE_CalculateSmoothBvStep(sID);
AE_CalCurrentLvX100(sID);
if (AE_IsDCIris(sID)) {
AE_RunDCIris(sID, pstAeExposureAttrInfo[sID]->enOpType);
}

if (pstAeExposureAttrInfo[sID]->enOpType != OP_TYPE_MANUAL) {
if (!AE_IsUseDcIris(sID)) {
AE_CalculateConverge(sID);
AE_ConfigExposureRoute(sID);
if (AeInfo[sID].bEnableSmoothAE && !AeInfo[sID].bMeterEveryFrame)
AE_ConfigSmoothExposure(sID);
AE_ConfigExposure(sID);
}
}
AE_UpdateFps(sID, AeInfo[sID].stExp[AE_LE].u32ExpTime);
}

可落地能力

统计输入能力:读取 AE zone RGB 与直方图,计算中心亮度、全局亮度、亮四分位亮度,支持 LE/SE 双帧统计
目标亮度与误差控制:基于补偿、LV分段、WDR目标区间动态计算 target range,并将亮度误差转 BV step
收敛策略能力:支持快收敛/常规收敛、黑白延迟帧、高ISO策略、稳定判定、过冲细调,属于完整的工程化收敛器,不是单一 PID
曝光路由能力:支持 Route 与 RouteEx 两种模式(时间+总增益 / 时间+AG+DG+ISPDG),并在运行时做限幅、去重、慢快门插点
平滑曝光能力:支持 meter 周期内插值的平滑 APEX 序列,非 meter 帧也可取平滑点输出,降低闪烁感
WDR能力:支持 LE/SE 双通道主从曝光、曝光比上下限、SE时间约束、同增益/分增益模式,且结果回填 ExpRatio
防闪烁能力:有独立 flicker 检测模块,按 25/30fps 和特定快门档位做垂直亮度序列判定
Face/Smart AE能力:支持人脸区域权重融合与 SmartExposure 限制(最小/最大曝光系数、间隔等)
Iris/DCIris能力:支持 Iris 与 DC Iris 参数更新、PWM 初始化与 PID 控制(位置/增量/积分模式),并可自动启停
手动曝光能力:支持 OP_TYPE_MANUAL,手动时间/增益控制仍走全套限幅与配置流程
AEB能力:支持 Bracketing 启动、按 EV 设置、按索引设置与结束恢复
RawReplay/仿真能力:有 RAW replay、AE 仿真模式入口与日志机制,便于离线调试与回放

硬件落地细节

真正下发 sensor again/dgain table 映射、积分时间更新、增益更新、WDR比值约束、sensor真实值回填、ISPDGain补偿、调试保护流程
结果输出包含 ISO、Luma、HistError、稳定标志、WDR短帧信息、路由回传、DCF字段。

实现边界及注意点

flicker 检测对帧率和快门档位有硬条件,非 25/30 或非指定档位会直接不判定
aeCtrl 目前几乎无实质控制分支,扩展命令能力偏弱
能力虽全,但高度依赖 sensor 回调质量(fps_set/inttime_update/gains_update/calc_table)。

PDAF开发记录

开局更正一点问题,首先有关pdaf的文件一共有六个,分别是pdaf_cpu的c和h,用来进行pdaf需要的计算和拟合,afalgo的c和h,存储pdaf个cdaf的逻辑和算法及raw图的抓取,同时还有cvi_af的对外接口封装

待测相机处理芯片为OV48B2Q.基于微透镜进行相位检测,跟刚开始考虑的遮蔽根本不一样 他是22 ml_pdaf:

2×2:指的是该相位检测的最小单元是2 行 ×2 列的像素组:这 4 个相邻的同色像素(适配 OV48B 的 4-cell Quad Bayer 滤色片架构)共享一个大尺寸的微透镜,光线通过这个微透镜后,会在 4 个子像素上形成不同的入射角度分布。

同时0.8微米且支持全方向相位检测 Quad Bayer(也叫四拜尔 / 4-cell)把这个单元放大了 4 倍,它的最小单元是4×4 像素块,里面每 2×2 的区域是同一种颜色,结构如下:

其中pdaf_cpu负责给出亚像素的值,afalgo则是状态机,决定什么时候进入各种不同状态

gainmap的获取: 投射式灯箱给出平行光源,摄像头贴近拍照,获取gainmap

dcc的获取:D50光源照射,相位差理论上标定的时候是左边大到左右相等到右边大,完整出来应该是个线性

2026.3.16完整记录

根据舜宇光学的参考文档,重新设置环境进行标定

gainmap标定: 背照光源,色温5000K,亮度750-900lx,镜头距离光源1cm,拍摄图像,获取标定结果为:

dcc标定:光源d50,亮度拉到最大,镜头与标定面平行,距离一张a4纸,拍摄170-230距离的值,间隔5

通过SAD计算相位差, 此时生成dcc同时生成可视的dac-pd图

以及dcc_slope图

单就这两张图来看,计算结果还算合理,同时通过他的广泛范围推测,应当把范围限定在中间190-210的范围,这一段具有比较明显的线性,斜率变化不大

采图的时候电机位置记得先放置0,不然会乱跑

在端侧计算相位差是时,出来的结果还是不对,就像定死了一样卡在了-0.529

问题在于目前的在线相位计算与离线相位计算的方法不一致,我需要先把他们的计算相位逻辑改成完全一致,然后再进行相位计算尝试

在修正中认识到一个问题:理论上来说,在相同显示距离的时候,不同的物体在不同的镜头变焦计算出的像素位移计算结果应当是相同的,同时同一个物体在不同位置计算的像素位移,应当在准确对焦的附近得到的值趋近0,而非在所有的距离算出来的相位差是固定的

D50光源下相位差测试结果(gainmap始终保持不变,dcc也用的是相同的)

这是距离30公分的标定板计算出来的dac及相位差的关系

10cm的相位差计算完全乱了,不过这个是真实物体的	



尝试使用dcc标定图在10cm重新计算一次	

考虑为什么在相同的gainmap下,当物体不同的时候,检测结果也不一样

在保持gainmap和dcc标定的内容,对不同距离的不同物体进行了像素位移与dac关系的计算,得到的结果如下:

正常光源下相位差测试结果(gainmap始终保持不变,dcc也用的是相同的)

有意思的来了,gainmap标定目前来看完全没毛病.就算在自然光照射条件下,相位差计算也是合理的数值	

我同时应该试试10cm距离,重新尝试下

在距离非常近的情况下,计算的结果不同,就目前测试,就算使用dcc标定,出来的相位差也不对

在距离较远,获取到的图像内容更丰富的情况下,算出来的结果也是非常完美的线性,在210位置确实也是比较好的对焦程度	

此处注意到一个问题,虽然说具有比较好的线性,但是应当在计算相同距离的同时出来的相位差是一致的,因此接下来尝试做一组实验,在相同距离下,固定相机位置不懂,分别使用dcc标定线条,对焦测试卡及随机实际物体(饮料瓶,金毛雕像)进行测试,查看计算出的相位结果是否合理,理论上应该是完全相同的

测试间距为35mm,测试板使用了亚克力板进行了安装,可能存在反光的问题

line_35mm

首先,计算结果还算能认可

其次,明显-1.1的亚像素计算在170-210

范围内有点超过限制,后续扩大相位计算,

明显要往大放

human_35mm

相位差明显不对,计算出来的结果

应当在中间的时候不会有这么多趋近0

的地方,但是现在所有的数据都存在boundary_hit

比例较高的情况

dog_35mm

面对毛发的测量直接就寄,根本没法用	

KP就变成了:能否通过算法解决sad计算不准确的问题? 目前来看在像素位移为0的区域, 出现的结果计算都是不正确的, 更不用说毛发这类难对焦的结果了

更新,目前最大的问题是根本没有办法解决计算相位差不准的问题,他也不让我修改任何关于有关相位获取的代码,那我就直接设置强调节出个demo就行,反正他也没需求,就目前来看也没有让我开发需求的必要,

对齐后发现我刚开始想做的就是他后面要做的多段对焦,所以结果出不来,主要是因为他也不支持多端对焦的功能,目前就是两段对焦,对焦结果如下: 

首先解决置信度问题,可靠场景下,confidence 由 SAD可靠度 + 边缘 + 方差加权得到,随后再做 ISO补偿,非可靠场景下,走衰减模型:confidence = 0.5 * decay_factor * iso_factor

尝试了限定阈值,然后给联想之前的回滞操作.给出了一份三段的代码,效果还可以

之后尝试五段LUT,效果一般,暂时不太知道怎么改

 

09-20-2025

1️⃣ 归一化 (Normalization)

👉 目的是 调整数据的分布,让训练更稳定。

数据层面的归一化

比如把输入像素缩放到 [0,1] 或标准化为均值 0、方差 1。

例子:transforms.Normalize((0.5,), (0.5,))。

层内的归一化

在网络内部,像 BN、LayerNorm、GroupNorm。

这些操作会对特征图的均值/方差做规范化。

📌 关键点:归一化不改变模型容量,只是让训练更快、更稳定。

2️⃣ 正则化 (Regularization)

👉 目的是 限制模型的复杂度,减少过拟合。

常见方法:

权重惩罚:L1/L2 正则化(在 loss 里加二范数

随机丢弃:Dropout

数据增强:随机翻转、裁剪

早停 (Early stopping)

📌 关键点:正则化是通过“约束”让模型不要过于拟合训练集,从而泛化更好。

09-06-2025

how to get the variable length string in C?

here is one of the solution


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include <stdlib.h>

char *get_string(){
int length = 0, capacity = 0;
int ch;
char *str = NULL;

while((ch = getchar()) != '\n' && ch != EOF){
if(length+1 > capacity){
capacity = (capacity == 0) ? 16 : capacity * 2;
char *temp = realloc(str, capacity);
if(temp == NULL){
free(str);
return NULL;
}
str = temp;
}
str[length++] = (char) ch;
}
if(str != NULL){
str[length] = '\0';
}
else{
str = calloc(1,sizeof(char));
if(str == NULL) return NULL;
}
return str;
}

07-22-2025

埃氏筛


高效筛选出某个范围内所有质数 的经典算法

思路:假设我们想找出 2 ~ N 之间的所有质数:

  1. 先假设 2~N 都是质数。

  2. 从 2 开始,把它的所有倍数(2×2, 2×3, 2×4…)都标记为合数。

  3. 再找到下一个未被标记的数(一定是质数),然后把它的所有倍数标记为合数。

  4. 不断重复,直到处理到 √N 为止。

  5. 剩下所有未被标记的数就是质数。


C代码

1
2
3
4
5
6
7
8
9
10
11
// 初始化
for (int i = 2; i <= n; i++) isPrime[i] = true;

// 埃氏筛
for (int i = 2; i * i <= n; i++) {
if (isPrime[i]) {
for (int j = i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}

从小到大,遇到质数就划掉他的倍数


we gt introduce the vise of eula

compared with vise of esteranis, this vise would’t get any re-count if its not prime, let start


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
C form

#include <stdbool.h>
#include <stdlib.h>

void vise_of_eula(int num){
if(num < 2){
obviously, no prime
}
bool *is_composite = (bool*) calloc(num+1, sizeof(bool));
int *Primes = (int*) malloc((num+1) * sizeof(int)),cnt = 0;
for(int i = 2; i <= num; i++){
if(!is_composite){
Primes[cnt++] = i;
}
for(int j = 0; j < cn && i * Primes[j] <= num; j++){
is_composite[i * Primse[j]] = true;
if(i % Primse[j] == 0) break;
}

}
free(is_composite);
int *final_Prime = realloc(Primes, cnt*sizeof(int));
free(Primes);
}

07/15/2025

一道小学入门题,从余数相同问题引出函数递归,并延伸到质因数分解


题目描述

已知三个正整数 $a$,$b$,$c$。现有一个大于 $1$ 的整数 $x$,将其作为除数分别除 $a$,$b$,$c$,得到的余数相同。

请问满足上述条件的 $x$ 的最小值是多少?数据保证 $x$ 有解。

输入格式

一行,三个不大于 $1000000$ 的正整数 $a$,$b$,$c$,两个整数之间用一个空格隔开。

输出格式

一个整数,即满足条件的 $x$ 的最小值。

输入输出样例

输入
1
300 262 205
输出
1
19

一道入门问题,只为了完成该任务直接选择无脑循环即可,但是从题目给出的数学角度出发,可以引入辗转相除法:

1
int gcd(int a, int b){return b == 0 ? a : gcd(b, a % b);}

三元运算符节省空间,函数调用步进提供最大公约数,三个多个都一样,套娃就ok。但是他题目要求的是大于1的最小的公约数,这里就牵扯到了质因数分解,因为所有公约数都蕴含在最大公约数里,考虑设计方法求出所有质因数:设计循环,从2开始,每一个数都除干净,

1
2
循环上限为 <= sqrt(n) 的所有质数,因为如果a <= b, a * b = n; 那么 a * a <= a * b = n;
同时b也可以做质因数分解,因此只需要考虑上限内的质数,如果都不满足,那么该数就是质数。

用上述方法我们就将公倍数质因数分解成功,并从中找到了最小的非1公倍数!

Embedded_Software

此文档主要记录本人在软件学习方面遇到的问题及技术总结

文章结构根据学习路线进行逐级更新,在学习与工作中存在问题也会同步更新,学习路线如下:

1.


1.建立计算机系统基础【 1-2个月 】

《深入理解计算机系统》 && 《C Primer Plus》
刷题

  • 洛谷:入门难度500题

2.数据结构与算法 【 2-4个月 】

《数据结构、算法与应用》 && 《C++ Primer》
可选补充《算法导论》
刷题

第一阶段

  • LeetCode:Easy难度
    • 数组:两数之和(1)、移除元素(27)
    • 链表:反转链表(206)、合并两个有序链表(21)
    • 字符串:验证回文串(125)、字符串转整数(8)
  • Codeforces:Div.4或Div.3的A/B题
    • 侧重输入输出和简单逻辑。

第二阶段

刷题建议

  • LeetCode:Easy-Medium难度
    • 树:二叉遍历(94/144/145)、对称二叉树(101)
    • 图:岛屿数量(200)、课程表(207)
    • 排序:合并区间(56)、前K个高频元素(347)
  • Codeforces:Div.3的C/D题
    • 练习贪心、简单动态规划(如背包问题)。

3.操作系统与Linux内核

《Linux内核完全剖析》 && 《Linux内核完全注释》
配合阅读:《计算机网络》
刷题建议

  • LeetCode:Medium-Hard难度
    • 动态规划:零钱兑换(322)、编辑
      距离(72)
    • 系统设计:LRU缓存(146)、实现
      Trie(208)
  • Codeforces:Div.2的D/E题
    • 练习高级数据结构(线段树、并查
      集)和数学思维。

4.高级应用与优化

《C++Primer》进阶 && 《算法导论》

  • Codeforces:Div.1/比赛全站
    • 参与周赛/虚拟比赛,训练速度和思
      维。
  • LeetCode:高频面试题
    • 重点:二叉树、链表、动态规䎞(如
      股票问题系列)。