diff --git a/docs/android_app/rendering_diff_phone_20261006.md b/docs/android_app/rendering_diff_phone_20261006.md index fc2f653..a5c4c50 100644 --- a/docs/android_app/rendering_diff_phone_20261006.md +++ b/docs/android_app/rendering_diff_phone_20261006.md @@ -599,3 +599,82 @@ JPEG 只能解释一部分:把我们那张(960×720 q95,202 KB)按 640× → 修好后我们**比官方更平滑**(官方因最近邻 4× 反而有 4 像素大块,见 x8 放大对照图)。 单测 119 全绿(`PhotoNucMappingTest` 更新为 160×120→960×720 的新策略)。 + +## 16. 「官方背景条纹更不明显」——逆向排除全部候选后,定位为**我们独有的逐行固定偏移**(2026-10-06 深夜,交接轮) + +用户发了同场景双截图(官方 vs 我们,均为竖屏、12 px/传感器像素、同一调色板铁虹)并要求 +"看逆向出来的代码是不是还漏了什么"。本轮做了两件事:把官方每帧链路逐条再对一遍(IDA 批量 +反编译),并对两台 App 的显示结果做**调色板弧长反演**的定量对比。**结论:每帧算法没有遗漏; +差异是一个官方没有、我们有的"逐传感器行固定偏移"(残余行 FPN,显示上就是水平条纹)。** + +### 16.1 逆向再核对(libcxsdk = 普通版 MAG-Cx 的 SDK,全部读反编译原文) + +- **内参来源定案**:`Controller::StartProcess(cb, w,h,sn,devType, close,open, ffcFrame,ffcTemp, palette, baseLineAcc, cali)` + 只写 Controller+0x28(w)/+0x2c(h)/+0x18(palette)/+0x40(baseLineAcc),其余字段保持 + `Controller::Controller()` 的默认:+0x44=**1**、+0x48=**1**、+0x4c=5。 + 映射到 CFunctions:0x3804=baseLineAcc=**4**、0x3808=**1**(温度累积器**旁路**)、 + 0x380c=**1**(**CSmoother 关**)、0x3810=5。→ 官方手机链路**没有**平滑器/累积器, + 之前 §8/§9/§10 的结论不用改。 +- **每帧链路** = `Calibration`(DDT 有效时走 `CalibrationMain_RTV`: + `d=(raw−base)>>1` → 按段阈值选 `(gain,off)` → `(d*gain>>12)+off`,clamp 0..0xffff) + + `BlindCompensation`(盲元按 3..8 邻域均值替换,DDT 盲元表) + Mirror(关) + + `TempRangeStat` + `GrayEnlarge`(内含 `HistDeRedundance`)。E2X/E4X 仅当 EX≠0 + (App imageEX=0),`FilterDetailEnhancement(_Simple)` 仅当 CFunctions+0x28≠0 + (**从未被写**=0)。→ 与我们的实现一一对应,**没有缺的阶段**。 +- **标定表只在 FFC 窗口重建**:`DoSomething(param_1==0)`→`SelectCaliCurve`+ + `GenerateVolatileLens`;param_1≥1 时在窗口各帧**分块** `InterpolateShort/UShort` + (块大小按 `(13+总字节+尾-2)/(13-1)+7&~7`,完成后置 0x2d24=1)。不在每帧跑 → + 我们"FFC 时 rebuildTables"一致。 +- **FFC 时序逐帧一致**:触发→cb(0) 关快门 →帧 1..5→帧 6..9 逐帧 `PushBaselineRaw` + (首帧 Restart,4 帧块平均)→**第 9 帧回调 cb(1) 开快门**→帧 10..13 DoSomething→帧 14 起正常。 + 我们的状态机(idx 1..5 / 6..9 / idx==9 onFfc(1) / 10..13)完全同相。 +- **设备配置命令**:`setFrameRate`(P2D_SetFrameRate=0x6BB6B679,载荷 interFrame/interLine + 两个 u32;fpsMode 0→9/12,否则 105/105)只在 **devType 1/2** 时发;我们 devType=**3** + → 官方也不发。`P2D_SetParameter1/2` 官方 USB 路径只发 Get。→ 原始流配置两边相同。 +- **工具链记录**:普通版 APK=`app/【普通版】MAG-Cx.apk`(libcxsdk.so 372KB armeabi, + md5 4d8d98bb…,与 analysis/sdk_re/android_app/bin 相同;JNI 层是 libcxx2java.so 67KB)。 + `analysis/ida/libcoresdk_arm64.so` 是**专业版 MAG-Mx** 的库,别拿它推普通版 + (它的 0x439d80/88 内参在 .bss,文件里读不到)。IDA Pro 9.4 批量反编译命令: + `idat.exe -A -S"" -L"" `(脚本按 `get_next_func` 遍历; + 对 `__imp__` 导入 thunk 会异常中断,注意跳过;Ghidra headless 兜底)。 +- `test_frames.bin` 夹具是合成/重复帧(60 帧 mean/std 完全相同),**不能**用于噪声分析。 + +### 16.2 定量对比(调色板弧长反演,脚本在 %TEMP%\mag160c_re\analyzer.py,临时件) + +方法:ironbow 256 色表(VendorPalettes)→ RGB 弧长参数化(消除调色板斜率影响)→ +12 px/传感器像素块中值采样到 160×120 → 3×3 高通。数据:用户双截图(竖屏)+ +真机连拍 3 帧(官方横屏 crop、我们竖屏,均 PNG 截屏无 JPEG 伪影)。 + +| 指标(弧长单位 ×1e-2) | 官方 | 我们 | 比值 | +|---|---|---|---| +| 整图低频 σ(对比度/音调曲线) | 20.2 | 21.2 | 1.05(一致) | +| scene(>8px) σ(真实场景对比度) | — | — | 0.95~0.97(一致) | +| 高频 σ(单帧 1~8px 频带) | 1.16~1.21 | 2.10~2.51 | **~2×** | +| 时间分量(连拍差分/√2) | 0.52 | 0.75 | 1.44× | +| **沿显示水平线均值的 std(=逐传感器行固定偏移)** | **0.106~0.15(max 0.57)** | **1.20~1.84(max 12.1)** | **8~17×** | + +分块统计(背景块):scene 比 0.95、1-8px 频带比 1.58、时间比 2.0 —— 我们多出来的 +能量集中在 1~8px 频带且**逐帧可复现(固定)**。 + +### 16.3 结论与交接(下一步) + +- **缺陷**:我们的渲染里有一个官方没有的**逐传感器行固定偏移**(残余行 FPN)。 + 显示旋转 90° 后,传感器行=屏幕水平线 → 就是用户看到的"背景条纹"。 + 它是固定的(连拍均值里都在),所以不是每帧算法、也不是显示插值(两边显示链等价: + 都是 160×120 数据 → 12 px/px 双线性上屏)。 +- **候选(按嫌疑排序)**: + 1. FFC 参考帧被污染/时序错位:官方与我们都"关 5 帧→采 4 帧→第 9 帧开",但我们的 + 帧计数从自己的处理循环来;USB 抖动/丢帧会让采集窗错相(§9.4 曾测得 + "延到 8 帧反而变差"——设备实际快门相与我们假设的错位的旁证)。 + 参考≠纯快门帧 → 减出的残差里留下行结构。 + 2. DDT 段表 (gain,off) 的布局/插值在当前 FPA 温度下与我们不一致 + (我们 `rebuildTables(shutterAtFfc + fpaTempFix)`;官方 `SelectCaliCurve` 的温度 + 来源、端点选择、Interpolate 的语义需要逐字段比对)。 + 3. 盲元处理差异(我们已实现 `nucAndBlind`,但要和官方 `BlindCompensation` 的 + 邻域定义逐条对——它用 10 int/条 的记录、邻居偏移含 ±1 与 ±行距)。 +- **验证路径(下一个模型从这里接)**: + 1. App 加"原始帧录制"开关(IrSession 读线程帧入口处写 files/,含一次完整 FFC 的 + 60+ 帧与帧头);真机录一段。 + 2. 离线重放:raw → 参考 → NUC → 表插值 → LUT,**每一级都算"沿行均值 std"**, + 找出引入行偏移的那一级;再用录到的数据做 A/B(改窗口/改表温度/改盲元)复现官方数值。 + 3. 真机 A/B 验收指标就用 16.2 的表:目标"逐行固定偏移 std ≤ 0.2"。 diff --git a/docs/android_app/session_state.md b/docs/android_app/session_state.md index c3f66fe..8e22c57 100644 --- a/docs/android_app/session_state.md +++ b/docs/android_app/session_state.md @@ -489,6 +489,27 @@ "未连接"分支显示,正常出图时用户看不到任何反馈)。 - [x] 单测 66 → **76 项全绿**;debug + release(R8) 双构建通过;APK 已更新。 +## 用户反馈修复 第三十七轮(2026-10-06 深夜,"官方背景条纹更不明显"——逆向排除全部候选,定位为逐行固定偏移;交接轮) + +用户:"很明显啊,官方背景里面的条纹就是要更不明显,你看看逆向出来的代码,是不是还漏掉了什么"。 +本轮**只做了调查与测量,无代码改动**。完整证据与数据表见 +`docs/android_app/rendering_diff_phone_20261006.md` §16,交接清单也在那里(16.3)。 + +- 逆向:官方每帧链路(CalibrationMain_RTV + BlindCompensation + TempRangeStat + + GrayEnlarge/HistDeRedundance)、内参(0x3808=1、0x380c=1、0x3804=baseLineAcc=4、 + 0x3810=5、EX=0、增强=0)、FFC 时序(关5→采4→第9帧开)、表只在 FFC 窗口重建、 + setFrameRate 仅 devType1/2 —— 全部与我们一致,**没有遗漏的阶段**。 +- 测量(调色板弧长反演 + 真机连拍):对比度一致;高频噪声我们 ~2×;**主导项是 + "逐传感器行固定偏移":我们 std 1.2~1.84(max 12.1)vs 官方 0.11~0.15(max 0.57)**。 +- 下一步(按序):① app 加原始帧录制(含 FFC 窗口)→ ② 离线逐级重放找引入行偏移的级 + (参考帧污染/表插值温度/盲元邻域)→ ③ 修复后用 §16.2 指标验收(逐行 std ≤ 0.2)。 +- 现场状态:热像仪已被用户拔下充电;手机 rotation 被我锁成竖屏 + (`su -c 'settings put system accelerometer_rotation 0'`,原值 1,**测完要恢复**); + 官方 App 已 force-stop,我们的 App 在前台(USB 权限对话框"确定"在 (1193,1897), + 勾选框未勾,"一律打开"关联仍指向官方)。 +- 工具痕迹:`%TEMP%\mag160c_re\`(IDA 批处理脚本、libcsxx 反编译、analyzer.py、 + 截图与 npy 中间件)——按约定属临时件,可删。 + ## 用户反馈修复 第三十六轮(2026-10-06 夜,"我们颗粒更大"→ 照片改单级放大,实时回退插值) 用户:"我们的app图片看起来像素颗粒更大啊,特别是高低温分界的边沿,是不是啥滤波没开。"