21 KiB
MAG160C 项目交接文档 (2026-08-10)
2026-08-10 晚更新(本会话):FFC 停帧问题已解决并多次实机验证; 坏点/对比度/标定管线已按开源方案重做并合入 csdk。详见第 10 节。
1. 项目目标
对 Elo/Magnity MAG160C USB 热成像相机进行完整逆向,实现一个独立、可用的 Linux/Windows C SDK + Windows GUI Demo。已完成的逆向依据:
analysis/protocol_spec.md(协议全谱)analysis/findings.md(证据链)analysis/captures/libusb0_trace.txt(官方 demo 完整 USB 流量,26092 行)analysis/captures/official_hand.pcap(官方 demo 手掌遮挡抓包)analysis/captures/csdk_verified.pcap(csdk 抓包)
2. 硬件事实(实机确认)
- 设备名:Magnity Thermal Camera,VID 0x833C PID 0x0001,序列号 160043865
- 分辨率 160x120,帧率 ~15fps,每帧 38456 字节
- USB:config 值 1(仅一个配置),interface 0,端点:0x03 OUT、0x81/0x82/0x84 IN
- 设备只有 config 1——Linux SDK 逆向中的 set_configuration(2) 在这台机器上失败, 会回退到 1(逆向代码 0x1865b 分支)
3. 已验证协议(权威,实机+官方流量双重确认)
3.1 命令(4 字节魔数,无参数;仅 FFC 用 8 字节 {magic,param})
| 命令 | 字节 | 响应 |
|---|---|---|
| 0x6bb6b66b 信息查询 | 4 | 0x5bb5b55b(60B:pid@+4,width=160@+0x14,height=120@+0x18,fps=15@+0x1c) |
| 0x6bb6b66c | 4 | 0x5bb5b55c(60B,另一数据块,勿当 info 解析) |
| 0x6bb6b66f | 4 | 0x5bb5b55e(20B) |
| 0x6bb6b672 FFC | 8 | 0x5bb5b55f(4B OK) |
| 0x6bb6b673 START | 4 | 0x5bb5b55f |
| 0x6bb6b674 STOP | 4 | 0x5bb5b55f(需先 clear_halt 0x03/0x82) |
注意:帧头字段偏移以"帧内"为准:marker@0、cnt@4、len@8、type@0xc、shutter@0x10。
3.2 启动序列(官方一致)
open(config 1, claim iface 0)
66b → 66c → 66f (各 4B)
FFC(0) → 100ms → FFC(0) → 300ms → START(4B) → 700ms
3.3 FFC 语义(关键难点)
- FFC(1) 使流切换为 type=0 帧(温度数据,avg ~11720,手掌遮挡 +1200 counts)
- FFC(0) 使流切换为 type=1 帧(avg ~16000,手掌遮挡变化小 <100)
- 官方 demo 在 type=0 下每 ~10 帧发一次 FFC(0/1 交替)维持推流
- FFC 必须在"完整帧(头+数据)之后"发送
- 问题:在 libusb-1.0(TI DLL)或 libusb0 下,FFC(1) 切换后设备经常停帧;
但
csdk/tools/thermal_viewer.c(单线程、frames==3 时 FFC(1)+Sleep(400)) 能稳定工作(已验证多次,显示 type=0 帧 100+) csdk/tools/mag160c_demo2.c基于 viewer 核心,但被强杀/反复运行后设备 进入坏状态需 libusb_reset_device 重试(已加 4 次重试)
3.4 帧格式
+0x00 u32 0x1bb1b11b
+0x04 u32 frame counter
+0x08 u32 0x9600 (38400 data length)
+0x0c u32 type (0=温度/response, 1=raw)
+0x10 u32 shutter
+0x14..0x1b 保留
+0x1c .. 38400 字节像素 (u16 LE)
+0x1c+38400 u32 0x1bb1b11c (尾标记)
之后 24 字节尾字段(含 0x6cf0 类统计值)
4. 温度数据(实测)
- type=0 帧:背景 avg≈11720,手掌遮挡(整个 FOV)+1200 counts
- 线性标定:约 147 counts/°C(假设手掌 34°C vs 背景 25°C,未精确标定)
- demo 温度显示:25 + (v - reference)/147
- 官方 Android SDK 有 T2E 表(0x112 项,已 dump 到 analysis/t2e_table.json) 和 E2TAccQ10 表(逆向的 ReviseTemperature/CorrectTemperature 用)
5. 当前 Demo 状态(csdk/tools/)
| 文件 | 状态 |
|---|---|
thermal_viewer.c |
✅ 稳定工作:单线程循环、frames==3 时 FFC(1)、percentile 2%-98% 渲染、type=0 显示 |
mag160c_demo2.c |
🔶 基于 viewer 核心,加面板/按钮/温度/坏点检测;有设备状态残留问题(需 reset 重试) |
mag160c_demo.c |
❌ 弃用(自行写的 init/FFC 逻辑设备会停帧) |
mag160c_demo_usb0.c |
❌ 弃用(libusb0 API 版,同样停帧——问题不在传输层) |
已知显示问题(需参考开源实现解决)
- 坏点(红蓝固定点):type=0 帧存在固定坏像素,显示为红/蓝点。 已在 demo2 加"参考采集时 min-max 波动 >400 标记坏点、邻居平均替换", 但用户反馈仍可见(阈值/方法需优化,或坏点表应在 FFC 后重新采集)
- 对比度:diff 模式(当前-参考,deadband±70,span 1500)手掌轮廓可见但偏弱; absolute 模式 percentile 拉伸对比度差
- FFC 后设备停帧:不稳定,与官方 demo(持续工作)行为不一致, 差异可能在于官方 FFC 的精确时序/频率
6. 环境与工具
- Windows 11,MinGW gcc 14.2 (C:\mingw64)
- 设备驱动:libusb-win32 v1.2.6.0(Zadig 安装;WinUSB 也可但 TI libusb DLL 的 FFC 写失败;官方 libusb-1.0.27 在两种驱动下都崩溃)
- 传输库:TI libusb-1.0.dll(C:\ti\ccs2050\ccs\ccs_base\common\bin,
支持 libusb0 后端,有无害的 monotonic clock 警告)
- dlltool 生成的导入库 csdk/third_party/libusb/win64/
- USBPcap 1.5.4 + Wireshark(重启后可用,设备在 \\.\USBPcap4)
- 抓包 pcap 解析脚本:analysis/captures/ 下(参考之前会话)
7. 开源热成像 SDK 参考(下一轮调研目标)
网络在部分时段可用,建议用 webfetch 搜索:
- FLIR Lepton SDK(github: groupgets/LeptonModule 或 purethermal1):展示了 raw→radiance→温度、AGC(自动增益控制)、伪彩色流程;坏点补偿思路
- Seek Thermal 开源驱动(github: ThermalScope/seek-thermal-camera 或 fnoop/seek-thermal-linux):EEPROM 坏点表、NUC(非均匀性校正)
- MLX90640 库(github: intergatedcircuits/Pico-MLX90640):插值+显示
- AMG8833/MLX90640 的 Adafruit 库:显示映射方法
- 关键要学习:①坏点检测与补偿算法 ②AGC/显示拉伸(直方图均衡 vs percentile) ③NUC/FFC 后的温度图管线 ④伪彩色 LUT 设计
8. 下一步工作
- 调研开源热成像显示管线,改进 demo2 的:坏点补偿、AGC(显示拉伸)、伪彩色
- 稳定 FFC:对照官方 trace 精确复刻 FFC 时序(包括周期性),解决停帧
- 温度标定:用已知温度(冰水/热水)做两点标定,替代 147 counts/°C 假设
- 把验证过的协议与显示管线合并回 csdk 的 mag160c_ir 实现
- Linux 移植(最终目标)
9. 快速启动命令
# 设备恢复(设备停帧时)
.\build-artifacts\usb_hardreset.exe
# 运行 demo(能看手掌的稳定版)
.\build-artifacts\thermal_viewer.exe
# 功能完整版(重试+坏点+新 FFC 调度)
.\build-artifacts\mag160c_demo2.exe
# 无头 FFC 稳定性验证(1400 帧 type=0,~95s)
.\build-artifacts\mag160c_ffc_test.exe
# csdk 线程管线验证(reader thread + FFC scheduler)
.\build-artifacts\csdk_stream_test.exe
# csdk CLI 综合(显示管线自检 / 流验证)
.\build-artifacts\csdk_cli_libusb.exe display-test
.\build-artifacts\csdk_cli_libusb.exe ffc-test 1000
# 抓包
& "C:\Program Files\USBPcap\USBPcapCMD.exe" -d \\.\USBPcap4 -o out.pcap -A -s 65535
10. 2026-08-10 晚:FFC 停帧解决 + 显示管线重做(本会话)
10.1 官方 FFC 时序(从 libusb0_trace.txt 精确解码)
逐行统计 26092 行官方流量,每帧 = 28B 头 + 38428B 数据。FFC 事件与帧计数:
init: 66b 66c 66f -> FFC(0) -> START -> [frame 1] -> FFC(0)
frame 10: FFC(1) -> 流切换 type=0(第 11 帧起)
然后周期循环: FFC(0) --9 帧--> FFC(1) --N 帧--> FFC(0) ...
- FFC(1) 总是在 FFC(0) 后恰 9~10 帧发出(0.6s@15fps,即快门闭合→恢复)。
- FFC(1) 后到下一个 FFC(0) 的间隔 N 不固定:34, 48, 66, 101, 166, 373, 346, 103, 1383, 381, 48, 1006, 317, 171, 158, 189, 219, 294, 425, 628, 723, 1012, 1450, 1804, 2680, 403, 105 …(用户/定时器驱动,非固定周期)。
- 全程 10898 帧持续推送,type=0 占 10519 帧(96.5%),type=1 只出现在每个 FFC(0)→FFC(1) 的 9 帧窗口。
- FFC 必须在一整帧(头+数据)读完之后发送(trace 中 FFC 行紧跟帧数据行)。
- 教训:demo2 旧版只发一次 FFC(1) 且周期 44 帧过密 → 设备停帧或 type=1 占比过高(17.7%)、fps 下滑。官方式 周期 400 帧 + 9 帧间隔 完美工作。
10.2 实机验证结果(全部 PASS)
| 验证项 | 工具 | 结果 |
|---|---|---|
| FFC 周期 400 + gap 9 | mag160c_ffc_test.exe |
1400 type=0 帧 / 95s / 15.1fps / 0 停帧(2 次) |
| csdk 线程管线(reader thread + scheduler) | csdk_stream_test.exe |
1030 type=0 帧 / 70s / 14.7fps / 0 停帧 |
csdk CLI ffc-test |
csdk_cli_libusb.exe |
同上,PASS |
| 显示管线单测 | csdk_test_display.exe |
20/20 通过 |
| GUI demo2 | mag160c_demo2.exe |
窗口实时显示 type=0,坏点红蓝占比 0.02%,无饱和坏点 |
| 回归(旧 4 套) | csdk test_* | 全部通过 |
10.3 显示管线(按开源方案重做,已合入 csdk)
新增 csdk/src/mag160c_display.c + csdk/include/mag160c/mag160c_display.h,
纯 C 无平台依赖(Linux 可直接编):
- 坏点检测(参考 OpenThermal/libseek-thermal SeekCam.cpp + MLX90640):
- 时域:参考帧 min-max 波动 > 400 → 坏点(保留旧法)
- 直方图峰偏离(Seek 法):
thr = histPeak - (frameMax - histPeak), 并加histPeak + 200下界防孤立极值误杀全图 - 拓扑序填充:坏簇从边缘向中心迭代,存填充顺序;参考图与每帧 都按该顺序用 4 邻域均值替换(坏簇逐层内缩)
- AGC/显示拉伸:
- 绝对模式:2%~98% percentile 拉伸 + ironbow LUT(FLIR 风格 7 锚点)
- diff 模式:自适应 span = 2×mean|diff|,clamp [120, 4000], deadband = span/20(轮廓对比度显著提升)
- FFC 调度器
mag160c_ffc_scheduler_t:tick(帧后)返回应发的 FFC 参数(0/1/-1);mag160c_ir_set_ffc_scheduler()挂到 reader thread, Linux 线程模型直接可用。 - 两点线性标定
mag160c_temp_calibrate_linear(counts0,temp0,counts1,temp1)→ a/b;demo2 有 Cal Cold(0°C)/Cal Hot(90°C) 按钮,CLI 有calibrate占位。
10.4 遗留事项(下一步)
- 物理两点标定:需实际操作(冰水 0°C / 开水 90°C+ 充满 FOV),用 demo2
的 Cal Cold/Cal Hot 按钮或记录 counts 代入
mag160c_temp_calibrate_linear。 当前仍是 147 counts/°C 假设(参考背景 ~11720 counts @ 25°C)。 - demo2 内联的坏点/AGC 逻辑与 csdk 模块功能重复,后续可让 demo2 直接调 csdk 模块(现 demo2 已用 csdk 的 FFC scheduler)。
- Linux 移植:csdk 侧已就绪(纯 C + pthread + libusb);GUI demo 的 Win32 部分需换 SDL/GTK。
10.5 后续小 bug 修复(2026-08-10 深夜)
用户反馈两个现象,均已修复并实机验证:
- 鬼影:旧参考帧用逐像素 EMA(
(r*199+v)/200)持续吸收当前画面, 静止物体 ~13s 就被"吃进"参考帧,移开后留下反向残影。改为漂移跟随: 仅当场景安静(mean|diff| < 40)时,把参考帧整体平移全局均值差 (clamp ±400),不再吸收任何空间内容 —— 跟温度漂移/FFC 基线,不跟场景。 - FFC 响应红黄闪烁 + 卡顿:FFC(0) 后设备输出 ~9 帧 type=1(avg ~16000,
与 type=0 基线差 +4300),旧 demo 照常渲染 → 全屏红黄;手动 FFC 按钮在
UI 线程
Sleep(300)阻塞。修复:- 主循环跳过非 type=0 帧的渲染(冻结画面,与官方 app 一致)—— 实测 218s/3744 帧/~8 次自动 FFC 周期标题栏从未出现 type=1,闪烁消除。
- 手动 FFC 改异步排队:按钮只置
g_manual_ffc标志,主循环在下一 完整帧后经mag160c_ffc_scheduler_trigger()发 FFC(0),9 帧后自动 发 FFC(1),UI 不再阻塞。 - csdk 新增
mag160c_ffc_scheduler_trigger()(test_display 22/22 通过)。
10.6 二次修复:鬼影根因 + FFC 残闪(2026-08-10 深夜,实机验证)
用户复测:鬼影仍存在,且高温物体进入鬼影区会被"遮住"成低温色; 红黄帧不再卡住但偶尔闪过。根因分析 + 修复(参考 OpenCV MOG 背景建模 与 Seek 挡片校准思路):
- 鬼影根因(两层):
- 旧参考更新用"全局 mean drift":物体占 FOV 比例小时 mean|d| < 40 误判安静,全局偏移把小物体逐步吸收进参考帧(数秒~数十秒), 移开后留下高温残影;真实高温物体移到该位置时 diff=live-ref 变负 → 显示成低温,即"被遮住"。
- 初始参考采集是 30 帧均值:采集窗口内若有物体在动,均值会把 物体烘焙进参考,永久鬼影。
- 修复:
a. MOG 逐像素背景模型(
mag160c_display_ref_track):背景像素 (|d| < 60)慢速 EMA 跟踪漂移;前景像素(|d| >= 60)完全冻结, 永不吸收(之前是 clamp+漏吸收,约 112 counts/s 泄漏)。 b. 安静门控的初始采集:每帧与上一帧 mean|Δ| < 25 才入样本, 30 帧逐像素取中位数(物体短暂进入窗口不会污染参考); 场景一直不静则参考一直不落(可手动 Set reference)。 c. 合成测试MOG_GHOST_TEST:静态 +1200 热块 4500 帧(模拟 5 分钟) 吸收 0 像素;移开后 diff≈0 无鬼影;慢漂移仍可跟踪 → PASS。
- FFC 残闪:FFC(1) 后 type=0 基线跳变(官方 trace 实测最大 +1000
counts),旧重对齐 ±400 clamp 不够,残余偏移需 MOG 数秒才消化 →
短暂偏红。修复:重对齐 clamp 放宽到 ±2000(中位数本身抗 >50% FOV
物体),FFC(1) 后跳过前 2 帧渲染(
g_skip_ffc)。 实测连续 3+ 个 FFC 周期(period 400)红色占比前后无跳变(11.1% → 11.1%),蓝色始终 0.01%,type=1 帧从不渲染,流不断(1500+ 帧)。
证据:analysis/demo2_v3_mog_verified_20260810.png;单测 28/28 通过
(csdk_test_display.exe),旧 4 套回归全绿。
10.7 三次修复:开机乱图 + 残余鬼影(2026-08-10 深夜,实机验证)
用户复测:FFC 红黄闪帧已解决,但(1) 刚开软件画面有红黄点乱分布, 且不会消失、叠加到正常画面上;(2) 鬼影仍存在。
根因(两层,均为 MOG"永久冻结"缺陷):
- 开机乱图:参考帧首次采集在 nread>=150(~10s,第一个自动 FFC 周期 之前)进行。设备刚完成启动 FFC(1),type=0 基线/坏点尚未稳定,启动 噪声(红黄点)被中位数采入参考;之后 live 已正常,这些像素 |d| >= 60 被 MOG 永久冻结 → 乱图叠加且永不消失。
- 鬼影:同上——参考一旦采错(含物体/含噪声),MOG 冻结使其无法自愈; FFC 后一次性 median rebase 只平移全局,修不掉逐像素错误。
修复:
- 首次参考采集提前到启动 FFC(1) 稳定之后(nread >= 40 + 跳过 2 帧 过渡),不在第一个自动 FFC 周期前采集 → 启动噪声不再进入参考。
- 每次 FFC(1) 后重新采集参考(REF_REINIT_AFTER_FFC):FFC 校准后 设备输出最干净的 type=0 帧,用它重建参考(安静帧中位数,30 帧, 沿用坏点表填充),取代一次性 rebase。每 ~27s 自动刷新一次,任何 残留错误最长一个周期内被清除。
- MOG 自愈(
mag160c_display_ref_track_heal):孤立像素(8 邻域前景 < 2)连续前景 >= 30 帧 → 判定为参考错误(启动噪声/坏点)而非物体 (物体是连片的),重置 ref = live。乱图/残点最长 ~2s 内自愈。
验证:
- 合成测试
SELFHEAL_TEST/ csdktest_display30/30:40 个孤立噪声点 全被治愈;60x40 连片热块 200 帧吸收 0 像素、不被误治;移开后无鬼影。 - 实机:开机 t=4s 孤立噪声 0.12%,t=34s(参考+FFC 后)0.11%,t=90s
(5+ FFC 周期)0.10% —— 乱图不出现、不叠加、不增长;红色像素全部为
真实场景连片目标(45
71 个大 blob);FFC 周期红%无跳变(6.48.6%), 蓝%恒 0.01%;流持续 2157+ 帧无停帧。
证据:analysis/demo2_v4_selfheal_verified_20260810.png。
10.8 四次修复:根因定位(传感器 mura)+ NUC 平场校正(2026-08-10 深夜,数据驱动)
用户复测:开机乱图和鬼影依然存在。本次用数据驱动定位真正根因,并 采用开源(Seek/FLIR 挡片帧)同款方案修复。
实测数据(mag160c_frame_dump 抓 60 帧 type=0 分析):
- 每像素时域噪声 std ~248 counts(99.9% 像素"波动")→ diff 模式自适应 span≈400、deadband≈20 把噪声全部放大成可见红蓝点 = 开机乱图
- 固定传感器 mura:行剖面跨度 15594(row1 恒定 +5000,25418 vs row98 9824)、 列剖面 8714;FFT 行/列轴能量占比 ~10%
- mura 会话内漂移 ~350 counts,FFC 后突变 → diff 参考帧跟不上 = 鬼影
- flat-field 校正验证:
live - (ref - mean(ref))把 mura std 3557→379 (行跨度 15704→401),中值滤波后噪声 ~80
为什么官方 app 没有乱图/鬼影:Android 官方管线是 raw→温度→绝对 温度窗口显示(25~40°C),不用场景参考帧做 diff,天然免疫噪声放大与 参考漂移。
修复(推翻 diff 方案,改 NUC 平场 + 绝对温度显示):
- flat-field(NUC)校正(
mag160c_display_nuc,csdk):nuc = live - (ref - mean(ref)),消除固定 mura;显示绝对温度级别,median 居中 ±1500 窗口 + ironbow。 - 3x3 中值平滑:把 248-count 时域噪声降 ~3 倍,画面平滑无噪点。
- 参考帧只做固定图案,不跟踪场景:采集时 5% 像素偏离阈值即拒帧 (持久物体永不进参考)+ MOG 冻结 + FFC 后重采集 → 无鬼影。
- diff 模式降级为可选(默认 absolute)。
实机验证:speckle residual 2.22.7(平滑)、纯蓝 0%、红色均为真实场景
连片目标(11.4%);连续 5+ FFC 周期无闪帧、无图案出现、无噪声增长;
流持续 2268+ 帧。csdk 单测 32/32,旧回归全绿。
证据:analysis/demo2_v5_nuc_verified_20260810.png。
工具:csdk/tools/mag160c_frame_dump.c、mag160c_frame_stats.c。
10.9 五次修复:数据驱动根因 + 官方 DLL 活体对比(2026-08-10 深夜)
用户复测:画面更混乱。本次彻底转向官方实现对比:
逆向成果(活体官方管线):
- 反汇编 Windows 官方 CoreSDKLib.dll + ThermalSDK.dll(65 个 MAG 导出,
精确 RVA 全部解析),确认官方渲染管线:
MAG_GetOutputBMPdataRGB24:8-bit 灰度[dev+0xb00]→ 调色板查表 (256x4 BGR),输出 320x240 RGBMAG_GetTemperatureData:逐像素 counts→temp,T2E 表(646 项,已从.rdata 0x5cde0提取)+ 斜率表,公式:temp = slope[i]*diff>>12 + (i<<12) - 0x249f0- Windows 调用序列:NewChannel(chan) → EnumCameras(chan) → LinkCamera(chan,pid) → StartProcessImage(chan)
- 用官方 ThermalSDK.dll 活体驱动设备成功(tsdk_debug/tsdk_capture3):
- 官方渲染帧 320x240,紫红调色板(G=0,R/B 渐变),极平滑 (speckle 0.00%,仅 106 色),无 mura 无噪点
- 官方温度:背景 26.7~27.4°C(ReadTemperatureAtPoint)
- 数据对比锁定根因:
- counts 有大尺度固定 mura:空间 std 3560、行跨度 15000+、 row0 17318 → row120 7954(固定,会话间一致,row1 漂移 1535/FFC)
- 官方图像完全无此 mura → 官方用 per-pixel 校正(baseline/DDT) 消除了它
- NUC 验证:
live - (ref - mean(ref))把 mura std 3560→29 (行跨度 15000→23~49),mura 消除 99%
- demo2 的 bug:参考采集的 quiet-gate(要求 mean|d|<25)在用户 观看时永不满足 → NUC 从未激活 → 显示 raw counts 乱图。
修复(最终方案):
- 参考采集去掉 quiet-gate,直接取 30 帧逐像素修剪中位数 (中间 50% 均值,抗物体/死点)
- NUC 平场校正为默认显示(绝对温度),消除 mura
- 自适应窄窗口:NUC 值 median ± 4*mean|d|(实测 std
29 → span120, 手掌 +1200 清晰弹出),替代过宽的 ±1500 固定窗口 - 3x3 中值平滑 + MOG 冻结/自愈 + FFC 后重采集(保留)
实机验证:unique colors 22260(高对比)、纯蓝 0%、孤立噪点 0.62%、 310 个大 blob(真实场景)、speckle 2.3、6+ FFC 周期无闪帧无鬼影累积、 流持续 2621+ 帧。csdk 单测 32/32 通过。
证据:analysis/demo2_v6_nuc_final_20260810.png。
工具:csdk/tools/tsdk_debug.c、tsdk_capture3.c、official_harness.c、
analysis/temp/official_t2e.txt(官方 646 项 T2E 表)。
10.10 六次修复:逐像素复刻官方显示管线(2026-08-10 深夜)
用户指出显示效果与官方不一致。通过官方 DLL 活体驱动 + 逐层提取, 完整复刻了官方的显示管线:
逆向提取(全部来自官方活体):
- 官方温度公式(CoreSDKLib 0x180016290):counts → 646 项 T2E 表
二分查找 + 斜率插值:
temp_mc = slope[i]*diff>>12 + (i<<12) - 0x249f0T2E 表已从 .rdata 0x5cde0 提取(646 int32,单调递增)。 shift=6 验证:counts 11224 → 24.8°C(与官方探针 26.7-27.4 一致, 差异来自 NUC/offset)。 - 官方调色板(从 8 帧官方渲染提取 115 色 + 插值到 256 项): 品红/紫红系:深红(74,0,0)→ 红 → 品红(145,0,145)→ 紫 → 蓝紫(115,32,210)→ 紫(154,0,188)。G 通道中段有小值。
- 官方显示特征:背景落在调色板中段(品红),不是黑/深红—— 因为显示窗口围绕背景温度(自适应),背景 ~25°C 映射到灰度 ~128。
demo2 复刻(最终显示管线):
counts → NUC 平场(live - (ref - mean(ref)),消除 mura)
→ T2E 官方温度(shift=6)
→ 自适应窄窗口(背景温度 ± 2°C)
→ 官方品红调色板查表
两个关键 bug 修复:
- 窗口单位 bug:temp_mc 是毫°C,窗口却用 °C 比较 → 全图灰度 255。
- NUC 参考被 MOG 更新吸收背景 → NUC 失效(参考只 FFC 后重采集, MOG 仅用于可选 diff 模式)。
实机验证:画面 mean RGB 139/25/144 vs 官方 141/1/130(几乎一致); 背景品红(139,0,117)与官方(145,0,145)同色系;黑色 0.1% vs 0.0%; 4+ FFC 周期无闪帧、稳定。csdk 单测 32/32。
证据:analysis/demo2_v7_official_look_20260810.png。
新增:csdk/src/mag160c_official_palette.h(256 项官方调色板)、
csdk/src/mag160c_official_t2e.h(646 项官方 T2E 表)、
csdk/tools/tsdk_pair.c、tsdk_gray.c、tsdk_palette.c。