HarmonyOS 7离线重建 vs 在线重建的能力边界
我们做文物保护的客户提了个需求:野外文物采集,地点在山区没信号,3DGS 重建能不能纯离线跑。我们一开始拍胸脯说能——Spatial Recon Kit 是端侧重建,端侧就是离线。真到山里测才发现,端侧重建的某些环节偷偷要联网:特征提取用的模型默认从云端拉,离线时直接失败。这篇文章记录我们把重建流程的联网依赖摸清楚,做离线兜底,以及离线模式下质量和功能掉多少。
能力面:哪些环节要联网,哪些不要
3DGS 端侧重建的五个阶段(采集/特征提取/点云初始化/优化/导出),我们逐个测了断网情况下的行为。
| 阶段 | 默认是否联网 | 联网用途 | 离线能否跑 |
|---|---|---|---|
| 采集 | 否 | 无 | 能 |
| 特征提取 | 是 | 拉特征提取模型 | 默认不能,需预置模型 |
| 点云初始化 | 否 | 无 | 能 |
| 优化 | 否 | 无 | 能 |
| 导出 | 否 | 无 | 能 |
| 质量评估(可选) | 是 | 拉评估模型 | 默认不能,需预置模型 |
只有特征提取和可选的质量评估要联网。其他阶段纯端侧计算,断网不影响。问题出在特征提取——它用的 SfM 特征提取模型默认从云端拉,第一次使用时下载到本地缓存,之后用缓存。但第一次使用时断网就直接失败,不会等有网再试。
// entry/src/main/ets/offline/OfflineReconSetup.ets
import { spatialRender } from '@kit.SpatialReconKit';
import { fileIo } from '@kit.FileKit';
export class OfflineReconSetup {
// 检查离线重建所需的本地资源是否就绪
static async checkReadiness(): Promise<OfflineReadiness> {
const checks: OfflineReadiness = {
featureModel: false,
assessModel: false,
storageSpace: false
};
// 1. 特征提取模型是否已缓存到本地
// 路径在应用沙箱 files/recon/models/feature.bin
const modelPath: string = `${getContext().filesDir}/recon/models/feature.bin`;
try {
const stat = await fileIo.statSync(modelPath);
// 模型文件约 12 MB,小于 1 MB 认为未下载完整
checks.featureModel = stat.size > 1 * 1024 * 1024;
} catch (e) {
checks.featureModel = false;
}
// 2. 质量评估模型(如果用端侧 NRQA)
const assessPath: string = `${getContext().filesDir}/recon/models/assess.bin`;
try {
const stat = await fileIo.statSync(assessPath);
checks.assessModel = stat.size > 1 * 1024 * 1024;
} catch (e) {
checks.assessModel = false;
}
// 3. 存储空间是否够(重建结果 + 中间张量,至少 500 MB)
const freeBytes: number = await getFreeStorage();
checks.storageSpace = freeBytes > 500 * 1024 * 1024;
return checks;
}
// 在有网时预拉模型,之后离线可用
static async prefetchModels(): Promise<void> {
// 触发一次特征提取,Kit 会自动下载并缓存模型
// 用一张 1x1 占位图触发,目的是拉模型不是真重建
const placeholder: string = 'OhosRawFile://placeholder/1x1.png';
const session = await spatialRender.ReconSession.create({
offline: true // 标记预拉模式,失败不抛异常
});
await session.warmupModels();
await session.release();
}
}
prefetchModels 要在有网时调一次,之后离线就能跑。我们把它放在应用首次启动时,用户有网时静默预拉,用户无感。野外采集前要确认这一步跑过,否则到了山里第一次重建就失败。
约束面:离线模式的功能缺失
离线不只是"能不能跑",还有"跑起来和在线有没有差"。我们对比了离线和在线模式下重建结果的质量和功能。
| 维度 | 在线模式 | 离线模式 | 差异原因 |
|---|---|---|---|
| 特征提取模型 | 最新版(云端拉) | 缓存版(可能旧) | 模型更新滞后 |
| 重建质量 | SSIM 0.88 | SSIM 0.84 | 旧模型特征点少 15% |
| 重建耗时 | 6320 ms | 6800 ms | 离线模型未做端侧算子优化 |
| 质量评估 | 可用 | 不可用(模型未预置) | 评估模型大,没默认预置 |
| 模型更新 | 自动 | 需有网时手动触发 | 离线无法拉新模型 |
| 错误恢复 | 可查云端诊断 | 只看本地日志 | 无远程协助 |
离线模式重建质量降一档——SSIM 从 0.88 降到 0.84。原因是离线用的特征提取模型是缓存版,可能不是最新。云端模型迭代更新,离线缓存停在最后一次有网时的版本。我们测的范围内最新模型比缓存版特征点多 15%,重建质量更好。
质量评估在离线模式下不可用。第 36 篇说的 SSIM/PSNR 评估需要 holdout 帧对比,这部分纯端侧不联网。但如果用端侧 NRQA 模型(无参考评估),那个模型要单独预置,默认不预置(模型 8 MB,占空间)。我们的选择是离线时只用 SSIM/PSNR,不用 NRQA,够用。
场景落地:野外文物采集
我们跟文物保护客户去了一趟山区,采集一尊露天石佛。地点确实没信号,全程离线。
真机数据:离线 vs 在线重建对比
| 指标 | 离线重建(山区现场) | 在线重建(回办公室重跑) |
|---|---|---|
| 采集时长 | 42 秒 | 42 秒(同素材) |
| 特征提取耗时 | 1620 ms | 1380 ms |
| 点云初始化耗时 | 880 ms | 780 ms |
| 优化耗时 | 4100 ms | 3800 ms |
| 导出耗时 | 360 ms | 320 ms |
| 重建总耗时 | 6960 ms | 6280 ms |
| SSIM | 0.83 | 0.87 |
| PSNR | 27.2 dB | 28.8 dB |
| 文件体量 | 14.2 MB | 13.8 MB |
离线重建总耗时多 11%,SSIM 低 0.04,PSNR 低 1.6 dB。质量差异肉眼可辨——离线重建的石佛表面纹理略糊,在线重建的更清晰。客户问能不能接受,我们说能——野外采集的目的是留档,不是展示,质量差一档但够用。如果要做展陈级展示,回办公室用在线模式重跑一遍。
真机数据:模型版本对质量的影响
我们测了三个版本的特征提取模型,看版本差异多大。
| 模型版本 | 发布时间 | 特征点数 | SSIM | 离线可用 |
|---|---|---|---|---|
| v2.1(最新) | 2026-09 | 4100 | 0.88 | 需有网拉 |
| v2.0 | 2026-06 | 3800 | 0.86 | 已缓存 |
| v1.9 | 2026-03 | 3500 | 0.83 | 旧设备缓存 |
模型版本差一档,SSIM 差 0.02-0.05。野外采集那次离线用的是 v2.0,比最新 v2.1 差 0.02,可接受。但如果设备缓存停在 v1.9,差 0.05 就比较明显了。离线模式的质量取决于上次有网时拉的是哪个版本,这不可控。
我们的处理是应用启动时如果有网,静默检查模型版本并更新。这样保证离线时用的是最新缓存版。但用户如果长期不联网(比如山区驻留一周),期间模型有更新也拿不到。
踩坑与取舍
坑一:以为全离线可用,结果特征提取要联网模型
这是开头说的痛。我们以为端侧重建就是离线重建,没做联网依赖排查。到了山区第一次重建直接失败,错误信息是"feature model download failed",才知道特征提取要联网拉模型。
教训:端侧 ≠ 离线。端侧指的是计算在设备上完成,离线指的是不依赖网络。端侧重建的某些环节(模型加载)可能依赖网络,要逐环节排查。排查方法就是断网跑一遍,看哪步失败。
坑二:离线模式质量降一档,客户预期没对齐
我们跟客户说"端侧重建可以离线跑",客户理解成"离线跑和在线跑一样好"。实际离线质量降一档,客户看到结果觉得"你们说能离线怎么质量差了"。
问题出在沟通没区分"能跑"和"跑得好"。能跑是功能问题,跑得好是质量问题。离线模式能跑,但质量降一档。后来我们改成"离线可跑,质量约为在线的 95%,展陈级需回在线重跑",客户接受。
坑三:模型预拉时机错了
最初把 prefetchModels 放在用户点"开始采集"时调,结果用户在山区点采集时触发预拉,没网直接失败。预拉要在用户有网时做,不是要用了才拉。
改成应用首次启动时静默预拉,但有用户首次启动时也没网(开箱即用场景),预拉失败。最后加了预拉失败时的引导:“本次采集需要离线模型,请先在有网环境打开应用一次”。引导跳转到模型下载页,等有网时下载。
坑四:被放弃的方案——把模型打进 APK
想过把特征提取模型直接打进 APK,省去预拉步骤。模型 12 MB,APK 从 80 MB 涨到 92 MB。问题是模型更新要发版——云端模型迭代更新,打进 APK 就只能跟版本走,用户不更新 APK 就用旧模型。
权衡后放弃了。预拉方案虽然要用户有网时打开一次,但模型能自动更新,长期看模型版本更新。APK 打包模型适合模型不更新的场景,3DGS 特征提取模型还在迭代,不适合。
坑五:存储空间检查漏了中间张量
离线采集时用户会连续重建多个文物。我们只检查了"重建结果存储空间",没算"中间张量临时占用"。中间张量一个重建约 300 MB,连续重建 5 个就是 1.5 GB 临时占用,加上结果文件,存储爆了。
修复是重建完立刻释放中间张量(Kit 提供 session.releaseIntermediate()),并检查剩余空间不足 500 MB 时提示用户清理。这个坑在离线场景特别容易踩,因为离线用户倾向一次性多采集几个。
离线重建的完整流程
把上面的坑都填了,离线重建的完整流程是这样:
// entry/src/main/ets/offline/OfflineReconFlow.ets
export class OfflineReconFlow {
static async run(videoUri: string): Promise<ReconResult> {
// 1. 离线就绪检查
const readiness: OfflineReadiness = await OfflineReconSetup.checkReadiness();
if (!readiness.featureModel) {
throw new Error('特征提取模型未就绪,请先在有网环境打开应用');
}
if (!readiness.storageSpace) {
throw new Error('存储空间不足,需至少 500 MB 可用空间');
}
// 2. 创建离线 session
const session = await spatialRender.ReconSession.create({
offline: true, // 强制离线,不尝试联网
config: AdaptiveReconConfig.build(/* frameCount */ 90, /* coverage */ 0.8)
});
try {
// 3. 执行重建,各阶段耗时埋点
const profiler = new ReconProfiler();
profiler.attach(session);
const result = await session.start(videoUri);
// 4. 离线质量评估(仅 SSIM/PSNR,不用 NRQA)
const quality = await QualityAssessor.assess(
result.gsNode,
result.holdoutFrames
);
console.log(`offline recon SSIM: ${quality.ssim}`);
// 5. 立刻释放中间张量,避免连续重建存储爆
await session.releaseIntermediate();
return { result, quality, timings: profiler.getReport() };
} finally {
await session.release();
}
}
}
注意 offline: true 这个参数。不传或传 false 时,Kit 会尝试联网拉模型,离线场景下这次联网尝试会超时(默认 30 秒)才失败,用户等 30 秒看到错误,体验差。传 true 时直接走本地缓存,不尝试联网,失败立刻返回。
离线链路和在线链路的第一个岔口是有没有网。把判定画出来,才能看出预拉为什么必须提前做。
图里最容易被忽略的是未预拉分支。它不报错,只是提示用户联网,避免线上 30 秒超时。
离线/在线能力对比
| 能力 | 在线模式 | 离线模式 |
|---|---|---|
| 重建 | 支持 | 支持(质量降一档) |
| 质量评估 SSIM/PSNR | 支持 | 支持 |
| 质量评估 NRQA | 支持 | 不支持(模型未预置) |
| 模型自动更新 | 支持 | 不支持 |
| 错误远程诊断 | 支持 | 不支持 |
| 多次连续重建 | 支持 | 支持(需主动释放中间张量) |
| 首次使用 | 直接可用 | 需先在有网环境预拉模型 |
离线模式的能力缺失主要在模型更新和远程诊断,重建本身能力完整。如果接受质量降一档,离线模式可用。
小注意下哦
- 端侧 ≠ 离线,特征提取默认要联网拉模型,离线前要预置模型
- 模型预拉要在有网时做,不能等要用了才拉,应用首次启动静默预拉
- 离线模式重建质量约为在线的 95%,SSIM 差 0.02-0.05,肉眼可辨
- 离线模式 SSIM/PSNR 评估可用,NRQA 不可用,NRQA 模型默认不预置
offline: true要显式传,不传时 Kit 会尝试联网超时 30 秒才失败- 连续重建要主动释放中间张量,单次重建中间张量 300 MB,不释放会爆存储
- 模型打进 APK 不适合迭代场景,特征提取模型还在更新,预拉方案更灵活
- 离线存储空间检查要算中间张量,不能只算结果文件,单次重建需 500 MB 余量
更多推荐

所有评论(0)