chore: reorganize analysis/ by SDK lineage (linux/win/android) with README index, move legacy notes to history/, refresh root README, ignore .zcode/

This commit is contained in:
ZXCLI
2026-09-10 03:09:13 +08:00
parent 4ba98f62cd
commit e69a97436b
137 changed files with 123 additions and 62 deletions
+163
View File
@@ -0,0 +1,163 @@
# MAG160C 热像仪渲染管线交接文档 v5
> 项目:MAG160C 热像仪(160x120, USB, VID 0x833C)自实现渲染管线 demo3
> 目标:复刻官方 CoreSDKLib.dll 渲染效果
> 状态:颗粒 ✓ / FFC 颜色 ✓ / 蒙层 ✓ / **黑洞·黑拖影 ✗(当前阻塞)**
---
## 1. 已解决问题(历史)
| 问题 | 根因 | 修复 |
|---|---|---|
| 画面颗粒重 | NUC 斜率 3 过大(官方 0.19) | `NUC_GAIN=19`(0.19) |
| FFC 后颜色跳变 | FFC 后重采集 ref 吸收场景 | `REF_REINIT_AFTER_FFC=0`:FFC(1) 后只 rebase 全局偏移 |
| 物体显示破碎/椒盐 | 固定窗口 ±312,物体 nuc 超窗口饱和 | 自适应 P2..P98 百分位窗口(下限 624,官方实测) |
| 画面"蒙一层东西" | 常数 ref 不做平场,mura(空间 std 3560)直接显示 | 启动采集每像素平场(median,运动门控) |
| 黑拖影/黑洞 | ref 冻结 + 物体移动 → 旧位置 d = live-ref < 0 → nuc 低 → 黑 | **未解决**(见 §3) |
---
## 2. 官方逆向成果(已验证,disasm 证据)
### 2.1 渲染数据流
```
USB帧(type=0)
→ 平滑器 0x41f10(模式1: 首帧 memcpy + EMA) → f20 (dev+0x41f20)
→ NUC 查表 0x180017200: d2=(f20-ref)>>1, 段查表, clamp[0,65535]
→ 3x3 加权 0x180017330(写回) → dev+0x270 (raw/NUC输出)
→ 窗口 0x4202c/0x42030 (hi/lo, 动态) → gray (dev+0x220, 2x 升采样 320x240)
→ 调色板 256 色 (pal[0]=黑, pal[255]=白) → RGB
```
### 2.2 NUC 查表(0x180017200, 完整逆向)
```
每像素:
d2 = (f20[i] - ref[i]) >> 1 (sar)
段选择: for(edx=0; edx<nsegs-1; edx++)
if (d2 <= s16 thresh[edx]) break; (thresh 在 dev+0x41858, 值 [3136, 2484, 644])
偏移 = edx * 19200 * 2
nuc = (u16 gain[段][i] * d2) >> (shift=0x11c=12) + u16 off[段][i]
clamp [0, 65535]
→ dev+0x270
```
- gain/off 表:dev+0x41870,nsegs=dev+0x41554=3,每段 19200 像素 × (gain u16, off u16)
- **注意:d2 全负(正常场景,ref≈f20+3800)→ 段0。段1/2 用于大 d(物体),官方对物体响应待验证**
### 2.3 参考帧 ref(dev+0x41ef0)
- 来源:平滑器 0x41ee0(模式4 = 累加平均 acc+=in, out=acc>>2)
- 采集:启动帧 6-9(仅 4 次调用 0x18000c620),之后**冻结**
- FFC 后:只全局偏移变化(-145/-214 counts),空间结构不变(不重采集)
- 与 f20 同源 mura(corr 0.998),精确抵消 mura → d2 空间 std 仅 ~114
### 2.4 FFC 触发(0x18000a1d2, 0x180002f50)
- 条件 A:帧号 ≥ r9 + [0x2d90](0x2d90=1800 帧 ≈ 120s 周期)
- 条件 B:帧号 ≥ r9 + r8(30/100 冷却)且 |sensor_temp - last| > [0x2d94]=250
- 动作:发 FFC(0) (0x6bb6b672, param=0),更新温度记录(0x54/0x58),重置计数(0x49c)
- FFC(1) 在 9 帧后(0x18000c620 链路),type=1 帧期间不渲染(官方冻结画面)
### 2.5 温度
- NUC 输出与温度**完全正相关(corr=1.0, 热=亮)**
- temp_mC = T2E 查表(3×nuc - C, C~5797, 表 0x249f0 645 项)
- 平滑器 0x41f40(模式?)→ 0x180010780(温度)
### 2.6 关键结论
- **官方 ref 冻结 → 官方同样会黑洞/拖影**(移动物体),官方无场景检测
- 官方 FFC 周期 120s,比 demo3 早期 27s 长得多
- 官方窗口动态(无手 span≈624,有手 span≈1381)
---
## 3. 当前阻塞:黑洞/黑拖影
### 3.1 现象
用户敲键盘(手在镜头前小幅移动):手移动后,手旧位置/背景最热处显示为黑色(d 负 → nuc 低 → 黑),拖影明显。
### 3.2 物理机制
```
ref 冻结(平场) → 物体移动 → 旧位置:
d = live(当前背景) - ref(启动背景)
若背景温度漂移/场景变化 → d < 0 → nuc < comp → 黑
```
### 3.3 已试方案与结果
| 方案 | 结果 | 失败原因 |
|---|---|---|
| 固定窗口 ±312 | 物体破碎 | 窗口太窄 |
| FFC 后重采集 ref | 颜色跳变 | 吸收场景 |
| 冻结 median 平场 | 黑洞 | ref 冻结 |
| 常数 ref(每帧全局最低) | 无黑洞但蒙层 | 不平场 |
| 平场+min 平移 | 蒙层✓(修复采集 bug 后) 黑洞回归 | ref 仍冻结 |
| SBNUC 条件更新(df<50 且 dd<80, α=1/64) | 蒙层✓ **黑洞仍存** | 见 3.4 |
### 3.4 SBNUC 失效根因(diag 实测 d=(-467±1479))
1. **df 条件(帧差<50)**:手快速移动时,手经过的像素帧差大 → 永不满足 → 永不吸收 → 拖影持续
2. **dd 阈值 80 太严**:背景 d 空间 std ~458 → 大部分背景像素 |d-med|>80 → 吸收率极低
3. **α=1/64 太慢**:完整吸收需 64 帧(4s),拖影长
4. **背景漂移**:场景整体漂移(实测 d mean 从 +1734 → -467,场景变冷)→ d 负 → 黑
### 3.5 下一步建议(按优先级)
1. **改 SBNUC 参数**:去掉 df 条件(或放宽到 200),dd 阈值 ~120,α=1/16(1s 吸收)
- 理由:只用 dd(物体距离)判断,手经过区域(背景没变,d≈med)→ 立即吸收
2. **每像素时域 d 方差检测**(Hardie Kalman SBNUC, IEEE TIP 1998):
- 维护 d[i] 短窗方差:背景稳定(方差小)→ 吸收;物体经过(方差大)→ 不吸收
3. **双缓冲 ref**:背景 ref(条件更新)+ 物体区域冻结保护
4. 验证指标(demo3_diag.txt):d mean → 0,d 空间 std 应 < 300,物体移动后旧位置 d 快速回 0
5. 若参数方案有效,复刻官方查表(0.19 线性 → 官方分段)对比官方画面
---
## 4. 代码结构与关键参数(demo3.c)
```
常量:
CONSTANT_REF=1 常数/平场+SBNUC 模式
NUC_GAIN=19 (0.19)
FFC_PERIOD=1800 官方周期(120s)
FFC_GAP=9
REF_INIT_N=12 平场采集帧数
REF_REINIT_AFTER_FFC=0 FFC 后不重采集
WIN_HALF=312 窗口下限半宽(P2-P98 自适应)
平场采集:g_ref_phase==1(启动 nread>=60 后),运动门控(帧差>30 或 4% 像素动 → 重置窗口)
SBNUC 块:CONSTANT_REF && g_ref_mura_ready 分支(行 ~885):
med = 直方图中值(live - g_ref_mura)
if (|live-prev|<50 && |(live-mura)-med|<80) mura += (live-mura)/64
平移: ref = mura - min(mura) + min(live)
关键数组:g_ref_mura[NPIX] 平场, g_reference[NPIX] 渲染用
```
### 编译
```
gcc -O2 -w -DMAG160C_STATIC -I"C:\Project\MAG160C\csdk\third_party\libusb\win64" -I"C:\Project\MAG160C\csdk\include" -I"C:\Project\MAG160C\csdk\src" -o "C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe" "C:\Project\MAG160C\csdk\tools\mag160c_demo3.c" "C:\Project\MAG160C\csdk\src\mag160c_display.c" "C:\Project\MAG160C\csdk\src\mag160c_error.c" "C:\Project\MAG160C\csdk\third_party\libusb\win64\libusb-1.0.x64.a" -lgdi32 -luser32
```
### 运行/测试
```
Stop-Process -Name mag160c_demo3 -Force
Start-Process "C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe" -WorkingDirectory "C:\Project\MAG160C\build-artifacts"
日志:demo3_diag.txt(每帧 ref/live/nuc/窗口/d), demo3_auto_*.bmp(每 30 帧自动截图)
用户测试:启动 → 等平场(~5s) → 手放镜头前小幅移动(敲键盘) → 观察黑拖影
```
### 工具
- `build-artifacts/tsdk_pair2.exe <dir> <npairs> <delay>`:官方 SDK 抓帧(需先停 demo3;若 "no channel" 需重插设备)
- `build-artifacts/mag160c_frame_stats.exe`:libusb 直连抓帧
- 反汇编:`analysis/disasm/coresdk_windows_disasm.txt`(UTF-16,193k 行)
- 官方数据:`analysis/pairs_nuc2/pair_000.*`(f20/ref/raw=nuc/gray/rgb/cbrgb/t32/thr/gain)
---
## 5. 方法参考(专利/开源)
- Scribner et al., "Adaptive nonuniformity correction for IR focal-plane arrays using neural networks", SPIE 1541, 1991/1993 — 最经典 SBNUC
- Hardie et al., "Scene-based nonuniformity correction with reduced ghosting using a recursive Kalman filter", IEEE Trans. Image Process. 7(10), 1998 — **专治移动物体鬼影,与当前问题最相关**
- FLIR/ULIS 自适应 FFC 专利(如 US 7,940,301 系列)— 静止场景才刷新校正表
- 开源:seek-thermal-suite(madsci1016)、Melexis MLX90640 API(无快门自校正)
- 核心思想:背景像素"静止且接近参考"才更新;物体区域冻结
## 6. 未完成逆向
- [ ] 官方查表段 1/2(大 d 物体)的增益/偏移值与物体响应(线性 0.19 vs 官方分段)
- [ ] 官方窗口(0x4202c/0x42030)更新机制(动态 span 怎么算)
- [ ] 0x180016ae0 菜单表初始化(0x417xx/DDT)
- [ ] FFC 状态机 0x73bf4(帧 75/130)
- [ ] 官方输出 2x 升采样算法(0x220 38400 → RGB)