app+csdk+docs: 按反汇编定案修复——官方安卓路径无 160→320 插值级(ImageViewer 无 FILTER_BITMAP 最近邻放大),我们的双线性 2× 自造交错细纹;实测冷区细条纹比 1.16/1.29→1.00/0.93,csdk 同加 upscale_nearest,119 单测全绿

This commit is contained in:
ZXCLI
2026-10-06 17:09:00 +08:00
parent 0be75fa8c3
commit 4a3916a2b7
10 changed files with 188 additions and 1 deletions
+4
View File
@@ -301,6 +301,10 @@ build-artifacts\csdk_test_display.exe
同场景照片逐像素平均差 4.5/255、逐计数中位差 2 级,见 §10/§11)。
⚠️ **本机没有 C 编译器**(gcc/clang/NDK 都没有),所以这段 C **未编译**——
算法本身由 Kotlin golden 测试锁定,合入前请在带编译器的环境编译 + 跑回归。
- 同一节还有个 `upscale_nearest`:官方**安卓**路径没有 160→320 的插值级
(SDK 给 App 的位图就是 160×120,App 用 `new Paint(1)`(无 FILTER_BITMAP)最近邻放大),
而 PC 版的双线性会展出一层"全幅/半幅"交错细纹(暗/低温区最明显)。
真机实测:冷区细尺度列条纹比 1.16/1.29(双线性)→ **1.00/0.93**(最近邻)。
- 顺带(同一条链):**曲线插值温度要加 `BasePara2.fpaTempFix`**。官方 App 传给 SDK 的是
`帧尾 FPA + fpaTempFix`(真机 1699),`SelectCaliCurve`/`GenerateVolatileLens`
用它选/插值每像素标定表;温度换算链路仍用帧尾原值。C 侧**已实现**
+8
View File
@@ -60,6 +60,14 @@ typedef struct mag160c_render_cfg_t {
int fpa_temp_fix;
/* Brightness offset for the Android LUT base; the official app passes 0. */
int lut_brightness;
/* 1 = replicate pixels in the 160x120 -> 320x240 stage instead of interpolating.
The official ANDROID path has no such stage at all (its SDK hands the app a
160x120 bitmap which ImageViewer draws with a non-filtering paint = nearest),
while the PC SDK's bilinear version fabricates an interleaved full/half
amplitude column pattern at the sensor Nyquist - visible as extra fine stripes
in the dark/cold regions. Measured on device: fine-scale cold-region stripe
ratio vs the official 1.16-1.29x (bilinear) -> 1.00/0.93 (nearest). */
int upscale_nearest;
mag160c_render_ffc_cb_t ffc_cb;
void *ffc_user;
mag160c_render_post_nuc_cb_t post_nuc_cb;
+15 -1
View File
@@ -59,7 +59,7 @@ struct mag160c_render_t {
mag160c_render_post_gray_cb_t post_gray_cb;
void *post_gray_user;
int ffc_period, ffc_drift, warm_frames, cdf_pivot_75, force75;
int android_lut, fpa_temp_fix, lut_brightness;
int android_lut, fpa_temp_fix, lut_brightness, upscale_nearest;
};
static int counts_to_temp_mc(int counts) {
@@ -524,6 +524,19 @@ static void upscale2x(mag160c_render_t *r) {
const unsigned char *s = r->gray160;
unsigned char *o = r->gray320;
int W = r->w, H = r->h, W2 = W * 2;
if (r->upscale_nearest) {
/* Android parity: no interpolation stage (see mag160c_render.h) */
for (int y = 0; y < H; ++y) {
const unsigned char *row = s + y * W;
unsigned char *o0 = o + y * W2 * 2, *o1 = o0 + W2;
for (int x = 0; x < W; ++x) {
unsigned char v = row[x];
o0[x * 2] = v; o0[x * 2 + 1] = v;
o1[x * 2] = v; o1[x * 2 + 1] = v;
}
}
return;
}
for (int y = 0; y < H - 1; ++y) {
const unsigned char *r0 = s + y * W, *r1 = r0 + W;
unsigned char *o0 = o + y * W2 * 2, *o1 = o0 + W2;
@@ -667,6 +680,7 @@ mag160c_error_t mag160c_render_init(mag160c_render_t **out,
r->android_lut = cfg->android_lut;
r->fpa_temp_fix = cfg->fpa_temp_fix;
r->lut_brightness = cfg->lut_brightness;
r->upscale_nearest = cfg->upscale_nearest;
r->force75 = cfg->startup_force_ffc;
r->dev24 = 5;
r->dev4c_shift = 3;
+1
View File
@@ -618,6 +618,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int show) {
cfg.cdf_pivot_75 = 1; /* kept for the PC path */
cfg.android_lut = 1;
cfg.fpa_temp_fix = 1699; /* BasePara2.fpaTempFix of device 160043865 */
cfg.upscale_nearest = 1; /* official Android path has no interpolating 2x stage */
cfg.ffc_cb = ffc_cb;
cfg.post_nuc_cb = post_nuc_cb;
cfg.post_gray_cb = post_gray_cb;
+1
View File
@@ -134,6 +134,7 @@ int main(int argc, char **argv) {
cfg.cdf_pivot_75 = 1; /* kept for the PC path */
cfg.android_lut = 1;
cfg.fpa_temp_fix = 1699; /* BasePara2.fpaTempFix of device 160043865 */
cfg.upscale_nearest = 1; /* official Android path has no interpolating 2x stage */
cfg.ffc_cb = ffc_cb;
mag160c_render_t *render = NULL;
if (mag160c_render_init(&render, &cfg) != MAG160C_OK) {