# 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> (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 `:官方 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)