HarmonyOS 6 轻相机应用开发4:物品分类功能实现

HarmonyOS 6 轻相机应用开发4:物品分类功能实现

引言

之前章节实现了基础的贴纸和滤镜效果,接下来就要开始接入AI能力。如果说滤镜是艺术的装点,那么 AI 识别就是相机的"智慧之眼"。

今天,我们将挑战更高级的能力:全能识物 。我们将探讨如何基于 MindSpore Lite 端侧推理引擎,在 HarmonyOS 6 上实现毫秒级的物品检测与分类,并让结果实时跃然于预览之上。

技术方案:一机多模的动态架构

在"轻相机"的设计中,我们没有为每种识别写一套逻辑,而是构建了一个名为 FaceDetector(实为通用推理器)的 C++ 基类。

它通过 NAPI 暴露了 switchAiMode 接口,允许我们在运行时动态切换模型文件。只需一行代码,相机就能从"认脸"切换到"识物":

typescript 复制代码
// ArkTS 层发起模式切换
CameraController.switchAiMode("models/detect_regular_nms_quant.ms", 320, 320);

底层 C++ 引擎会自动解析新模型的 Input/Output 维度,重新配置内存池,并继续接收来自预览流的 YUV 指针进行异步推理。

模型与数据集:百类识物

我们采用了一个经过量化的 SSD(Single Shot MultiBox Detector) 模型。该模型不仅能返回物体的位置(Bounding Box),还能根据内置的 OBJECT_LABELS 词典返回高达 300+ 类的分类标签(如:Cat, Bottle, Mobile phone, Cup 等)。

这些标签被定义在 ObjectDetectionUtil.ets 中,作为后期视觉渲染的依据。

核心算法:SSD 坐标解码与 NMS 抑制

由于神经网络输出的是原始的张量(Tensor),我们需要在 ArkTS 层进行数学解码。

1. SSD 坐标解码

模型输出的坐标通常是相对于 Anchor(锚点)的偏移量。我们需要根据输入比例(如 320x320)计算回真实坐标:

typescript 复制代码
static decodeSSD(reg: number[], cls: number[], anchors: SSDAnchor[], scoreThresh: number): DetectedObject[] {
    const results: DetectedObject[] = [];
    for (let i = 0; i < anchors.length; i++) {
        let score = 1.0 / (1.0 + Math.exp(-cls[i])); // Sigmoid 激活
        if (score > scoreThresh) {
            const p = i * 4;
            const cx = reg[p] + anchors[i].x_center;
            const cy = reg[p + 1] + anchors[i].y_center;
            // ... 转换为标准化矩形坐标 [x1, y1, x2, y2]
        }
    }
    return results;
}
2. 非极大值抑制(NMS)

为了解决同一个物体被多个检测框覆盖的问题,我们引入了 NMS 算法,保留置信度最高且重叠度(IOU)最小的候选框。

ArkTS 实战:实时识物与视觉反馈

识别结果通过 registerFaceListener(通用 AI 回调)异步返回给 UI。我们在主界面的 Canvas 叠加层上进行动态绘制:

typescript 复制代码
private renderAIOverlay() {
  if (!this.context) return;
  this.context.clearRect(0, 0, this.compWidth, this.compHeight);
  
  if (this.aiMode === 'object') {
    this.detectedObjects.forEach((obj) => {
      // 绘制定制化的青色识别框
      this.context.lineWidth = 3;
      this.context.strokeStyle = '#22D3EE'; 
      this.context.strokeRect(x, y, w, h);
      
      // 绘制半透明标签底色
      this.context.fillStyle = 'rgba(34,211,238,0.8)';
      this.context.fillRect(x, y - 30, textWidth + 16, 30);
      
      // 绘制识别名称与置信度
      this.context.fillStyle = Color.Black;
      this.context.fillText(`${obj.label} ${(obj.score*100).toFixed(0)}%`, x + 8, y - 8);
    });
  }
}

为了保证渲染性能,我们将 renderAIOverlay 放在 @Watch('onAIUpdate') 中,只有当 AI 结果真实变化时,才触发 Canvas 的重绘,显著降低了预览时的 CPU 占用。

进阶:如何将 AI 识别框"拍"进照片?

很多开发者发现,预览时有框,但拍出来的照片却空空如也。

在"轻相机"中,我们利用 OffscreenCanvas(离屏画布) 解决了这一痛点。在执行 saveCapturedPhoto 时,我们将原始图片数据解析为 PixelMap,然后在其上层同步绘制当前的识别框,最后再执行编码保存:

typescript 复制代码
// 1. 绘制原始底图
ctx.drawImage(bgPixelMap, 0, 0, imgW, imgH);
// 2. 按照比例缩放并叠加 AI 识别信息
if (this.saveAIOverlays) {
    this.detectedObjects.forEach(obj => {
        ctx.strokeRect(obj.x1 * imgW, obj.y1 * imgH, ...);
    });
}
// 3. 统一打包保存
const finalPixelMap = ctx.getPixelMap(0, 0, imgW, imgH);
效果展示

点击AI按钮出现选择AI智能模式后选择全物识别,当识别到物品时会通过框线标记出来:

总结

到这里,"轻相机"系列的核心功能------从底层预览到高阶滤镜,再到实时贴纸与 AI 识物------已经全部落实。

通过这四篇文章的实战,我们深度探索了 HarmonyOS 6 在 Native 渲染与本地 AI 推理方面的强大底蕴。希望这一系列能够成为你探索鸿蒙应用开发的助推器,开发出更多具有"智慧灵魂"的作品。

相关推荐
jiejiejiejie_2 小时前
Flutter for OpenHarmony 底部导航栏交互优化实战
flutter·华为·交互·harmonyos
IntMainJhy2 小时前
Flutter 三方库 share_plus 的鸿蒙化适配与实战指南
flutter·华为·harmonyos
_waylau2 小时前
HarmonyOS 6.0升级至6.1改动点
华为·ai·harmonyos·鸿蒙·鸿蒙系统
木斯佳2 小时前
HarmonyOS 数据可视化实战:封装自定义值机控件实操记录与复盘
信息可视化·harmonyos
wayz112 小时前
Day 15 编程实战:KMeans聚类与股票风格分类
算法·机器学习·分类·kmeans·聚类
李李李勃谦2 小时前
基于鸿蒙PC多窗口架构的任务管理与番茄钟工作流实践
华为·架构·harmonyos
零度@3 小时前
鸿蒙应用发布到华为应用市(AppGallery)的完整流程
华为·harmonyos
m0_640309303 小时前
HarmonyOS 5.0 IoT开发实战:构建分布式智能设备控制中枢与边缘计算网关
分布式·物联网·harmonyos
Dev7z3 小时前
基于卷积神经网络(CNN)的脑电信号分类及可解释性分析
人工智能·分类·cnn