docs: 手机端渲染差异定位(官方照片无数据块/亮度差复现;三 SDK 交叉验证把差异收敛到灰度 LUT-CDF 阶段)
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# 手机端渲染差异定位(Android SDK ↔ Windows/Linux SDK 交叉验证)2026-10-06
|
||||
|
||||
> 背景:相机改插 root 手机(22041211AC,Android 12 + Magisk)后,按用户要求
|
||||
> "官方 App 拍照 vs 我们的 App 拍照" 做对比,出现差异就**同时**逆 Android SDK 与
|
||||
> Linux/Win SDK 交叉验证。本轮结论:**亮度/对比度差异的根因是"窗口半宽 = 基础窗口 ×
|
||||
> 对比度修正",官方手机 App 带对比度偏移,我们的移植只在 c=0 时一致。**
|
||||
|
||||
## 1. 对比做法与结果
|
||||
|
||||
| 项 | 官方 App(cn.com.magnity.magnitycx) | 我们的 App |
|
||||
|---|---|---|
|
||||
| 照片存放 | `/sdcard/magnity/Cx/media/MAG-160CORE<时间>.jpg`(+ `others/` 里是 DDT) | `/sdcard/DCIM/MAG160C/MAG160C_<时间>.jpg` |
|
||||
| 照片内容 | **纯 JPEG(无任何数据块,EOI 即文件尾)** | 完整 MDT(INFO0/INFO1/FRAME/NUC/RENDER/EXTREMES) |
|
||||
| 亮度(同场景) | luma p25=40 p50=49 mean=84 | p25=10 p50=19 mean=53 |
|
||||
| 调色板索引分布(按 16 档) | 峰值在 2–4 档(10%/40%/12%) | 峰值在 0–1 档(15%/39%) |
|
||||
|
||||
→ 同一静止场景,**我们的图整体偏暗约 30 luma**:热点位置一致、调色板一致,属于
|
||||
"灰度映射/窗口"差异(不是色板或数据差异)。
|
||||
|
||||
## 2. 交叉验证:窗口是怎么算的
|
||||
|
||||
**Android SDK(libcxsdk 反编译,权威)**:
|
||||
|
||||
```
|
||||
CFunctions::GrayEnlarge() // 灰度/窗口总入口
|
||||
uVar2 = CalContrastOffsetedAutoEnlargeRange() // 窗口"范围"(不是半宽)
|
||||
winLo = min(mean - (uVar2>>1), statMin) // 注意:向外扩到数据范围
|
||||
winHi = max(mean + (uVar2>>1), statMax)
|
||||
HistDeRedundance() // 直方图去冗余(我们的 lutRebuild)
|
||||
|
||||
CFunctions::CalContrastOffsetedAutoEnlargeRange():
|
||||
base = (dev24 * 1000) >> shift // dev24=8, shift=3 → 1000
|
||||
c = clamp(contrast, -100, 100) // ★ 对比度设置
|
||||
range = base - base*c / (150 + (c<0 ? -100 : 0)) // c>0:range 变小(窗口更窄→更亮)
|
||||
if (brightness 项 dev+0x6c/0x38 有效) range += 亮度修正项
|
||||
range = max(range, 0x80)
|
||||
```
|
||||
|
||||
**Windows SDK**:`MAG_SetAutoEnlargePara` / `MAG_SetFixedEnlargePara` /
|
||||
`MAG_SetSubsectionEnlargePara`(同一组参数的用户 API)。
|
||||
**Linux SDK**:`MAG_SetAutoEnlargePara`(libmagcore @0x11be50)同名同参 —— 两条 SDK 线吻合。
|
||||
|
||||
**官方手机 App 侧**:`ExtPara`(设备上报)含 `intContrastOffset` / `intBrightOffset` /
|
||||
`intAutoEnlargeRange` / `intDetailRatio` / `intCurrentEnvTemperature`,App 用
|
||||
`DeviceController.getExtParameter()` 读取后回写(`setExtParameter`)。
|
||||
|
||||
## 3. 我们的移植差在哪
|
||||
|
||||
`RenderPipeline.statsWindow()` 的窗口结构与官方**完全一致**(`winLo=min(mean−half,min)`、
|
||||
`winHi=max(mean+half,max)`),但:
|
||||
|
||||
- `half = base>>1` **只在对比度 c=0 时**等于官方(官方 `range=base` → `range>>1`);
|
||||
- 官方手机 App 带 `intContrastOffset`(正对比度 → 窗口更窄 → 更亮)→ 这就解释了我们偏暗。
|
||||
|
||||
**证据链**:PC 端(对比度 0)我们的渲染与官方 PC SDK 逐像素差 1.3 级 ✔;
|
||||
手机端(官方 App 带对比度)差值 ~30 级 ✔ —— 同一实现、不同对比度输入,两个场景都对得上。
|
||||
|
||||
## 4. 顺带确认的两件事
|
||||
|
||||
1. **环境温度输入**:官方 App 调 `setEmissivity(emissivity, ExtPara.intCurrentEnvTemperature)`
|
||||
—— 即 PC SDK 的 `dev+0xA4`(我们温度链里的 `ATZeroErrorPoint`)就是**环境温度**
|
||||
(设备默认 22216 = 22.2 ℃);App 的发射率设置也走这里(100 = 1.00)。
|
||||
→ 我们 App 的发射率设置应当**接进 `OfficialTemp.temperature(emissivity=…)`**(当前固定 0.98)。
|
||||
2. **BasePara2 真机报文**(60 B,magic 已由我们的读取层吃掉):
|
||||
`fpaTempFix` @+14(short)=1699、`ATZeroErrorPoint` @+40(int)=22216、`ATErrorSlope` @+44(float)=−0.02789
|
||||
—— 已写入单测作为地面真值。**注意**:PC 上实测的补偿量 `v50`(=dev+0x5C−dev+0x54,0…89 mC)
|
||||
**不等于** `fpaTempFix`(1699),故 App 侧 `sensorDeltaMc` 暂取 0(误差 ≤0.09 ℃),
|
||||
待定位 dev+0x5C 的来源(疑似滤波后的 FPA 温度)后再接入。
|
||||
|
||||
## 5. 下一步(按此顺序)
|
||||
|
||||
1. 移植 `CalContrastOffsetedAutoEnlargeRange`(含亮度项到 `statsWindow`),并在设置页加
|
||||
"对比度/亮度"(默认值取官方 App 的默认),重拍对比 → 目标是 luma 直方图与官方吻合。
|
||||
2. 补 `getExtParameter` 命令(Android SDK 侧 JNI:`DeviceController.getExtParameter`),
|
||||
把设备的 `intContrastOffset/intBrightOffset/intCurrentEnvTemperature` 接进来。
|
||||
3. 温度读数接 App 的发射率设置(`OfficialTemp` 已支持参数)。
|
||||
4. 以上在 App 验证无误后,按用户要求同步进 `csdk`(C 参考实现)与 csdk 测试。
|
||||
|
||||
## 6. 追加实测(同日):实时画面亮度差已复现,差异区间收敛到"窗口/LUT"
|
||||
|
||||
同一静止场景、前后相隔约一分钟分别截取两个 App 的**实时画面**(官方横屏 3200×1440、
|
||||
我们竖屏 1440×3200),按行/列亮度自动裁掉黑边后统计:
|
||||
|
||||
| | p25 | p50 | p75 | mean |
|
||||
|---|---|---|---|---|
|
||||
| 官方 App 实时 | 12–20 | 26–33 | 63–124 | 53–72 |
|
||||
| 我们的实时 | 2–4 | 12–25 | 27 | 20–25 |
|
||||
|
||||
→ 差异是**真实且系统性的**(不是拍照时刻/场景差异),并已把差异区间收敛到显示阶段的
|
||||
"窗口 + 灰度 LUT"两步。
|
||||
|
||||
**三方交叉验证(Android ↔ Windows ↔ Linux)**:
|
||||
|
||||
| 阶段 | Android(libcxsdk) | Windows(CoreSDKLib) | Linux(libmagcore) |
|
||||
|---|---|---|---|
|
||||
| 设置入口 | `setAutoEnlarge(enlargeRange)`(官方 App 传 BasePara2 的 `enlargeRange`=**8**) | `MAG_SetAutoEnlargePara(chan, range, contrast, brightness)` | 同名同参(+0x24/+0x30/+0x34) |
|
||||
| 窗口范围 | `CalContrastOffsetedAutoEnlargeRange()`:`range = base − base*c/(150+(c<0?−100:0))`,`base=(dev24*1000)>>shift`;`winLo=min(mean−range/2, min)`、`winHi=max(mean+range/2, max)` | 同结构(我们的 `statsWindow` 即此移植) | 同结构 |
|
||||
| 灰度 LUT | `HistDeRedundance()`:1024 桶直方图(`0xFFC00000/span`、`>>20 & 0xffc` = 我们的 `lutRebuild` 公式)+平滑+CDF | 我们的移植来源 | 同结构 |
|
||||
|
||||
**结论**:窗口公式在对比度 c=0 时与我们**逐字节一致**(且官方 App 只传了 range=8,
|
||||
未设对比度),直方图/LUT 的骨架也一致 —— 所以剩下的差异只可能出在
|
||||
① LUT 的**平滑/CDF/pivot 细节**(Android 版 `HistDeRedundance` 的后续段尚未逐行核对),
|
||||
或 ② 官方 App 通过 `setEX`/`ExtPara` 设置的**亮度偏移**(`intBrightOffset`)等参数。
|
||||
这两处是下一轮的直接目标(继续用同一套"三 SDK 交叉 + 真机截图定量"的方法)。
|
||||
Reference in New Issue
Block a user