Files
MAG160C/analysis/history/handoff_20260813.md
T

8.0 KiB
Raw Blame History

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)