在这里插入图片描述

📖 引言

你有没有这样的经历:

翻家里的老相册,看到一张几十年前的老照片——可能是爷爷奶奶年轻时的照片,可能是某个少数民族的历史影像。照片很有纪念意义,但画质太差了:模糊不清、颗粒感重、还有划痕和破损。你想把它修复清晰,但又不知道怎么办。

这时候,图像超分辨率(Super Resolution) 技术就能派上用场了。简单说,就是用AI让模糊的图片变清晰,让低分辨率的图片变成高分辨率。

在鸿蒙7中,端侧图像超分是视觉AI能力的重要组成部分。基于深度学习的超分算法,可以在手机本地就能完成图像的画质增强——不需要上传云端,保护隐私的同时,还能获得出色的效果。

你可能会问:

  • 什么是图像超分辨率?它和普通的放大有什么区别?
  • AI超分的原理是什么?为什么能让模糊的图片变清晰?
  • 鸿蒙的端侧超分能力有多强?支持哪些场景?
  • 「民族图鉴」可以用超分做哪些功能?
  • 超分太慢怎么办?怎么优化性能?
  • 超分效果不自然怎么办?怎么调优?

这些问题非常重要。图像超分是AI在图像增强领域最实用的技术之一,用好它能显著提升图片展示的质量和用户体验。

本文将系统讲解图像超分辨率技术的原理、应用和优化方法。我们会从基础概念讲起,深入到技术原理,然后结合「民族图鉴」设计应用场景,最后通过实战演示如何实现老照片修复功能。


🎯 学习目标

完成本文后,你将能够:

  • ✅ 理解什么是图像超分辨率(SR)
  • ✅ 了解传统插值和AI超分的区别
  • ✅ 掌握鸿蒙端侧超分能力的使用
  • ✅ 学会设计「民族图鉴」的超分应用场景
  • ✅ 掌握超分性能优化的方法
  • ✅ 了解超分效果调优的技巧
  • ✅ 具备实战实现老照片修复的能力
  • ✅ 了解常见问题及解决方案

💡 需求分析

为什么需要图像超分?

在讲技术之前,我们先回答一个最根本的问题:为什么需要图像超分?它能给用户带来什么价值?

1. 老照片修复:让历史焕发新生

很多老照片承载着珍贵的记忆和历史价值,但由于年代久远,画质往往很差:

  • 分辨率低
  • 模糊不清
  • 有划痕、破损
  • 色彩褪色、偏色

用超分技术可以:

  • 提升清晰度,让细节更丰富
  • 去除噪点和划痕
  • 恢复色彩
  • 让老照片"重获新生」

对于「民族图鉴」来说:

  • 很多民族历史照片可以修复得更清晰
  • 提升用户的浏览体验
  • 更好地展示和传播民族文化
2. 缩略图放大:点击即高清

在列表页,为了节省流量和内存,我们通常用缩略图。但用户点击查看大图时,如果只有缩略图,放大后会很模糊。

用超分技术可以:

  • 缩略图加载快(省流量、省内存)
  • 用户点击查看时,实时超分成高清图
  • 兼顾加载速度和展示质量
3. 低质图片增强:提升内容质量

用户上传的图片、网络上的图片,质量参差不齐。用超分技术可以:

  • 自动增强低质量图片
  • 统一展示质量
  • 提升整体的视觉体验
4. 节省带宽:小图传,大图看

在网络传输中,可以:

  • 传输低分辨率的小图(省流量、传得快)
  • 接收端用超分"放大"成高清图
  • 同样的视觉质量,用更少的流量

这对于移动网络环境下的用户体验提升很大。


「民族图鉴」的超分需求场景

「民族图鉴」作为一款展示民族文化的应用,有很多适合用超分的场景:

「民族图鉴」超分应用场景
├── 1. 老照片修复
│   ├── 民族历史照片
│   ├── 老纪录片截图
│   └── 历史人物照片
├── 2. 缩略图放大
│   ├── 列表缩略图 → 点击超分放大
│   ├── 封面图高清展示
│   └── 节省内存和流量
├── 3. 文档/文字增强
│   ├── 古籍图片清晰化
│   ├── 老报纸/老照片文字增强
│   └── OCR识别前预处理
└── 4. 用户上传图片增强
    ├── 用户上传的服饰照片
    ├── 用户上传的文物照片
    └── 提升展示质量

🛠️ 核心实现

步骤1:什么是图像超分辨率

1.1 基本概念

图像超分辨率(Super Resolution,简称SR) 就是从一张低分辨率(Low Resolution, LR)的图片,恢复出一张高分辨率(High Resolution, HR)的图片。

简单说:让小图变大、变清晰。

低分辨率图(模糊) → [超分算法] → 高分辨率图(清晰)

放大倍率(Scale Factor)

  • 2x超分:宽高各放大2倍,面积是4倍
  • 3x超分:宽高各放大3倍,面积是9倍
  • 4x超分:宽高各放大4倍,面积是16倍

倍率越高,难度越大,效果也越难保证。


1.2 传统方法 vs AI方法

图像超分不是什么新技术,很早就有了。但传统方法和AI方法的效果差距很大。

传统插值方法

最常见的是最近邻插值、双线性插值、双三次插值等。它们的原理很简单:**根据周围的像素,"猜"出新像素的值。

双线性插值:
已知四个角的像素值
    ↓
用线性加权的方式
    ↓
计算出新像素的值

传统方法的问题

  • 只是"平滑地放大",不会增加新的细节
  • 放大后图片还是模糊的
  • 边缘、纹理等细节丢失严重

你可以把它想象成:把一张小图打印在大纸上,虽然变大了,但还是模糊的。


AI超分方法

AI超分用深度学习模型,“学习"了大量的高清-低清图片对,知道"模糊的地方应该是什么样的”,然后"脑补"出细节。

大量高清图片
    ↓
训练AI模型
    ↓
学会"低清图 → 高清图"的映射
    ↓
给一张新的低清图
    ↓
AI"猜"出高清版

AI方法的优势

  • 能"生成"细节,而不只是平滑放大
  • 边缘更锐利
  • 纹理更丰富
  • 整体更清晰

你可以把它想象成:一个见过无数高清照片的画家,看着模糊的小图,凭着经验把它画清晰。


效果对比示意

方法 效果 速度 适用场景
最近邻插值 差(马赛克) 像素风
双线性插值 一般(模糊) 很快 简单放大
双三次插值 较好(较模糊) 传统图像处理
AI超分 好(细节丰富) 较慢 追求画质

1.3 AI超分的技术原理

AI超分的核心是深度学习模型。最经典的是基于卷积神经网络(CNN)的方法。

基本思路

低清图 → [卷积神经网络] → 高清图

几种经典的超分模型

模型 提出时间 特点
SRCNN 2014 最早的CNN超分模型,简单直接
ESPCN 2016 实时超分,速度快
SRResNet 2017 残差网络,效果好
EDSR 2018 增强版残差,效果更好
RCAN 2019 注意力机制,SOTA
Real-ESRGAN 2021 实用化、人脸修复
Stable Diffusion 2022 扩散模型,生成式超分

端侧常用的是轻量级模型,比如:

  • 移动端优化的SRCNN变体
  • MobileNet-based的超分模型
  • 量化后的INT8模型

步骤2:超分的应用场景

图像超分的应用非常广泛,我们来梳理一下。

超分应用场景
├── 1. 老照片修复
│   ├── 家庭老照片
│   ├── 历史影像修复
│   ├── 老旧电影修复
│   └── 黑白照片上色(结合色彩恢复
├── 2. 视频画质增强
│   ├── 低清视频转高清
│   ├── 视频降噪、去划痕
│   └── 老视频修复
├── 3. 图像编辑
│   ├── 图片放大不失真
│   ├── 缩略图放大
│   └── 画质增强
├── 4. 医学影像
│   ├── CT/MRI图像增强
│   └── 辅助诊断
├── 5. 监控安防
│   ├── 监控画面增强
│   └── 人脸识别前预处理
├── 6. 游戏/渲染
│   ├── 超采样(DLSS、FSR)
│   └── 性能提升
└── 7. 手机拍照
    ├── 数码变焦增强
    ├── 夜景增强
    └── 画质提升

对于「民族图鉴」,我们重点关注几个场景:

  1. 老照片修复
  2. 缩略图放大
  3. 文档/文字增强

步骤3:鸿蒙端侧超分能力

鸿蒙7提供了端侧的图像超分能力,开发者可以很方便地使用。

3.1 能力概览
鸿蒙超分能力
├── 1. 通用图像超分
│   ├── 2x/3x/4x超分
│   ├── 人像优化
│   └── 通用场景
├── 2. 人像超分
│   ├── 人脸优化
│   ├── 皮肤优化
│   └── 人像照片增强
├── 3. 文字超分
│   ├── 文字图像增强
│   ├── 文档清晰化
│   └── OCR前处理
└── 4. 实时超分
    ├── 视频实时超分
    └── 低延迟
3.2 超分API的使用

鸿蒙提供了封装好的超分API,开发者可以直接调用。

基本使用流程

1. 创建超分器(SuperResolution)
   ↓
2. 配置参数(倍率、模型类型等)
   ↓
3. 输入图片
   ↓
4. 执行超分
   ↓
5. 获取结果

**代码示例(概念代码):

// 鸿蒙超分API使用示例(概念代码)
import { SuperResolution } from '@kit.VisionKit';

class SuperResolutionService {
  private static instance: SuperResolutionService;
  
  static getInstance(): SuperResolutionService {
    if (!SuperResolutionService.instance) {
      SuperResolutionService.instance = new SuperResolutionService();
    }
    return SuperResolutionService.instance;
  }

  /**
   * 图像超分
   * @param image 输入图片
   * @param scale 放大倍率:2、3、4
   * @param type 超分类型:通用、人像、文字
   */
  async upscale(
    image: Image,
    scale: number = 2,
    type: SRType = SRType.GENERAL
  ): Promise<Image> {
    try {
      // 创建超分器
      const sr = SuperResolution.create({
        scale: scale,
        type: type,
        quality: SRQuality.HIGH, // 质量优先
      });

      // 执行超分
      const result = await sr.process(image);
      
      return result;
    } catch (e) {
      console.error('Super resolution failed:', e);
      throw e;
    }
  }
}

enum SRType {
  GENERAL = 'general',     // 通用
  PORTRAIT = 'portrait',   // 人像
  TEXT = 'text',         // 文字
}

enum SRQuality {
  FAST = 'fast',       // 速度优先
  BALANCED = 'balanced', // 平衡
  HIGH = 'high',       // 质量优先
}

💡 注意:以上是概念示例,具体API以鸿蒙7官方文档为准。


步骤4:「民族图鉴」超分应用设计

讲完了技术原理,我们来为「民族图鉴」设计具体的超分应用。

4.1 应用一:老照片修复

功能描述
用户上传或选择一张老照片,AI自动修复:提升清晰度、去除噪点、增强细节。

使用场景

  • 民族历史老照片修复
  • 用户自己的老照片修复
  • 历史影像资料增强

功能流程

用户选择老照片
    │
    ▼
  图片预览
    │
    ├─► 选择修复模式(基础/增强/极致)
    │
    ▼
  开始修复(进度条)
    │
    ▼
  修复完成
    ├─ 左右对比(滑动查看前后对比)
    ├─ 放大查看细节
    ├─ 保存到相册
    └─ 分享

修复模式

模式 效果 速度 适用场景
基础修复 2x超分 + 基础去噪 一般的老照片,追求速度
增强修复 3x超分 + 增强去噪 + 锐化 大多数场景,平衡
极致修复 4x超分 + 全面增强 重要照片,追求最好效果

4.2 应用二:缩略图智能放大

功能描述
列表页用低分辨率缩略图(省内存、省流量),用户点击查看大图时,用AI超分实时放大成高清图。

好处

  1. 列表页加载更快
  2. 内存占用更少
  3. 大图更清晰
  4. 节省网络流量

实现思路

列表页:加载缩略图(200×200)
    ↓
用户点击查看大图
    ↓
显示缩略图先显示(快速呈现)
    ↓
后台执行超分
    ↓
超分完成后,替换为高清图

渐进式体验

  • 先看模糊的,再变清晰
  • 比让用户等很久才看到图好

4.3 应用三:文档/文字增强

功能描述
对包含文字的图片(古籍、老报纸、文档照片等做增强,让文字更清晰,便于阅读和OCR识别。

使用场景

  • 民族古籍图片清晰化
  • 老照片上的文字增强
  • 文献资料图片增强

步骤5:超分性能优化

超分是计算密集型任务,性能优化很重要。如果超分一张图要等十几秒,用户早就不耐烦了。

5.1 性能优化的维度
维度 指标 优化方向
速度 处理时间(秒/张) 模型优化、硬件加速、尺寸优化
内存 内存占用(MB) 内存复用、分块处理
电量 耗电量 调度优化、避免长时间高负载

5.2 模型选择与量化

模型选择

不同的模型,速度和效果差异很大:

模型大小 效果 速度 适用场景
小模型 一般 很快 实时、缩略图放大、列表页
中模型 较好 中等 大多数场景
大模型 很好 较慢 重要照片、追求质量

建议

  • 列表缩略图用小模型(快)
  • 详情页用中模型(平衡)
  • 用户主动选择"修复"时用大模型(质量好)

模型量化

和其他AI模型一样,超分模型也可以量化:

  • FP32 → FP16 → INT8
  • 体积减小,速度加快
  • 精度损失可控

建议:端侧优先用INT8量化模型。


5.3 输入尺寸优化

超分的计算量和图片尺寸的平方成正比:

  • 200×200 → 4万像素
  • 400×400 → 16万像素(4倍计算量)
  • 800×800 → 64万像素(16倍计算量)

所以,控制输入尺寸是最有效的性能优化手段

优化策略

  1. 限制最大输入尺寸

    • 比如最大边长不超过512px或1024px
    • 超过的先缩小再超分
    • (太大的图,用户也不会放大看细节)
  2. 分块处理

    • 把大图分成小块,一块块处理
    • 处理完再拼起来
    • 内存占用更低
    • 可以并行处理(如果支持)
  3. 按需超分

    • 只超分用户要看的区域
    • 比如用户放大看哪里,超分哪里
    • 类似"看得见的才超分,看不见的不超分

5.4 渐进式加载

对于大图查看,可以用渐进式加载提升体验:

1. 先显示缩略图(快,但模糊)
   ↓
2. 同时开始超分
   ↓
3. 超分完成,替换为高清图

好处

  • 用户不用等,立刻能看到图
  • 从模糊到清晰,有"逐渐清晰的感觉
  • 整体体验更好

5.5 缓存策略

对超分结果做缓存,避免重复计算。

缓存设计

// 超分结果缓存
class SRCache {
  private cache: Map<string, SRCacheItem> = new Map();
  private maxSize: number = 50; // 最多缓存50张

  // 缓存key:图片hash + 倍率 + 模型类型
  private getKey(imageId: string, scale: number, type: string): string {
    return `${imageId}_${scale}_${type}`;
  }

  // 获取缓存
  get(imageId: string, scale: number, type: string): Image | null {
    const key = this.getKey(imageId, scale, type);
    const item = this.cache.get(key);
    if (item) {
      // 更新访问时间(LRU用)
      item.lastAccessTime = Date.now();
      return item.image;
    }
    return null;
  }

  // 设置缓存
  set(imageId: string, scale: number, type: string, image: Image): void {
    const key = this.getKey(imageId, scale, type);
    
    // 超过容量,删除最久未使用的
    if (this.cache.size >= this.maxSize) {
      this.evictLRU();
    }
    
    this.cache.set(key, {
      image: image,
      lastAccessTime: Date.now(),
      createTime: Date.now()
    });
  }

  // LRU淘汰
  private evictLRU(): void {
    let oldestKey = '';
    let oldestTime = Infinity;
    
    for (const [key, item] of this.cache) {
      if (item.lastAccessTime < oldestTime) {
        oldestTime = item.lastAccessTime;
        oldestKey = key;
      }
    }
    
    if (oldestKey) {
      this.cache.delete(oldestKey);
    }
  }

  // 清空缓存
  clear(): void {
    this.cache.clear();
  }
}

interface SRCacheItem {
  image: Image;
  lastAccessTime: number;
  createTime: number;
}

5.6 硬件加速

和其他AI任务一样,超分也可以用硬件加速:

硬件 速度 功耗 说明
NPU/APU 最快 最低 AI专用芯片,优先用
GPU 中等 图形处理器,浮点运算强
CPU 较高 兼容性最好

建议

  • 优先用NPU加速
  • 不支持NPU的设备用GPU
  • CPU是最后的选择

步骤6:超分效果调优

光有速度还不够,效果也要好。我们来聊聊怎么调优超分效果。

6.1 常见的效果问题
问题 表现 原因
过度平滑 像油画一样,不自然 模型太"聪明",生成了不存在的纹理
细节丢失 还是模糊,不清楚 模型能力不够,或参数不对
伪影/ artifacts 奇怪的花纹、色偏色 模型训练不足,或不适合这类图
噪点增多 噪点反而更多了 把噪点也"增强"了
边缘锯齿 边缘有锯齿 上采样方式不好

6.2 效果调优手段

1. 降噪 + 超分 + 锐化 组合拳

单一的超分效果不一定最好,可以组合多种处理:

原图
 ↓
去噪(去除噪点和划痕)
 ↓
超分(放大并增强)
 ↓
锐化(让边缘更清晰)
 ↓
色彩增强(恢复色彩)
 ↓
最终结果

不同的图片,组合不同的处理流程效果更好。


2. 针对不同类型的图片,用不同的模型/参数

不是一个模型通吃所有场景。不同类型的图片,适合不同的处理:

图片类型 优化重点 推荐处理
人像照片 皮肤自然、五官清晰 人像超分 + 磨皮 + 五官增强
风景照片 细节丰富、色彩自然 通用超分 + 色彩增强
文字/文档 文字清晰、背景干净 文字超分 + 二值化增强
老照片 去划痕、去噪、恢复 去噪 + 超分 + 色彩恢复
建筑/文物 边缘锐利、纹理清晰 超分 + 锐化 + 去畸变

3. 多模型融合

可以用多个模型,然后融合结果:

原图 → 模型A → 结果A
      ↓
      模型B → 结果B
      ↓
      融合 → 最终结果

比如:

  • 模型A擅长保持结构
  • 模型B擅长纹理
  • 融合起来,又有结构又有纹理

6.3 老照片修复的特殊处理

老照片修复是个特殊的场景,除了超分,通常还要做很多额外处理:

老照片修复流程
├── 1. 数字化
│   └── 扫描/拍摄
│   └── 倾斜校正
├── 2. 修复
│   ├── 去划痕
│   ├── 去斑点
│   ├── 去折痕
│   └── 去霉点
├── 3. 增强
│   ├── 超分辨率
│   ├── 去噪
│   └── 锐化
├── 4. 色彩
│   ├── 黑白上色
│   ├── 色彩校正
│   └── 色彩增强
└── 5. 输出
    └── 保存/分享

对于「民族图鉴」的老照片:

  • 很多是黑白的,需要上色
  • 很多有划痕破损,需要修复
  • 很多偏色褪色,需要校正

这些可以结合超分一起做,效果更好。


步骤7:实战——实现老照片修复功能

讲了这么多理论,我们来实际实现一个老照片修复功能。

7.1 功能设计

功能名称:老照片修复

功能描述
用户选择一张老照片,AI自动修复,提升清晰度,去除噪点,让老照片焕发新生。

页面结构

老照片修复页
├── 导航栏
├── 图片选择区
│   ├── 占位图(未选择时)
│   └── 选中的图片
├── 操作按钮
│   ├── 选择照片
│   └── 开始修复
├── 修复模式选择
│   ├── 基础修复(快)
│   ├── 增强修复(推荐)
│   └── 极致修复(慢)
├── 修复进度(进度条 + 提示)
└── 结果展示区
    ├── 左右对比滑块
    ├── 放大查看
    ├── 保存到相册
    └── 重新修复

7.2 代码实现

核心代码:

// PhotoRestorationPage.ets
// 老照片修复页面

import router from '@ohos.router';

// 修复模式
enum RestoreMode {
  BASIC = 'basic',       // 基础修复
  ENHANCED = 'enhanced', // 增强修复
  EXTREME = 'extreme',     // 极致修复
}

// 修复进度
interface RestoreProgress {
  stage: string;  // 当前阶段
  percent: number; // 进度百分比
}

@Entry
@Component
struct PhotoRestorationPage {
  @State selectedImage: string = '';
  @State restoreMode: RestoreMode = RestoreMode.ENHANCED;
  @State isRestoring: boolean = false;
  @State progress: RestoreProgress = { stage: '', percent: 0 };
  @State resultImage: string = '';
  @State showCompare: boolean = false;

  // 超分服务
  private srService = SuperResolutionService.getInstance();

  build() {
    Column({ space: 0 }) {
      // 导航栏
      this.buildNavBar()

      Scroll() {
        Column({ space: 16 }) {
          // 图片展示区
          this.buildImageArea()

          // 修复模式选择
          if (this.selectedImage && !this.isRestoring && !this.resultImage) {
            this.buildModeSelector()
          }

          // 操作按钮
          this.buildActionButtons()

          // 修复进度
          if (this.isRestoring) {
            this.buildProgressArea()
          }

          // 结果展示
          if (this.resultImage) {
            this.buildResultArea()
          }
        }
        .width('100%')
        .padding(16)
      }
      .layoutWeight(1)
      .scrollBar(BarState.Off)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8F8F8')
  }

  // 导航栏
  @Builder
  buildNavBar(): void {
    Row() {
      Text('<')
        .fontSize(24)
        .fontColor('#333333')
        .width(40)
        .onClick(() => {
          router.back();
        })

      Text('老照片修复')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
        .layoutWeight(1)
        .textAlign(TextAlign.Center)

      Text('')
        .width(40)
    }
    .width('100%')
    .height(48)
    .backgroundColor('#FFFFFF')
    .alignItems(VerticalAlign.Center)
    .padding({ left: 12, right: 12 })
  }

  // 图片展示区
  @Builder
  buildImageArea(): void {
    Column() {
      if (this.resultImage) {
        // 修复完成:对比视图
        if (this.showCompare) {
          // 左右对比
          Stack() {
            // 修复后(右边)
            Image(this.resultImage)
              .width('100%')
              .aspectRatio(1)
              .objectFit(ImageFit.Cover)

            // 修复前(左边,用clip控制显示宽度)
            Image(this.selectedImage)
              .width('100%')
              .aspectRatio(1)
              .objectFit(ImageFit.Cover)
              .clip(true)
          }
          .width('100%')
          .aspectRatio(1)
          .borderRadius(12)
          .backgroundColor('#EEEEEE')
        } else {
          // 只显示修复后
          Image(this.resultImage)
            .width('100%')
            .aspectRatio(1)
            .objectFit(ImageFit.Cover)
            .borderRadius(12)
        }
      } else if (this.selectedImage) {
        // 已选择,未修复
        Image(this.selectedImage)
          .width('100%')
          .aspectRatio(1)
          .objectFit(ImageFit.Cover)
          .borderRadius(12)
      } else {
        // 未选择图片
        Column({ space: 12 }) {
          Text('🖼️')
            .fontSize(48)

          Text('选择一张老照片')
            .fontSize(16)
            .fontColor('#666666')

          Text('AI自动修复,让老照片焕发新生')
            .fontSize(14)
            .fontColor('#999999')
        }
        .width('100%')
        .aspectRatio(1)
        .backgroundColor('#FFFFFF')
        .borderRadius(12)
        .border({ width: 1, color: '#EEEEEE', style: BorderStyle.Dashed })
        .justifyContent(FlexAlign.Center)
      }
    }
    .width('100%')
  }

  // 修复模式选择
  @Builder
  buildModeSelector(): void {
    Column({ space: 12 }) {
      Text('修复模式')
        .fontSize(14)
        .fontColor('#666666')
        .width('100%')

      Row({ space: 8 }) {
        this.buildModeCard(
          RestoreMode.BASIC,
          '基础修复',
          '2x超分 · 快速',
          this.restoreMode === RestoreMode.BASIC
        )
        this.buildModeCard(
          RestoreMode.ENHANCED,
          '增强修复',
          '3x超分 · 推荐',
          this.restoreMode === RestoreMode.ENHANCED
        )
        this.buildModeCard(
          RestoreMode.EXTREME,
          '极致修复',
          '4x超分 · 最佳效果',
          this.restoreMode === RestoreMode.EXTREME
        )
      }
      .width('100%')
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .alignItems(HorizontalAlign.Start)
  }

  // 模式卡片
  @Builder
  buildModeCard(mode: RestoreMode, title: string, desc: string, selected: boolean): void {
    Column({ space: 4 }) {
      Text(title)
        .fontSize(14)
        .fontWeight(selected ? FontWeight.Bold : FontWeight.Normal)
        .fontColor(selected ? '#FF6B35' : '#333333')

      Text(desc)
        .fontSize(12)
        .fontColor('#999999')
    }
    .layoutWeight(1)
    .height(60)
    .backgroundColor(selected ? '#FFF5F0' : '#F8F8F8')
    .borderRadius(8)
    .border({
      width: selected ? 2 : 1,
      color: selected ? '#FF6B35' : '#EEEEEE'
    })
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .onClick(() => {
      this.restoreMode = mode;
    })
  }

  // 操作按钮
  @Builder
  buildActionButtons(): void {
    if (!this.selectedImage && !this.isRestoring && !this.resultImage) {
      // 未选择图片
      Button('选择照片')
        .type(ButtonType.Normal)
        .width('100%')
        .height(48)
        .borderRadius(24)
        .backgroundColor('#FF6B35')
        .fontColor('#FFFFFF')
        .fontSize(16)
        .onClick(() => {
          this.pickImage();
        })
    } else if (this.selectedImage && !this.isRestoring && !this.resultImage) {
      // 已选择,未修复
      Row({ space: 12 }) {
        Button('重新选择')
          .type(ButtonType.Normal)
          .layoutWeight(1)
          .height(44)
          .borderRadius(22)
          .backgroundColor('#FFFFFF')
          .fontColor('#333333')
          .fontSize(15)
          .border({ width: 1, color: '#DDDDDD' })
          .onClick(() => {
            this.pickImage();
          })

        Button('开始修复')
          .type(ButtonType.Normal)
          .layoutWeight(1)
          .height(44)
          .borderRadius(22)
          .backgroundColor('#FF6B35')
          .fontColor('#FFFFFF')
          .fontSize(15)
          .onClick(() => {
            this.startRestore();
          })
      }
      .width('100%')
    } else if (this.resultImage) {
      // 修复完成
      Row({ space: 12 }) {
        Button('保存到相册')
          .type(ButtonType.Normal)
          .layoutWeight(1)
          .height(44)
          .borderRadius(22)
          .backgroundColor('#FF6B35')
          .fontColor('#FFFFFF')
          .fontSize(15)
          .onClick(() => {
            this.saveToAlbum();
          })

        Button('重新修复')
          .type(ButtonType.Normal)
          .layoutWeight(1)
          .height(44)
          .borderRadius(22)
          .backgroundColor('#FFFFFF')
          .fontColor('#333333')
          .fontSize(15)
          .border({ width: 1, color: '#DDDDDD' })
          .onClick(() => {
            this.reset();
          })
      }
      .width('100%')
    }
  }

  // 修复进度
  @Builder
  buildProgressArea(): void {
    Column({ space: 12 }) {
      Text(this.progress.stage)
        .fontSize(14)
        .fontColor('#666666')

      // 进度条
      Stack({ alignContent: Alignment.Start }) {
        // 背景
        Row()
          .width('100%')
          .height(6)
          .backgroundColor('#EEEEEE')
          .borderRadius(3)

        // 进度
        Row()
          .width(`${this.progress.percent}%`)
          .height(6)
          .backgroundColor('#FF6B35')
          .borderRadius(3)
      }
      .width('100%')

      Text(`${this.progress.percent}%`)
        .fontSize(12)
        .fontColor('#999999')
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .alignItems(HorizontalAlign.Center)
  }

  // 结果展示区
  @Builder
  buildResultArea(): void {
    Column({ space: 12 }) {
      // 对比切换
      Row() {
        Text(this.showCompare ? '查看对比' : '查看结果')
          .fontSize(14)
          .fontColor('#FF6B35')

        Toggle({ type: ToggleType.Switch, isOn: this.showCompare })
          .selectedColor('#FF6B35')
          .onChange((value: boolean) => {
            this.showCompare = value;
          })
      }
      .width('100%')
      .justifyContent(FlexAlign.End)

      // 说明文字
      Text('修复完成!点击切换查看前后对比')
        .fontSize(13)
        .fontColor('#999999')
        .width('100%')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
  }

  // ---------- 功能方法 ----------

  // 选择图片
  private pickImage(): void {
    // 调用系统相册选择
    // 实际项目中用 photoAccessHelper
    this.mockPickImage();
  }

  // 模拟选择图片
  private mockPickImage(): void {
    // 模拟选了一张老照片
    this.selectedImage = 'resource://rawfile/17_dai.jpg';
    this.resultImage = '';
    this.showCompare = false;
  }

  // 开始修复
  private async startRestore(): Promise<void> {
    if (!this.selectedImage || this.isRestoring) {
      return;
    }

    this.isRestoring = true;
    this.resultImage = '';
    this.progress = { stage: '准备中...', percent: 0 };

    try {
      // 模拟修复进度
      await this.simulateRestoreProgress();
      
      // 执行真实超分
      // const result = await this.srService.upscale(
      //   this.selectedImage,
      //   this.getScaleByMode(this.restoreMode),
      //   SRType.GENERAL
      // );
      
      // 模拟结果(实际项目替换为真实结果)
      this.resultImage = this.selectedImage; // 简化:用同一张图模拟
      
    } catch (e) {
      console.error('[Restore] failed:', JSON.stringify(e));
    } finally {
      this.isRestoring = false;
    }
  }

  // 模拟修复进度
  private async simulateRestoreProgress(): Promise<void> {
    const stages = [
      { stage: '加载图片...', percent: 10 },
      { stage: '去噪处理...', percent: 30 },
      { stage: 'AI超分中...', percent: 60 },
      { stage: '细节增强...', percent: 85 },
      { stage: '完成!', percent: 100 },
    ];

    for (const s of stages) {
      this.progress = s;
      await new Promise(resolve => setTimeout(resolve, 600));
    }
  }

  // 根据模式获取倍率
  private getScaleByMode(mode: RestoreMode): number {
    switch (mode) {
      case RestoreMode.BASIC: return 2;
      case RestoreMode.ENHANCED: return 3;
      case RestoreMode.EXTREME: return 4;
      default: return 2;
    }
  }

  // 保存到相册
  private saveToAlbum(): void {
    // 保存图片到系统相册
    // 实际项目中用 photoAccessHelper
    console.log('Save to album');
  }

  // 重置
  private reset(): void {
    this.resultImage = '';
    this.showCompare = false;
    this.progress = { stage: '', percent: 0 };
  }
}

// 模拟的超分服务
class SuperResolutionService {
  private static instance: SuperResolutionService;
  static getInstance(): SuperResolutionService {
    if (!SuperResolutionService.instance) {
      SuperResolutionService.instance = new SuperResolutionService();
    }
    return SuperResolutionService.instance;
  }
  // 实际方法...
}

7.3 前后对比效果展示

一个好的超分功能,一定要有前后对比,让用户直观看到效果。

对比方式

  1. 左右滑动对比

    • 左边是原图,右边是修复后
    • 用户可以滑动分割线,对比不同区域
    • 最直观的对比方式
  2. 点击切换

    • 点击图片,在原图和修复后之间切换
    • 简单直接
  3. 双图并列

    • 上面原图,下面修复后
    • 或者左右并排
    • 适合整体对比
  4. 放大镜对比

    • 一个圆形放大镜
    • 移动放大镜,圈内是修复后,圈外是原图
    • 适合看细节

建议

  • 主对比用左右滑动(最直观)
  • 辅助用点击切换(最简单)
  • 细节看用放大镜(最清楚)

⚠️ 常见问题与解答

Q1:超分太慢了,用户等不及怎么办?

A:超分确实是计算密集型任务。几个优化方向:

1. 性能优化(技术层面)

  • 用轻量模型,牺牲一点效果换速度
  • 模型量化:INT8比FP32快2-3倍
  • 硬件加速:NPU > GPU > CPU
  • 减小输入尺寸:输入越小越快

2. 体验优化(产品层面)

  • 给用户明确的进度反馈
  • 进度条 + 文字提示(“正在处理中,预计还需X秒”)
  • 不要让用户傻等,不知道还要等多久

3. 功能设计

  • 提供不同速度/质量档位
  • 快速模式(快,但效果一般)
  • 高质量模式(慢,但效果好)
  • 让用户自己选

4. 预加载/后台处理

  • 预判用户可能要看的图,提前超分
  • 后台默默处理好,等用户要看时已经好了
  • (但要注意不要太耗电)

经验值

  • 2秒以内:用户觉得"很快
  • 2-5秒:可以接受
  • 5秒以上:有点慢了
  • 10秒以上:很多用户会放弃

Q2:超分效果不自然,像油画一样怎么办?

A:这是AI超分常见的问题,叫"过度平滑"或"油画感"。几个解决方法:

1. 调整模型/参数

  • 换更适合的模型
  • 调整超分的强度/权重
  • 不要过度超分,适当"减弱效果

2. 混合传统方法结合

  • AI超分 + 原始图按比例混合
  • 比如70%超分结果 + 30%传统放大结果
  • 既有超分的清晰度,又保持自然
  • 不会太"假"

3. 分区域处理

  • 不同区域用不同强度
  • 比如皮肤区域柔一点(自然)
  • 边缘、纹理区域强一点(清晰)
  • 效果更自然

4. 后处理

  • 适当加一点点噪点(增加真实感)
  • 适当锐化(增加细节感)
  • 色彩校正(避免偏色)

Q3:超分会丢失细节,还是模糊怎么办?

A:如果超分后还是模糊,可能的原因和解决方法:

1. 模型能力不够

  • 换更大、更强的模型
  • 用专门训练的专用模型(比通用模型好)

2. 输入质量太差

  • 原图太模糊了,神仙也救不了
  • 先做去模糊、去噪预处理
  • 实在太差的图,提示用户"图片质量太差,效果可能有限"

3. 倍率太高

  • 4x超分肯定比2x超分难
  • 适当降低倍率,效果更好
  • 不要盲目追求高倍率

4. 后处理增强

  • 超分后再加锐化
  • 适当增强对比度
  • 细节会更清楚

Q4:超分会不会把噪点也增强了,噪点更多了怎么办?

A:这是个常见问题。AI超分可能会把噪点也"增强"。解决方法:

1. 先去噪,再超分

  • 超分前先做去噪处理
  • 把噪点去掉,再超分
  • 顺序很重要:去噪 → 超分 → 锐化

2. 用带去噪功能的超分模型

  • 有些超分模型自带去噪能力
  • 一步到位,效果更好
  • 比如Real-ESRGAN等

3. 超分后再做轻度去噪

  • 超分后做轻度去噪
  • 去掉超分产生的伪影和噪点
  • 注意不要把细节也去没了

Q5:端侧超分效果不如云端,怎么办?

A:端侧模型受限于体积和算力,确实不如云端大模型。几个思路:

1. 端云结合

  • 默认用端侧超分(快、隐私)
  • 用户需要更好的效果"时,再用云端超分
  • 兼顾速度和质量

2. 分场景使用

  • 缩略图放大、列表页:用端侧小模型(快)
  • 用户主动"修复":可以选择云端大模型(效果好)
  • 不同场景用不同方案

3. 持续迭代模型

  • 收集用户数据,持续优化模型
  • 模型越来越强
  • 端侧也能越来越好

📝 本章小结

核心知识点

本文系统讲解了图像超分辨率技术的知识体系:

1. 什么是图像超分

  • 从低分辨率图恢复高分辨率图
  • 传统插值方法 vs AI方法
  • AI超分效果好太多了

2. 技术原理

  • 传统插值:双线性、双三次等,效果有限
  • AI超分:深度学习模型,"学习"高清-低清映射
  • 经典模型:SRCNN、ESRGAN、Real-ESRGAN等

3. 应用场景

  • 老照片修复:历史照片增强
  • 缩略图放大:点击即高清
  • 文档增强:文字图片清晰化
  • 视频超分:低清转高清

4. 鸿蒙端侧超分能力

  • 通用超分、人像超分、文字超分
  • 2x/3x/4x倍率
  • 封装好的API,开箱即用

5. 「民族图鉴」应用设计

  • 老照片修复功能
  • 缩略图智能放大
  • 文档/文字增强

6. 性能优化

  • 模型选择与量化
  • 输入尺寸优化
  • 渐进式加载
  • 缓存策略
  • 硬件加速

7. 效果调优

  • 去噪 + 超分 + 锐化 组合
  • 不同图片类型,不同处理
  • 多模型融合
  • 老照片特殊处理流程

最佳实践总结

速度与质量的平衡

不要追求极限质量,找到平衡点
  - 列表页:快就行,用小模型
  - 详情页:平衡,用中模型  
  - 用户主动修复:质量优先,用大模型
不同场景,不同策略

超分不是万能的

超分可以让模糊的图变清晰
但不能凭空创造不存在的信息
太模糊的图,神仙也救不了
管理用户预期,不要吹得太厉害

对比是最好的展示

说一百遍"变清晰了,
不如让用户亲眼看看前后对比
左右滑动对比、点击切换对比
直观的对比,胜过千言万语

系列总结

到这里,鸿蒙7新特性篇的5篇文章就全部结束了。让我们回顾一下:

第71篇:鸿蒙7全景——五大创新方向与九大Kit升级

  • 智能化、空间化、多窗交互、高性能、全场景
  • AI Kit、图形Kit、多媒体Kit、分布式Kit、窗口Kit等九大Kit升级

第72篇:Skill技能开发——小艺技能接入与语音交互

  • 意图、槽位、对话流
  • 「民族图鉴」Skill设计
  • Skill与App联动

第73篇:Agent智能体——A2A协议与系统级AI能力

  • Agent的四大核心能力
  • 元能力开发
  • 民族文化问答、旅游规划、学习助手三个Agent

第74篇:视觉AI能力——端侧大模型与场景化控件

  • 图像分类、物体检测、OCR、人脸识别、场景识别
  • 民族服饰拍照识别
  • 端侧推理性能优化

第75篇:图像超分AI——老照片修复与画质增强

  • 传统插值 vs AI超分
  • 老照片修复实战
  • 性能优化与效果调优

下一步展望

鸿蒙7新特性篇虽然结束了,但学习的脚步不会停止。

技术在不断发展,鸿蒙系统也在持续演进。从最早的分布式能力,到AI能力不断升级,我们见证了鸿蒙从"能用"到"好用"再到"智能"的演进之路。

作为开发者,我们需要:

  • 保持学习的心态,与时俱进
  • 关注新技术,但不盲从
  • 从用户需求出发,技术为产品服务
  • 在实践中成长,在项目中精进

「民族图鉴」这个项目,也还有很多可以探索的方向:

  • 把学到的新特性逐步落地
  • 持续优化用户体验
  • 探索更多AI能力
  • 做出更有价值的功能

技术之路,永无止境。愿我们都能在技术的海洋中,不断成长,不断进步。


💡 最后想说的话

技术是工具,人才是目的。

无论是鸿蒙系统、AI能力、还是其他新技术,最终都是为了给用户创造更好的体验、更大的价值。

不要为了AI而AI,不要为了新技术而新技术。始终记得:**用户需要什么,我们就做什么。技术只是实现目标的手段,而不是目标本身。

希望这5篇文章,能给你带来一些启发和帮助。也希望「民族图鉴」能越做越好,成为传播民族文化的优秀载体。

我们后会有期!

Logo

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

更多推荐