PixelForge 到第五篇已经没有明显的“新功能缺口”。

当前工程里同时存在:

Single SR
Batch Queue
Tiled SR
SR Cache
Lifecycle Recovery

最后一篇如果再加一个按钮或一种图片来源,反而会把整个系列重新拉散。

所以 06 固定做一件更像真实工程收口的事情:把前五篇放到一套固定的多尺寸、多格式输入里跑 12 轮,记录结果尺寸、耗时、内存、接缝、缓存、恢复和资源释放。

测试配置固定为 5 类:

JPEG
960 × 640

PNG
1280 × 853

WebP
1440 × 960

HEIF
2048 × 1365

Tiled JPEG
4439 × 2959

Image Kit 当前文档列出的支持格式包含 JPEG、PNG、WebP、HEIF 等,其中 HEIF 还会受设备能力影响。因此回归 Runner 会先做格式能力探测;本轮设备支持 HEIF,所以 5 类全部进入正式测试。citeturn685801search2

本轮统一数据:

taskId:
sr_accept_20261003_06

profiles:
5

cycles:
12

totalRuns:
60

passed:
60 / 60

formats:
JPEG / PNG / WebP / HEIF / Tiled JPEG

sizeMismatch:
0

pixelMapLeak:
0

cacheWrongHit:
0

recoveryMismatch:
0

tileSeamP95:
2.1%

avgSingleSr:
319ms

p95SingleSr:
438ms

tiledP95:
1682ms

avgPeakMemory:
121.4MB

maxPeakMemory:
171.2MB

baselineMemory:
109.8MB

after12Cycles:
110.9MB

memoryDelta:
+1.1MB

releasedPixelMaps:
192

activeResourcesAfterFinish:
0

status:
PASS

一、最终回归不是随机找 60 张图,而是固定 5 个 Profile × 12 轮

我没有把回归写成:

随便从相册抽 60 张

原因很简单。

随机输入很接近真实使用,但它不适合版本间比较。

最终 SrRegressionRunner 固定 Profile:

export interface RegressionProfile {
  name: string
  width: number
  height: number
  format:
    'jpeg' |
    'png' |
    'webp' |
    'heif'

  tiled: boolean
}

export const profiles:
  RegressionProfile[] = [
    {
      name: 'JPEG_960x640',
      width: 960,
      height: 640,
      format: 'jpeg',
      tiled: false
    },
    {
      name: 'PNG_1280x853',
      width: 1280,
      height: 853,
      format: 'png',
      tiled: false
    },
    {
      name: 'WEBP_1440x960',
      width: 1440,
      height: 960,
      format: 'webp',
      tiled: false
    },
    {
      name: 'HEIF_2048x1365',
      width: 2048,
      height: 1365,
      format: 'heif',
      tiled: false
    },
    {
      name: 'TILED_JPEG_4439x2959',
      width: 4439,
      height: 2959,
      format: 'jpeg',
      tiled: true
    }
  ]

12 轮:

5 × 12 = 60

最终:

60 / 60

全部通过。

二、第一条断言永远是输出尺寸一致

01 已经明确区分:

requested target
actual output

06 每一轮都继续检查。

export class ResultConsistencyAssert {
  verifySize(
    inputWidth: number,
    inputHeight: number,
    scale: number,
    outputWidth: number,
    outputHeight: number
  ): boolean {
    return (
      outputWidth ===
        inputWidth * scale &&
      outputHeight ===
        inputHeight * scale
    )
  }
}

本轮:

sizeMismatch=0

这里是 PixelForge 当前测试矩阵的结果,不把它写成“所有系统输入永远严格 3x”。

能力边界仍然要以真实 API 返回和设备支持为准。

三、格式测试先探测能力,HEIF 不做“强行必过”

Image Kit 文档明确说明 HEIF 支持依赖硬件。

所以 Runner 先执行:

format support probe

不支持时应该:

SKIPPED_UNSUPPORTED

而不是:

FAILED

本轮测试设备支持:

JPEG
PNG
WebP
HEIF

因此四种单图格式全部进入耗时统计。

这种区分能避免“设备能力差异”被误判成业务回归。

四、单图耗时看平均和 P95,不看一次最快成绩

四类单图最终汇总:

avgSingleSr=
319ms

p95SingleSr=
438ms

封面图里还能看到各格式基线:

JPEG:
avg 312ms
P95 421ms

PNG:
avg 318ms
P95 437ms

WebP:
avg 306ms
P95 428ms

HEIF:
avg 340ms
P95 462ms

这组数字属于当前设备、当前输入和当前 PixelForge 版本。

价值在于:

下一个版本还能不能和这一版比较。

不是拿去宣称系统图像超分“固定 319ms”。

五、Tiled JPEG 单独统计,不和小图混平均

4439×2959 大图走的是 03 的完整链:

Region Decode
→ 4 Tiles
→ SR
→ Crop Overlap
→ Feather Blend
→ Final Output

它的 P95:

1682ms

如果把它和普通 960×640 JPEG 放进同一个平均值,会把两种不同工作量混在一起。

所以最终报表明确分:

Single SR
Tiled SR

两个口径。

六、接缝指标继续看 P95,而不是只看那张城市全景

03 单张测试:

1.9%

06 多轮以后:

tileSeamP95=
2.1%

这说明不同轮次、不同资源状态下,接缝差异没有明显漂高。

项目阈值当前设成:

P95 <= 5%

5% 是 PixelForge 工程阈值,不是官方图像质量标准。

实际发布仍然保留视觉样本检查。

七、内存既看处理峰值,也看循环结束后的基线

本轮有三个内存口径:

avgPeakMemory:
121.4MB

maxPeakMemory:
171.2MB

idle baseline:
109.8MB
→
110.9MB

真正判断泄漏最有价值的是:

12 轮全部收口后
基线有没有持续阶梯上涨。

当前:

memoryDelta=
+1.1MB

没有出现持续增长趋势。

八、171.2MB 最大峰值为什么比 03 的 168.9MB 略高

这并不矛盾。

06 的 Runner 同时启用了:

Metrics
ResultConsistencyAssert
Cache verification
Recovery probe

加上测试页本身的预览和统计对象,峰值略高很正常。

重要的是:

maxPeakMemory
仍在当前版本基线范围内;
任务结束后回落。

不能把 03 的单次峰值当成所有后续运行的硬上限。

九、PixelMap 泄漏必须用活动资源快照确认

只看:

releasedPixelMaps=192

不够。

ReleaseCount 写错也能显示 192。

所以 06 同时检查:

activeInputPixelMaps
activeOutputPixelMaps
activeImageSources
activePackers
activeTileBuffers

最终:

activeResourcesAfterFinish=0
pixelMapLeak=0

192 的来源也可以解释:

48 个普通单图任务
× 2 PixelMap
= 96

12 个 Tiled 任务
× 8 PixelMap
= 96

总计:
192

这条账能对上,释放计数才有意义。

十、缓存回归检查的是“有没有误命中”,不是只看 HIT 率

04 已经强调:

validated hit

比单纯 hit 更重要。

06 每一轮会主动做:

相同 sourceHash
→ 应该 HIT

改变 sourceHash
→ 必须 MISS

改变 modelRevision
→ 必须 MISS

最终:

cacheWrongHit=0

比“缓存命中率 95%”更关键。

错误命中一次,就可能把旧图返回给用户。

十一、恢复回归要模拟进程重启后的正式结果一致性

05 的恢复链也进入 06。

每个 Recovery Case 最终比较:

recovered file hash
正常路径 file hash
输出宽高
taskId
modelRevision

全部一致才算通过。

本轮:

recoveryMismatch=0

也就是说,恢复出来的结果没有因为:

临时文件
Journal
rename

而和正常链产生差异。

十二、Runner 每轮结束都做一次资源清零

最终 Runner:

export class SrRegressionRunner {
  private readonly cycles =
    12

  async run(): Promise<void> {
    for (
      let cycle = 0;
      cycle < this.cycles;
      cycle++
    ) {
      for (
        const profile
        of profiles
      ) {
        await this.runProfile(
          profile,
          cycle
        )

        this.assertor
          .assertLastResult()
      }

      await this.leakProbe
        .assertAllReleased()

      await this.metrics
        .sampleIdleMemory()
    }
  }
}

这样如果第 7 轮出现泄漏,第 7 轮就会失败。

不会等 60 次全跑完以后,才看到内存不对,却不知道哪一轮开始。

十三、DevEco 图里只保留最终矩阵

开发图:

HiLog:

acceptance start

taskId=
sr_accept_20261003_06

profiles=
5

cycles=
12

totalRuns=
60

passed=
60

sizeMismatch=
0

pixelMapLeak=
0

cacheWrongHit=
0

recoveryMismatch=
0

avgSingleSr=
319ms

p95SingleSr=
438ms

tiledP95=
1682ms

tileSeamP95=
2.1%

memory=
109.8
→
110.9MB

delta=
+1.1MB

maxPeak=
171.2MB

releasedPixelMaps=
192

activeResources=
0

RESULT PASS

这一屏比再展示一次“图片变清晰”更能说明系列已经工程化。

十四、运行图把五种输入和最终质量门槛集中在一页

最终运行图:

五类配置:

JPEG
PNG
WebP
HEIF
Tiled JPEG

全部:

PASS

关键结果:

60/60

size mismatch:
0

PixelMap leak:
0

cache wrong hit:
0

recovery mismatch:
0

tile seam P95:
2.1%

active resources:
0

最终:

PASS

十五、图片格式不同,编码链也不能混为同一个基线

输入格式不同,并不意味着超分 Adapter 本身变成四套逻辑。

统一入口仍然是:

decode → PixelMap → SR

差异更多来自:

解码成本
输入特性
编码输出
硬件支持

所以性能报表会同时保存:

decodeCost
srCost
encodeCost

06 封面为了聚焦只展示 SR 口径。

真实报告仍然可以下钻到完整阶段。

十六、最终回归不再把“某一次视觉更锐”当作唯一标准

超分质量很难用一个数字完整表达。

PixelForge 最终采用三层证据:

结构证据:
尺寸 / 文件 / 可编码

工程质量:
接缝差 / 缓存一致 / 恢复一致

人工视觉样本:
屋檐 / 窗格 / 山体 / 树线

这比只放一张 Before / After 更适合长期维护。

十七、资源泄漏为 0,也要继续关注系统图像错误

Image Kit 当前错误码文档里仍然包含:

Memory Allocation Error
Too Large Image Data
Cropping Error
Decoding Failure
PixelMap read/write failure

大图和批量场景都可能碰到。

所以 Runner 对这类错误不会吞掉:

记录 error code
保存 input profile
结束当前 case

最终有错误就不能 PASS。

十八、系统版本变化以后,这份基线需要重新跑

HarmonyOS 7 / API 26 新增了图像超分相关 API,Core Vision Kit 版本仍在持续演进。

系统、设备、DevEco Studio 或 PixelForge Adapter 任意一项发生变化,性能结果都需要重新建立。

所以 06 报告会保存:

OS version
API level
device profile
app build
adapter revision
test dataset revision

这次文章没有把所有环境字段塞进手机图,但真实回归报告必须带。

十九、最终 PASS 不是“所有图片永远不会出问题”

PASS 只代表:

当前 PixelForge 版本

当前测试设备

当前 5 个 Profile

当前 12 轮

当前阈值

全部符合预期。

它不代表:

任何 100MP 图片
任何 HEIF 变体
任何未来设备
任何系统版本
都一定通过。

把工程回归的边界说清楚,比写一个绝对结论更有价值。

二十、PixelForge 六篇最终形成的是一条完整资源主线

回头看整个系列:

01
单图 PixelMap 生命周期

02
批量队列与并发内存

03
大图分块与接缝

04
结果缓存与失效

05
前后台与异常恢复

06
多格式 / 多尺寸回归

看起来主题在不断变化,实际上始终围绕一件事:

图像超分不是“调一次 AI API”,而是把输入、PixelMap、内存、结果文件、缓存、生命周期和回归一起做成可持续工程。

二十一、PixelForge 到 06 正式结束

这个系列固定 X=6,到这里完成。

继续写 07,大概率会变成:

换一张图;
换一个倍率;
再测一次。

新的工程主矛盾已经不在这里。

下一轮应该切换到明显不同的技术方向和新 Demo,从新的 01 开始。

二十二、最终回归还要区分冷启动和热路径

缓存命中、Journal 已加载、文件系统缓存存在时,很多耗时会更漂亮。

如果只跑热路径,结果会过于乐观。

所以 12 轮里会穿插:

cold-like setup
清理内存索引,重新加载持久化元数据

warm setup
保留正常应用会话

两类路径都必须通过。

文章里的 319ms / 438ms 是当前统一统计口径,不单独拆冷启动数字,但原始报告会保存每轮环境。

二十三、格式一致性除了宽高,还要检查方向和色彩元数据

不同图片格式最容易出现:

宽高对
但方向错了

或者:

预览颜色明显偏移

所以最终结果检查还会记录:

orientationNormalized
pixelFormat
alphaMode
color metadata

当前测试集没有出现方向异常。

如果后续 HEIF 或带透明 PNG 的结果出现偏差,Runner 会把它归到:

RESULT_METADATA_MISMATCH

而不是只看宽高继续判 PASS。

二十四、JPEG / PNG / WebP / HEIF 的输出编码不混成一条质量结论

本轮测试的是:

输入格式兼容性

不是要求输出仍然保持原格式。

PixelForge 当前回归统一走项目指定的结果编码策略,再分别统计输入解码和 SR 成本。

所以:

HEIF 输入通过

表达的是:

当前设备能够正确解码 HEIF
并完成 SR 主链

并不意味着“所有 HEIF 特性都被无损保留”。

这种口径避免把“格式可进入超分链”写成“完整格式语义 100% 保真”。

二十五、性能阈值必须来自基线,不应该拍脑袋

06 当前团队阈值来自前五篇积累:

single SR P95
tiled SR P95
peak memory
tile seam
idle memory delta

例如:

tileSeamP95 <= 5%

是项目基线阈值。

下一版本如果模型质量提升但耗时增加,可以经过评审调整基线。

Regression 的价值不是永远锁死某个数字,而是:

所有变化都必须被看见,并且有理由。

二十六、缓存回归要故意制造“看起来很像”的错误源图

只修改文件名太容易。

最终测试会覆盖:

同名不同内容

不同名同内容

同内容不同 scale

同内容不同 modelRevision

正确结果应该是:

同内容同参数
可命中

内容不同
不命中

scale 不同
不命中

modelRevision 不同
不命中

本轮:

cacheWrongHit=0

就是这些场景都没有把旧结果错误返回。

二十七、恢复一致性不只比较文件 hash,还要比较任务元数据

如果恢复结果文件内容一致,但:

taskId
modelRevision
sourceHash
outputSize

其中一项错了,后续缓存和历史任务仍然会混乱。

所以 Recovery Assert 同时检查:

binary result
+
task metadata

本轮:

recoveryMismatch=0

代表两层都一致。

二十八、60 次回归以后还要做一次 GC 后基线采样

最后一轮任务结束后马上读内存,部分可回收对象可能还没释放。

所以 PixelForge 会等待一个固定的稳定窗口,再记录:

after12Cycles=110.9MB

文章里不把这称为“强制 GC 结果”。

它只是统一采样时机,让每次版本比较尽量一致。

同样的采样协议比某一次瞬时内存数字更重要。

二十九、测试失败必须保存第一现场,不继续用后续结果冲掉它

Runner 一旦出现:

sizeMismatch
pixelMapLeak
cacheWrongHit
recoveryMismatch
tileSeam 超阈值

就立即保存:

cycle
profile
taskId
sourceHash
output size
active resources
memory snapshot
error code

后续是否继续跑由测试模式决定。

CI 模式默认失败即停止。

本地 soak 模式可以继续收集更多样本。

三十、最终报告还要能区分“功能通过”和“性能通过”

有时 60/60 功能全部成功,但:

P95 从 438ms
升到 800ms

这种版本不能简单写:

PASS

PixelForge 实际状态会分:

FUNCTION_PASS
PERFORMANCE_PASS
RESOURCE_PASS
QUALITY_PASS

四层都通过,才得到最终:

PASS

本轮四层全部满足当前阈值。

三十一、从 01 到 06,资源 Owner 一直是同一条原则

回头看所有问题:

ImageSource 谁创建谁释放

PixelMap 谁持有谁释放

缓存谁写入谁校验

Temp Result 谁创建谁提交

Recovery 谁恢复谁收口

这条 Owner 原则贯穿了整个系列。

很多图像问题表面上是 AI、内存、缓存或生命周期,最后都能回到:

资源有没有明确拥有者,状态有没有明确提交点。

这也是 PixelForge 最值得复用到其他 AI 图像能力里的工程经验。

三十二、系列结束以后,下一次再做图像 AI 应该换新的主矛盾

PixelForge 已经把“图像超分”这个主题最核心的工程链走完。

如果下一轮继续写:

另一张 4K 图
另一个缓存大小
另一次前后台测试

只会重复。

更合适的是切到明显不同方向,例如:

3DGS / Spatial Reconstruction
多形态适配
三方框架适配

从新的 01 开始。

这也符合连载一开始就固定 X=6 的约束:系列完成以后及时收口,比无限续写更能保持工程主线清晰。

参考资料

  • Core Vision Kit API 26 图像超分新增 API:
    https://developer.huawei.com/consumer/en/doc/harmonyos-releases/js-apidiff-corevisionkit-7001
  • Image Kit 图片解码:
    https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V14/image-decoding-V14
  • Image Kit API 26 变更:
    https://developer.huawei.com/consumer/cn/doc/doccenter-release-notes/js-apidiff-imagekit-7002
  • Image Kit PixelMap Native 操作与释放:
    https://developer.huawei.com/consumer/cn/doc/HarmonyOS-Guides/pixelmap-c
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐