35 KiB
MAG160C 热像仪逆向工程完整交接说明
1. 文档目的
本文档用于把 C:\Project\MAG160C 整个工程移交给另一位工程师或另一位 AI。目标不是只说明当前代码怎么编译,而是把以下内容全部交代清楚:
- 工程每个主要目录的用途。
- MAG160C 硬件、USB、帧格式和驱动环境。
- 官方 Windows、Android、Linux SDK 的逆向成果。
- 官方 CoreSDKLib.dll 实际渲染主链路。
mag160c_demo3.c当前实现和所有实验性分支。- 已经解决的问题、仍未解决的问题和曾经失败的路线。
- 如何安装工具、构建程序、连接设备、抓帧、运行和诊断。
- 如何继续逆向低温残影,并避免重复走已经验证失败的路线。
- 让下一位 AI 从零开始接手时可以直接使用的中文提示词。
文档日期:2026-08-11。工作目录:C:\Project\MAG160C。远端仓库:https://git.zxcli.top/zxc/MAG160C.git。
2. 一分钟结论
2.1 硬件
- 设备是 MAG160C 160×120 红外热像仪。
- USB 设备常见身份是 VID
0x833C、PID0x0001。 - 它不是普通 UVC 热像仪,而是厂商自定义 USB bulk 协议。
- 命令使用 EP
0x03,响应使用 EP0x82,实时帧使用 EP0x81。 - 原始实时帧包含 160×120 个小端
uint16像素。
2.2 官方渲染链路
官方 Windows CoreSDKLib.dll 的主链路已经被活体抓帧和反汇编共同确认:
USB type=0 原始帧
-> f20 平滑器 0x41f10,当前 mode=1,基本是逐帧 memcpy
-> NUC 0x180017200
d2 = (f20[i] - ref[i]) >> 1
每像素两个 signed threshold 选择三个 segment
每像素 gain/off 查表
out = off + ((gain * d2) >> 12)
clamp 到 [0, 65535]
-> 0x180017330,固定表驱动的坏点/盲元邻域补偿
-> 可选 0x18001e920 temporal filter;当前实测 mode=1,通常跳过
-> 窗口 hi/lo
-> 1024 项灰度 LUT
-> 256 项 BGR 调色板
-> 320×240 输出
2.3 官方参考帧
- 官方参考缓冲来自
dev+0x41ef0,对象起点是dev+0x41ee0。 - 参考平滑器是 mode=4,启动阶段通过累计平均形成参考。
- 正常 type=0 帧不会逐帧重新采集整幅参考。
- FFC 后空间结构通常保持,只做全局基线变化或重新进入内部配置过程。
- 官方参考不是 demo3 当前的“每帧根据场景自适应参考”。
2.4 当前 demo3 状态
当前 demo3 已经接入一组从官方活体抓取并验证过的三段逐像素 NUC 表:
build-artifacts/mag160c_official_nuc_gain.binbuild-artifacts/mag160c_official_nuc_thr.bin
当前默认策略是:
CONSTANT_REF=1。BADMAP_ENABLE=0。- 官方表存在时使用三段逐像素 gain/off/threshold 查表。
- 使用当前场景中值在官方 NUC 输出域反求一个全局参考偏置,使中值约为
NUC_CENTER=9804。 SBNUC_ENABLE=1,但实际只允许“曾经进入热态、后来变成持续负残差”的像素在运动结束后自愈。- 正残差不会写入参考,避免热目标被吸收。
- 显示层
deghost_nuc()不调用。
当前仍未完全解决:
- 低温区域静止时间较长后仍可能出现残影。
- 某些固定参考失配会表现为黑洞。
- 官方每次 FFC/传感器温度区间变化后会重新生成 NUC 表;demo3 当前使用一组静态抓取表,没有完整复刻官方温度端点插值和运行时重建。
- 官方
0x180017330的固定盲元补偿记录还没有完整接入 demo3 的新 NUC 表路径。 - 因此当前版本是比线性近似更接近官方的研究基线,不应宣称已经完全复刻官方。
3. 目录说明
3.1 根目录
| 路径 | 用途 |
|---|---|
README.md |
仓库入口和最短说明。 |
交接_完整逆向工程说明_20260811.md |
本完整交接文档。 |
findings.md |
早期和中期的综合逆向发现,包含 Windows、Android、Linux SDK 证据。 |
progress.md |
按日期记录的长期工程进度、协议恢复和工具安装记录。 |
task_plan.md |
早期 Linux SDK 实现计划和历史任务状态。后续热像渲染工作应以本交接文档和 analysis/handoff_*.md 为准。 |
frame_stats.txt |
历史原始帧统计。 |
pair_*.win、pair_*.win2、pair_*.nuctab |
根目录中遗留的官方抓帧窗口、字段和短 NUC 表样本。完整抓帧在 analysis/pairs_*。 |
.gitattributes |
Git LFS 大文件规则。 |
.tools/ |
逆向分析工具、Python 包和下载缓存。 |
.agents/ |
当前为空,保留目录结构。 |
.superpowers/ |
早期计划工具的资料,当前不参与 demo3 运行。 |
app/ |
原厂 APK 和 PC 分析程序。 |
IR_Camera_SDK-1.0.1/ |
原厂 Windows、Android、Linux SDK、示例、驱动、DLL、SO 和文档。 |
vendor-docs/ |
从根目录整理出的模块硬件文档。 |
3.2 csdk/
这是当前维护的纯 C SDK 和 Windows 工具目录。
| 路径 | 用途 |
|---|---|
csdk/include/ |
对外头文件和 C API。 |
csdk/src/mag160c_frame.c |
0x1bb1b11b / 0x1bb1b11c 帧解析和流组装。 |
csdk/src/mag160c_ir.c |
libusb 设备打开、命令、启动、停止、FFC、帧线程。 |
csdk/src/mag160c_temp.c |
原始响应、PWL 校正、T2E 温度换算。 |
csdk/src/mag160c_tcm.c |
TCM 的 0x7e 帧和校验。 |
csdk/src/mag160c_display.c |
坏点、显示、FFC 调度、线性温度工具。 |
csdk/src/mag160c_tables.h |
从官方二进制提取的温度表。 |
csdk/tools/mag160c_demo3.c |
当前主要 Windows 直连、渲染和残影实验程序。 |
csdk/tools/mag160c_demo2.c |
历史显示管线和 MOG/NUC 实验版本。 |
csdk/tools/tsdk_pair2.c |
官方 ThermalSDK 活体同帧抓帧工具。已修正 gain/thr 文件覆盖问题。 |
csdk/tests/ |
C SDK 纯计算、协议、温度和显示测试。 |
csdk/third_party/libusb/win64/ |
Windows x64 libusb 头文件、DLL 和 MinGW 导入库。 |
csdk/CMakeLists.txt |
CMake 构建文件。当前环境没有 CMake,主要使用直接 GCC 命令。 |
csdk/WINDOWS_TESTING.md |
USBPcap、Wireshark、MinGW 和硬件测试指南。 |
3.3 analysis/
这是逆向工程的核心证据目录。
| 路径 | 用途 |
|---|---|
analysis/disasm/ |
Windows CoreSDK、Linux libmagcore、Android ARM64 的反汇编、符号和函数切片。 |
analysis/protocol_spec.md |
USB 协议、帧格式、命令、温度和 NUC 公式的正式规格。 |
analysis/progress_reverse.md |
官方渲染主链和反汇编阶段性结论。 |
analysis/handoff_20260810.md |
demo2 早期路线、MOG、平场和问题演化。 |
analysis/handoff_20260811.md |
较短的 2026-08-11 交接。 |
analysis/handoff_20260811_full.md |
当前残影问题最重要的交接文档之一。 |
analysis/handoff_20260812.md |
官方活体抓帧、NUC 和显示数据分析。 |
analysis/handoff_20260812_night.md |
平滑器、参考和 NUC 查表的夜间逆向结论。 |
analysis/handoff_20260813.md |
黑洞、SBNUC、Hardie/Kalman 路线的历史总结。 |
analysis/pairs_nuc2/ |
官方 NUC 同帧数据。 |
analysis/pairs_move/ |
官方移动目标数据。注意旧 .gain/.thr 曾被覆盖。 |
analysis/pairs_recheck_20260811/ |
使用修复后的 tsdk_pair2_fixed.exe 重新捕获的数据,包含未覆盖的真实 .gain/.thr。 |
analysis/pairs_long/ |
较长时间官方抓帧和内部缓冲。 |
analysis/pairs_ffc/、pairs_ffc2/ |
FFC 前后对比。 |
analysis/pairs_win/、pairs2/、pairs_bar/ |
窗口、调色板和官方输出实验。 |
analysis/captures/ |
USBPcap、libusb shim 和官方/csdk 抓包。 |
analysis/usbnoise/ |
原始噪声帧和元数据。 |
analysis/ourdump/ |
直连设备原始抓帧。 |
analysis/reverse-cache/ |
AAR、JAR 等解包后的逆向缓存。 |
analysis/reverse_tools/ |
ARM64/ELF 辅助工具。 |
analysis/revtools.py |
ELF 加载、符号、交叉引用辅助脚本。 |
analysis/t2e_table.json |
T2E 单调表。 |
analysis/official_t2e_table.txt |
官方 T2E 提取文本。 |
analysis/legacy-cpp/ |
被纯 C SDK 替代的旧 C++ 实现和构建物。 |
analysis/demo2_*.png |
历史实机验证截图。 |
3.4 build-artifacts/
该目录保存可直接运行的 Windows 程序、DLL、抓图、日志和实验产物。当前最重要的文件:
mag160c_demo3.exe:当前 demo3。mag160c_official_nuc_gain.bin:官方三段 gain/off 表,230400 字节。mag160c_official_nuc_thr.bin:官方 threshold 抓取文件,115200 字节;demo3 实际使用前 76800 字节中的两个 threshold/像素,尾部多余数据保留作证据。tsdk_pair2_fixed.exe:修复.gain/.thr覆盖问题的官方抓帧工具。demo3_diag.txt:demo3 每帧诊断日志。demo3_ffc.txt:FFC 调度日志。demo3_rebase.txt:FFC 后参考 rebase 日志。demo3_auto_*.bmp:demo3 每 30 帧自动抓图。official_*.bin、official_*.rgb、official_meta.txt:官方活体输出样本。csdk_*、mag160c_*、usb_*、tsdk_*:历史测试和探针程序。
不要把 build-artifacts 当成唯一源代码目录。多数文件是从不同历史版本生成的,必须结合时间、文件名和日志判断是否属于当前版本。
4. 硬件和 USB 环境
4.1 设备身份
VID = 0x833C
PID = 0x0001(常见值,具体以设备描述符为准)
分辨率 = 160×120
帧像素数 = 19200
常见帧率 = 15 fps
4.2 Windows 直连端点
| 端点 | 方向 | 用途 |
|---|---|---|
0x03 |
主机到设备 | 命令写入。 |
0x82 |
设备到主机 | 命令响应。 |
0x81 |
设备到主机 | 实时帧。 |
0x84 |
设备到主机 | 大块数据或 DDT 相关读取,当前 demo3 不依赖。 |
4.3 原始帧布局
EP 0x81 数据以固定标记开始:
+0x00 u32 0x1BB1B11B
+0x04 u32 帧计数
+0x08 u32 数据长度,160×120 时为 0x9600
+0x0C u32 帧类型,0 或 1
+0x10 u32 shutter/周期字段
+0x1C 38400 字节像素,19200 个小端 uint16
+0x1C+len u32 0x1BB1B11C
demo3 的第二次 bulk read 直接从 data[0] 读取 38400 字节像素;第一段 28 字节头已在 hdr 中读取。这是曾经修复过的关键偏移问题。
4.4 命令序列
当前设备实测的初始化序列:
0x6BB6B66B,4 字节
0x6BB6B66C,4 字节
0x6BB6B66F,4 字节
0x6BB6B672,参数 0,8 字节,通常连续发送两次
等待约 300 ms
0x6BB6B673,4 字节,启动
停止:
clear_halt(0x03)
clear_halt(0x82)
0x6BB6B674,4 字节
FFC:
0x6BB6B672 + uint32 参数
不要把普通 4 字节命令误写成 8 字节;当前设备对普通命令的 8 字节形式可能 STALL。只有带参数的 FFC 使用 8 字节。
5. 官方 SDK 和反汇编成果
5.1 SDK 文件
原厂 SDK 主要在:
IR_Camera_SDK-1.0.1/windows/windows/app/
IR_Camera_SDK-1.0.1/windows/windows/lib/x64/
IR_Camera_SDK-1.0.1/windows/windows/drivers/
IR_Camera_SDK-1.0.1/android/android/EloThermal/
IR_Camera_SDK-1.0.1/linux/1.2.2/1.2.2/EloThermal/
Windows 关键文件:
CoreSDKLib.dll:底层 MAG API、USB 和渲染主链。ThermalSDK.dll:更高层的热像 API 包装。libusb0.dll:官方旧版 libusb-win32 路径使用。CameraSDK.dll:RGB/UVC 相机接口,不是红外原始帧主通道。
Android/Linux 版本提供了额外符号、JNI、C++ 类名和温度函数线索,对 ARM64 libcoresdk.so 的温度和校正逆向非常有帮助。
5.2 平滑器
通用平滑器函数大约位于 0x1800011a0:
- mode=1:当前 f20 实例使用,逐帧复制输入,不是多帧 EMA。
- mode=2:两帧平均。
- mode=4:累计平均,当前 ref 启动阶段使用。
对象:
dev+0x41ee0:ref 平滑器对象
dev+0x41ef0:ref 实际 uint16 缓冲指针
dev+0x41f10:f20 平滑器对象
dev+0x41f20:f20 实际 uint16 缓冲指针
dev+0x41fd8:ref 相关 mode,实测为 4
dev+0x41fdc:f20 相关 mode,实测为 1
dev+0x41fe0:后续可选处理模式,实测为 1
5.3 官方参考时序
启动帧计数和参数实测:
0x2d78 = 4
0x2d88 = 5
0x2d8c = 4
0x2d90 = 1800
0x2d94 = 250
启动早期的 c620 -> 0x41ee0 推帧会形成 ref。正常处理帧不会每帧重新采集整幅 ref。FFC 会切换 type=1 校准帧,官方应用在这段时间冻结显示。
5.4 官方 NUC 查表
0x180017200 的关键反汇编已经确认:
d2 = ((int)f20[i] - (int)ref[i]) >> 1;
seg = 0;
while (seg < nsegs - 1 && d2 > threshold[i][seg])
seg++;
gain = gainoff[seg][i].gain;
off = gainoff[seg][i].off;
out = off + ((gain * d2) >> 12);
out = clamp(out, 0, 65535);
实测:
nsegs = 3
每像素 threshold 数 = 2
每段每像素是一个 uint16 gain + 一个 uint16 off
gain/off 表总大小 = 3 × 19200 × 4 = 230400 字节
threshold 实际需要 = 2 × 19200 × 2 = 76800 字节
shift = dev+0x11c = 12
本工程通过修复后的 tsdk_pair2.c 抓取 pair_000 表,并用 PowerShell 离线复算:
官方 raw 与表公式重建的平均绝对误差约 0.118 counts
绝大多数像素完全一致
少量最大误差约 900 counts,来自后续盲元补偿尚未复刻
这是当前最可靠的官方 NUC 复刻证据。
5.5 NUC 表生成
相关函数:
0x180016ae0:按 dev+0x54 传感器温度选择端点区间
0x180016dd0:threshold 的 signed Q12 分段插值
0x180016f10:gain/off 的 unsigned Q12 分段插值
0x18000c760:把表重建分成多个 chunk 逐步写入
端点来自 DDT/配置,不来自当前 live、ref 或场景。官方表在启动重建和 FFC 后重建阶段变化;同一个重建组内的连续普通帧通常相同。当前 demo3 使用一组静态官方表,因此 FFC 后和传感器温度区间变化时还不完全等价。
5.6 NUC 后处理
0x180017330 不是全帧 3×3 模糊,而是固定记录表驱动的盲元/坏点补偿:
- 只处理
dev+0x41878指向的固定记录。 - 原地修改
dev+0x270。 - 访问邻域像素并平均或按固定类型替换。
- 没有场景历史,也不负责整幅图去鬼影。
0x18001e920 可能是输出 temporal filter,但当前 dev+0x41fe0=1 时实测路径跳过,不能把它当成官方当前画面的主要鬼影来源。
5.7 窗口、灰度和调色板
- 官方窗口字段约为
dev+0x4202c/dev+0x42030。 - 静态背景最小跨度约 624 counts,即半宽约 312。
- 有热目标时窗口会动态扩大。
dev+0x4284c有 1024 项灰度 LUT。dev+0xb18有 256×4 BGR 调色板。- 同帧重建实验已经证明窗口和 LUT 是当前帧确定性映射,不保存上一帧历史,显示层不是大片鬼影的主要来源。
5.8 官方温度
demo3 采用已从官方提取的 T2E 表:
temp_mC = T2E[3 * nuc - C]
C 约为 5797,实际会话相关
主要代码在 counts_to_temp_mc()。T2E 数据在:
csdk/include/mag160c_official_t2e.hanalysis/t2e_table.jsonanalysis/official_t2e_table.txt
6. 当前 demo3 代码思路
6.1 输入和坏点
decode_live():
- 从第二次 bulk read 的
data[0]解析 19200 个小端uint16。 - 如果启用固定坏点表则执行拓扑填充;当前
BADMAP_ENABLE=0,避免动态场景坏图钉在屏幕坐标。 - 执行
correct_zero_pixels(g_live),修复原始零值。
6.2 参考采集
- 启动 FFC 后等待基线稳定。
REF_INIT_N=12帧采集。- 每像素收集样本并做排序和中间 50% 平均。
- 结果放入
g_ref_mura。 g_ref_mura同时承担固定 mura 图案和启动场景基线,这是当前低温残影的根本风险之一。
6.3 官方表加载
load_official_nuc_tables() 从程序工作目录加载:
mag160c_official_nuc_gain.bin
mag160c_official_nuc_thr.bin
official_nuc_value() 按官方公式选择每像素 segment 并计算输出。
6.4 全局偏置
calibrate_official_ref_bias():
- 每帧抽取每 4 个像素中的一个。
- 对候选 scalar bias 计算官方 NUC 输出直方图中值。
- 二分搜索,使输出中值接近
NUC_CENTER=9804。 - 使用
g_ref_mura + g_official_ref_bias作为查表参考。
这个步骤只跟踪全局漂移,不应把局部场景写进逐像素参考。
6.5 当前 SBNUC 实验分支
当前 SBNUC_ENABLE=1 的实际更新约束:
- 正残差不更新参考。
- 运动期间创新门控保持约 6 帧,不更新参考。
- 负残差需要运动结束后连续 2 帧低于
SB_RECOVER_T=16。 - 还要求该像素之前处于
SB_HOT_RELEASE,也就是曾经为热态、随后离开。 - 低温物体从头到尾的负残差不应进入自愈,避免移开后亮鬼影。
这仍是实验代码。旧的 g_hot_hist、g_sb_prev_d、g_sb_innov_var 等数组和注释中保留了多轮失败方案,后继者应在确认新方案后清理,而不是继续叠加状态。
6.6 设置参考按钮
当前按钮文字是 Recenter bias,对应 WM_COMMAND 的 1004:
- 如果官方表可用,只重新计算全局 bias。
- 不再执行
g_ref_mura[i] = g_live[i]。 - 这是刚修复的严重问题;旧行为会把当前物体温度写进参考,导致设置参考后所有物体趋于相同,挪开后才出现高温/低温差异。
- 没有官方表时才保留旧的 fallback 手动参考行为。
7. 已解决的问题
以下问题在历史实机验证中已经明显改善,不要在没有证据时推翻:
| 问题 | 原因 | 当前处理 |
|---|---|---|
| 颗粒感很重 | demo2 早期 NUC 斜率过大,曾使用接近 3 的斜率 | 当前线性 fallback 为 NUC_GAIN=19,官方表路径已接入。 |
| FFC 后颜色跳变 | FFC 后重新采集场景参考,把场景写进 ref | REF_REINIT_AFTER_FFC=0,type=1 不渲染,使用全局 rebase。 |
| 物体破碎、椒盐 | 固定窗口过窄 | 使用 P2..P98 自适应窗口和最小 624 跨度。 |
| mura 蒙层 | 常数参考或错误平场直接显示传感器固定纹理 | 启动采集 g_ref_mura,并使用逐像素官方 NUC 表。 |
| 中上固定遮蔽 | 动态 badmap 将场景结构钉在屏幕坐标 | BADMAP_ENABLE=0。 |
| 右下炫光 | 把盲元补偿误当全帧 3×3 blur | 删除错误整帧 blur 路径。 |
| 最高温点黑色 | 极值映射和零值处理不稳 | idx >= hi 饱和到 1023,保留零值修复。 |
| 黑洞完全不消失 | 参考冻结且没有任何失配处理 | 当前保留受限的 post-motion self-heal,但仍有速度/误判权衡。 |
| 设置参考后物体被抵消 | 按钮把当前 live 整帧覆盖到 ref | 改为 Recenter bias,不覆盖固定平场。 |
8. 已经尝试且效果不好的路线
8.1 单纯调 SBNUC 全局参数
尝试过:
- 去掉帧差条件。
- 放宽
dd阈值。 alpha从1/64调到1/16。- 统一使用更快负残差步长。
结果:黑洞在某些情况下改善,但小温差或低温物体会被参考吸收,移开后残影回来;过激时画面稳定性变差。
8.2 显示层去鬼影
尝试过:
- 最近热区 mask。
- motion history。
- recent hot mask。
- 显示层邻居替换。
deghost_nuc()。
结果:容易把真实目标抹掉,出现“有地方看不见”的副作用。当前调用被注释,后继者不要重新走这条路线。
8.3 复杂 MOG/自愈状态机
尝试过:
- 逐像素 warm/release 状态。
- 时域创新方差。
- 运动保持计数。
- persistent negative self-heal。
结果:可以在黑洞和鬼影之间移动问题。根本原因是一个 g_ref_mura 同时承载固定平场、场景基线和自适应背景,信息角色混在一起。
8.4 完全冻结参考
效果:热目标鬼影明显减少或消失。
副作用:当场景基线或局部低温发生变化时,旧位置会形成黑洞;黑洞自愈又可能吸收低温物体。这个折中证明需要拆分“固定传感器校正”和“场景背景模型”,而不是继续改一个 ref。
8.5 静态官方表
效果:比单一 0.19 + comp 更接近官方,热目标鬼影有明显改善。
局限:
- 表来自某次官方会话,FFC/传感器温度变化后官方会重新插值。
0x180017330固定盲元补偿没有完整接入。- 表外的参考时序、内部 sensor temperature 和端点配置没有完全复刻。
- 当前静态表不是最终官方复刻。
9. 当前未解决问题和最重要的下一步
9.1 低温长停留残影
现象:
- 低温区域在画面中停留较长时间。
- 参考或负残差处理可能逐渐改变局部基线。
- 物体移动后出现残影,或者黑洞与亮鬼影互换。
最可能的根因:
- demo3 的
g_ref_mura仍然是“固定平场 + 启动场景”混合物。 - post-motion self-heal 对“曾热后变冷”和“从头到尾低温”虽然已区分,但低对比度转换可能漏过状态阈值。
- 官方表当前是静态表,FFC/温度区间变化没有实时重建。
- 官方盲元补偿没有完全复刻,少量异常像素可能形成黑点或局部结构。
- 官方的实际 ref 绝对偏置和 demo3 的
g_ref_mura + scalar bias不是同一个参考定义。
9.2 优先任务 A:复刻官方动态 NUC 表
需要继续做:
- 从
tsdk_pair2_fixed保存的b01/b02/b04/b05端点源表中确认 DDT 端点记录结构。 - 找到 USB 原始帧或设备状态中对应
dev+0x54的传感器温度。 - 按
0x180016ae0、0x180016dd0、0x180016f10的 Q12 整数公式,在 demo3 中按温度插值生成 threshold/gain/off。 - FFC 后重新生成表,但不重新把场景采入空间参考。
- 用多温度、多次 FFC 的官方
b03/b06和raw做逐像素回归。
9.3 优先任务 B:复刻官方盲元补偿
需要从官方活体捕获:
dev+0x41878固定记录表。dev+0x41654对应的记录数量。- 每条记录的目标像素、类型和邻域索引。
然后把 0x180017330 的原地邻域补偿接到官方 NUC 表输出后。不要使用由场景动态生成的 badmap。
9.4 优先任务 C:拆分参考角色
推荐最终数据结构:
g_fixed_pattern[i] 只保存传感器固定空间校正
g_scene_reference[i] 可选、严格受状态控制的场景背景
g_global_ref_bias 全局传感器/FFC 漂移
g_official_nuc_table 官方温度配置表
当前 g_ref_mura 不应继续同时承担上述所有角色。
9.5 优先任务 D:受控实验数据
必须抓以下序列,每个序列至少 60 帧,最好包括 live/ref/raw/gain/thr/gray:
- 空背景稳定 10 秒。
- 热目标进入、停留、离开、空背景恢复。
- 冷目标进入、停留、离开、空背景恢复。
- 小温差热目标重复移动。
- FFC 前后同一目标序列。
对每个像素同时画:
live
ref
live-ref
d2
official raw
demo3 raw
gray
不要只看 BMP。BMP 只能说明最终表现,不能定位残影是在 USB、ref、NUC、盲元补偿还是窗口阶段产生。
10. 环境安装和部署
10.1 当前开发环境
当前主要环境是 Windows PowerShell:
工作目录:C:\Project\MAG160C
MinGW GCC:C:\mingw64\bin\gcc.exe
GCC 版本:曾使用 14.2.0
Python:用于 PDF、二进制和逆向辅助
Java:Zulu 21,用 javap 查看 Android 类
Git:用于提交和远端同步
Git LFS:用于大型二进制
10.2 必装工具
建议安装或确认以下工具:
- MinGW-w64,要求
gcc、g++、ar、objdump、readelf、strings、dlltool、gendef可用。 - Git。
- Git LFS。
- Python 3.10 或更新版本。
- Java 21 或可用的
javap,仅在需要分析 Android JAR/AAR 时使用。 - PowerShell 5.1 或 PowerShell 7。
- 可选:CMake。当前环境中
cmake不在 PATH,因此实际验证主要使用 GCC 直接命令。 - 可选:Wireshark 4.6.7 和 USBPcap 1.5.4,用于 USB 抓包。
- 可选:Zadig,用于切换 WinUSB/libusb-win32 驱动。
10.3 Python 逆向包
历史上使用过:
capstonepyelftoolspdfplumber
工程中已有 .tools/python-revlibs/,不要假设系统 Python 一定有这些包。需要时可以先检查:
python --version
python -c "import capstone, elftools; print('逆向 Python 包可用')"
10.4 SDK 和 DLL
原厂文件已经随工程提供,通常不需要再次下载:
IR_Camera_SDK-1.0.1\windows\windows\app\CoreSDKLib.dll
IR_Camera_SDK-1.0.1\windows\windows\app\ThermalSDK.dll
IR_Camera_SDK-1.0.1\windows\windows\app\libusb0.dll
IR_Camera_SDK-1.0.1\windows\windows\lib\x64\CoreSDKLib.dll
IR_Camera_SDK-1.0.1\windows\windows\lib\x64\ThermalSDK.dll
csdk\third_party\libusb\win64\libusb-1.0.dll
csdk\third_party\libusb\win64\libusb-1.0.x64.a
官方 ThermalSDK.dll 路径和 demo3 的 libusb-1.0 路径不要混用。官方程序通常依赖 libusb0.dll/libusb-win32;demo3 使用 libusb-1.0.dll 和 MinGW 导入库。
10.5 驱动注意事项
曾经验证过的 Windows 组合:
- 原厂旧驱动签名在新 Windows 上可能失败。
- Zadig 安装 WinUSB 或 libusb-win32 后,设备才能被对应程序打开。
- 官方 DLL、TI 的 64 位
libusb-1.0.dll、WinUSB/libusb-win32 的组合行为不同。 - 不要在官方程序、
tsdk_pair2和 demo3 同时占用设备。 - 如果出现
no channel、STALL、设备不枚举,先停止所有程序并重新插拔 USB。
11. 构建和启动
11.1 demo3 当前编译命令
在 PowerShell 中执行:
注意:命令只允许出现一次 mag160c_error.c。重复传入会出现 multiple definition 链接错误。
11.2 启动 demo3
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
Start-Process "C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe" -WorkingDirectory "C:\Project\MAG160C\build-artifacts"
官方 NUC 表文件必须和 exe 在同一个工作目录中:
build-artifacts\mag160c_official_nuc_gain.bin
build-artifacts\mag160c_official_nuc_thr.bin
如果缺失,程序会退回旧的线性 NUC 路径,画面和残影表现不能与当前版本比较。
11.3 停止 demo3
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
必须先停止 demo3 才能运行官方 ThermalSDK 抓帧工具。
11.4 编译修复后的官方抓帧工具
tsdk_pair2.c 原来先保存真实指针表,后面又覆盖同名 .gain/.thr。当前修复版把后面的内联字段改存为 .gain_inline/.thr_inline。
11.5 官方抓帧
先确认输出目录父目录存在,再执行:
New-Item -ItemType Directory -Path "C:\Project\MAG160C\analysis\pairs_recheck_20260811" -Force
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
& "C:\Project\MAG160C\build-artifacts\tsdk_pair2_fixed.exe" "C:\Project\MAG160C\analysis\pairs_recheck_20260811" 12 6000
参数含义:
参数 1:输出目录
参数 2:抓取 pair 数
参数 3:官方 SDK 初始化等待毫秒数
tsdk_pair2.c 当前会在约三分之一和三分之二位置触发 FFC,适合验证 FFC 表变化,不适合完全无干预的纯运动实验。要做低温残影实验,建议另写不自动触发 FFC 的 harness。
11.6 日志和图像
demo3 工作目录下:
日志文件由程序重新启动时以写模式打开,重启会覆盖旧日志。要保留一轮实验,先复制到 analysis/ 并改名。
12. C SDK 构建和验证
如果已经安装 CMake:
cmake -B build -S csdk
cmake --build build
ctest --test-dir build
当前机器没有 CMake 时,按照 csdk/WINDOWS_TESTING.md 使用 MinGW 直接编译。无硬件时可以验证:
build-artifacts\csdk_cli_libusb.exe frame-test
build-artifacts\csdk_cli_libusb.exe temp-test
build-artifacts\csdk_cli_libusb.exe tcm-rotate 5
build-artifacts\csdk_cli_libusb.exe tcm-light green blink
build-artifacts\csdk_cli_libusb.exe ir-info
预期 TCM 编码结果示例:
7e 00 07 85 02 77 00 01 00 05 7f
13. Git 和仓库维护
本工程原先只有空的 .git 目录,不是有效 Git 仓库。本次移交应初始化真实 Git 仓库并推送到:
https://git.zxcli.top/zxc/MAG160C.git
仓库约 0.824 GB,包含大量 DLL、EXE、APK、PDF、PNG、BMP、抓帧和反汇编二进制。已准备 Git LFS 规则。提交前必须检查:
不要把账号密码、访问令牌、私钥写入文档或代码。原厂 SDK 和 APK 可能受第三方许可限制,仓库接手者应确认仓库访问权限和内部使用范围。
14. 当前接手者的建议工作顺序
第一步:确认环境和版本
- 阅读本文、
analysis/handoff_20260813.md、analysis/handoff_20260811_full.md。 - 检查
git status和远端分支,确认没有并行改动。 - 检查设备 PID、驱动、DLL、表文件。
- 编译并启动当前 demo3,保存一轮不移动时的日志。
第二步:验证当前路径是否真的加载官方表
- 暂时把
mag160c_official_nuc_gain.bin改名,启动一次并记录 fallback 画面。 - 恢复表文件,再启动并记录官方表画面。
- 比较
demo3_diag.txt中g_sb_shift、NUC 统计和 BMP。 - 不要用缺失表文件的 fallback 版本评价当前算法。
第三步:做官方和 demo3 同帧采集
- 停 demo3。
- 用修复后的官方工具抓取至少 60 帧,不要自动触发 FFC。
- 保存 f20、ref、raw、gain、thr、gray、window、blind compensation 记录。
- 用脚本逐像素对比官方 raw 和 demo3 raw。
第四步:优先修官方动态表和盲元补偿
不要先改调色板、窗口、显示层。官方证据已经说明这两个阶段没有上一帧历史,低温残影优先查 ref、gain/off、threshold、FFC 表重建和盲元补偿。
15. 给下一位 AI 的接手提示词
下面的提示词可以直接复制给下一位 AI。它要求 AI 先理解工程,再动手,不要从头重做,也不要反复尝试已经失败的显示层补丁。
你现在接手 C:\Project\MAG160C 的 MAG160C 热像仪逆向工程。
设备:MAG160C,160x120,USB VID 0x833C,常见 PID 0x0001。
主程序:C:\Project\MAG160C\csdk\tools\mag160c_demo3.c
输出程序:C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe
官方 DLL:IR_Camera_SDK-1.0.1\windows\windows\app\CoreSDKLib.dll 和 ThermalSDK.dll
远端仓库:https://git.zxcli.top/zxc/MAG160C.git
严格执行以下步骤:
1. 先读:
- 交接_完整逆向工程说明_20260811.md
- analysis/handoff_20260813.md
- analysis/handoff_20260811_full.md
- analysis/protocol_spec.md
- csdk/tools/mag160c_demo3.c
- csdk/tools/tsdk_pair2.c
2. 再检查:
- git status --short --branch
- build-artifacts/mag160c_official_nuc_gain.bin
- build-artifacts/mag160c_official_nuc_thr.bin
- analysis/pairs_recheck_20260811/
- analysis/disasm/
3. 先理解已经确认的官方事实:
- EP 0x03 是命令 OUT,EP 0x82 是响应 IN,EP 0x81 是帧流。
- 帧 marker 是 0x1BB1B11B,像素从帧内 +0x1c 开始,160x120 uint16 LE。
- f20 平滑器 dev+0x41f10 当前 mode=1,正常帧基本直接复制,不是隐藏 EMA。
- ref 在 dev+0x41ef0,启动/FFC 平滑器 mode=4 形成,正常显示帧不逐帧重采集。
- NUC 0x180017200 使用 d2=(f20-ref)>>1、每像素两个 signed threshold、三段 gain/off、Q12 乘法和 clamp。
- 0x180017330 是固定盲元邻域补偿,不是全帧 3x3 blur。
- 0x18001e920 当前 mode=1 通常跳过,不要假设官方有开启的 temporal filter。
- 官方 gain/off/threshold 表由传感器温度、DDT 配置和 FFC 重建生成,不读取 scene/live/ref。
4. 当前 demo3 的真实状态:
- 已接入一组官方活体抓取的静态 gain/off/threshold 表。
- 用输出域中值反求全局 ref bias。
- SBNUC 只允许曾经热、后来负残差的像素自愈;低温从头到尾的负残差不应更新参考。
- 显示层 deghost_nuc() 不调用,BADMAP_ENABLE=0,窗口、LUT、palette 不要随意改。
- 低温区域长时间停留仍有残影,说明问题尚未解决。
5. 当前首要研究目标:
- 查清低温静止目标的残影是在 raw/live、ref、d2、官方 gain/off、盲元补偿还是窗口前产生。
- 不能只看 BMP;必须逐像素保存和比较 live/f20/ref/d2/raw/gray。
- 建立官方和 demo3 的 60 帧以上同场景数据集,覆盖热目标和冷目标。
- 复刻官方 gain/off/threshold 温度端点插值和 FFC 后表重建。
- 复刻固定盲元补偿记录表,不能用场景动态 badmap 代替。
6. 已经失败、不要盲目重复的路线:
- 显示层 motion history、recent hot mask、邻域替换。
- 单纯把 SBNUC 全局 alpha 调快。
- 把所有负残差都快速写回参考。
- 把所有正负残差都用一个 MOG 参考吸收。
- 随意修改窗口、调色板、FFC 周期和 BADMAP_ENABLE。
7. 修改原则:
- 先保留当前已验证的官方查表、窗口、LUT、palette 和 USB 链路。
- 只在有反汇编或抓帧证据的地方修改。
- 不回退用户已经确认有效的修复。
- 所有手工编辑使用 apply_patch。
- 修改后使用用户给出的 GCC 命令编译,并启动 demo3 让用户实测。
- 不要声称“已修复”,除非有用户实机反馈或可复现的同帧数据证据。
8. 编译命令:
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
9. 启动命令:
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
Start-Process "C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe" -WorkingDirectory "C:\Project\MAG160C\build-artifacts"
10. 你的第一条回复不要直接提方案。先返回:
- 你读过的文件。
- 当前官方链路理解。
- 当前 demo3 链路理解。
- 低温残影的证据缺口。
- 下一轮最小可验证实验。
然后再开始修改或抓帧。
16. 交接结束条件
下一位接手者在以下条件都满足前,不应把项目标记为完成:
- 官方和 demo3 的 60 帧以上同帧 raw/ref/NUC 对比完成。
- 热目标和冷目标的进入、停留、离开都没有明显残影。
- FFC 前后表重建、窗口和显示冻结行为与官方一致。
- 固定盲元补偿记录已复刻,异常零点和少量极端 outlier 消失。
- 不依赖显示层遮罩,不牺牲真实目标,不产生黑洞。
- 用户在实机上确认低温和小温差场景都达到可接受效果。