第16篇:HarmonyOS AI能力概述与集成

📚 本篇导读

在前面的教程中,我们已经完成了地图导航、数据分析等核心功能。从本篇开始,我们将进入AI能力的学习,这是HarmonyOS平台的一大亮点。通过集成HarmonyOS AI Kit,我们可以为应用添加图像识别、语音合成等智能功能,让农业管理更加智能化。

本篇将实现

  • 🤖 HarmonyOS AI Kit概述(Vision Kit、Speech Kit)
  • 🔧 Vision Kit集成配置(图像识别能力)
  • 🎙️ Core Speech Kit集成配置(语音合成能力)
  • 🔐 AI能力权限配置
  • ⚙️ AI服务初始化

🎯 学习目标

完成本篇教程后,你将掌握:

  1. HarmonyOS AI Kit的整体架构和能力
  2. 如何集成Vision Kit实现图像识别
  3. 如何集成Core Speech Kit实现语音合成
  4. AI能力所需的权限配置
  5. AI服务的初始化流程

一、HarmonyOS AI Kit概述

1.1 什么是HarmonyOS AI Kit?

HarmonyOS AI Kit是华为提供的端侧AI能力开放平台,为开发者提供了一系列开箱即用的AI能力,包括:

AI能力 说明 应用场景
Vision Kit 图像识别与分析 植物识别、病虫害诊断、文字识别
Speech Kit 语音识别与合成 语音播报、语音输入
NLP Kit 自然语言处理 文本分析、智能问答
Translation Kit 翻译服务 多语言翻译

本项目使用的AI能力

  • Vision Kit:用于植物识别、病虫害诊断
  • Core Speech Kit (TTS):用于操作提示的语音播报

1.2 AI能力的优势

端侧AI的优势

  • 🚀 响应快速:无需网络请求,毫秒级响应
  • 🔒 隐私保护:数据不上传云端,本地处理
  • 💰 成本低廉:无需调用云端API,节省费用
  • 📱 离线可用:无网络环境也能使用

1.3 AI能力架构

应用层
  ├── ImageScanPage(图像识别页面)
  └── TTSService(语音合成服务)
       ↓
AI Kit层
  ├── Vision Kit
  │   ├── ImageAnalyzer(图像分析器)
  │   ├── TEXT(文字识别)
  │   ├── SUBJECT(主体识别)
  │   └── OBJECT_LOOKUP(物体搜索)
  └── Core Speech Kit
      ├── TextToSpeechEngine(TTS引擎)
      ├── speak()(朗读文本)
      └── stop()(停止播报)
       ↓
系统层
  └── HarmonyOS AI能力底层

二、Vision Kit集成

2.1 Vision Kit简介

Vision Kit提供了强大的图像识别能力,主要包括:

识别类型 枚举值 功能说明
文字识别 ImageAnalyzerType.TEXT 识别图片中的文字(OCR)
主体识别 ImageAnalyzerType.SUBJECT 识别图片主体并支持抠图
物体搜索 ImageAnalyzerType.OBJECT_LOOKUP 识别物体并提供搜索功能

2.2 导入Vision Kit

在页面文件中导入Vision Kit相关模块:

// 导入Vision Kit
import { visionImageAnalyzer } from '@kit.VisionKit';
// 导入图像处理相关
import { image } from '@kit.ImageKit';
// 导入文件操作
import { fileIo } from '@kit.CoreFileKit';
import { picker } from '@kit.CoreFileKit';
// 导入相机
import { cameraPicker } from '@kit.CameraKit';
import { camera } from '@kit.CameraKit';

模块说明

  • @kit.VisionKit:Vision Kit核心模块
  • @kit.ImageKit:图像处理模块(PixelMap)
  • @kit.CoreFileKit:文件操作模块
  • @kit.CameraKit:相机调用模块

2.3 创建图像分析控制器

@Entry
@ComponentV2
struct ImageScanPage {
  // 选中的图片URI
  @Local selectedImageUri: string = '';
  
  // 选中的图片PixelMap(用于显示和识别)
  @Local selectedPixelMap: image.PixelMap | null = null;
  
  // Vision Kit图像分析控制器
  private visionImageAnalyzerController: visionImageAnalyzer.VisionImageAnalyzerController =
    new visionImageAnalyzer.VisionImageAnalyzerController();
}

关键点

  • VisionImageAnalyzerController:图像分析控制器,负责管理识别过程
  • PixelMap:图像的像素数据,Vision Kit需要RGBA_8888格式
  • 控制器在页面创建时初始化,无需额外配置

2.4 设置识别监听器

在页面显示时设置各种识别事件的监听器:

onPageShow(): void {
  // 1. 监听识别界面可见性变化
  this.visionImageAnalyzerController.on('imageAnalyzerVisibilityChange',
    (visibility: visionImageAnalyzer.ImageAnalyzerVisibility) => {
      console.info('[ImageScanPage] 识别界面可见性:', JSON.stringify(visibility));
    });
  
  // 2. 监听文字识别结果
  this.visionImageAnalyzerController.on('textAnalysis', (text: string) => {
    console.info('[ImageScanPage] 文字识别结果:', text);
    // 可以在这里处理识别到的文字
  });
  
  // 3. 监听选中文字变化
  this.visionImageAnalyzerController.on('selectedTextChange', (selectedText: string) => {
    console.info('[ImageScanPage] 选中文字:', selectedText);
  });
  
  // 4. 监听主体识别结果
  this.visionImageAnalyzerController.on('subjectAnalysis', 
    (subjects: visionImageAnalyzer.Subject[]) => {
      console.info('[ImageScanPage] 主体识别结果:', JSON.stringify(subjects));
      // 可以在这里处理识别到的主体
    });
  
  // 5. 监听选中主体变化
  this.visionImageAnalyzerController.on('selectedSubjectsChange', 
    (subjects: visionImageAnalyzer.Subject[]) => {
      console.info('[ImageScanPage] 选中主体:', JSON.stringify(subjects));
    });
  
  // 6. 监听识别失败
  this.visionImageAnalyzerController.on('analyzerFailed', (error: BusinessError) => {
    console.error('[ImageScanPage] 识别失败:', JSON.stringify(error));
    promptAction.showToast({
      message: '识别失败,请重试',
      duration: 2000
    });
  });
}

监听器说明

监听器 触发时机 用途
imageAnalyzerVisibilityChange 识别界面显示/隐藏 监控识别状态
textAnalysis 文字识别完成 获取OCR结果
selectedTextChange 用户选中文字 处理选中的文字
subjectAnalysis 主体识别完成 获取主体信息
selectedSubjectsChange 用户选中主体 处理选中的主体
analyzerFailed 识别失败 错误处理

2.5 在Image组件中启用AI识别

Vision Kit的核心是通过Image组件的特殊配置来启用AI识别:

// 图片预览区域
if (this.selectedPixelMap) {
  Image(this.selectedPixelMap, {
    // 配置识别类型
    types: [
      ImageAnalyzerType.TEXT,          // 文字识别
      ImageAnalyzerType.SUBJECT,       // 主体识别
      ImageAnalyzerType.OBJECT_LOOKUP  // 物体搜索
    ],
    // 绑定控制器
    aiController: this.visionImageAnalyzerController
  })
    .width('100%')
    .height(400)
    .objectFit(ImageFit.Contain)
    .borderRadius(12)
    .enableAnalyzer(true)  // 启用AI分析器
}

关键配置

  • types:指定要启用的识别类型(可多选)
  • aiController:绑定图像分析控制器
  • enableAnalyzer(true):启用AI分析功能

用户交互

  • 用户长按图片会触发识别
  • 系统会自动显示识别结果的交互界面
  • 用户可以选择文字、主体进行操作(复制、分享、搜索等)

2.6 图片选择与转换

Vision Kit需要PixelMap格式的图片,我们需要将URI转换为PixelMap:

/**
 * 从相册选择图片
 */
async selectImageFromGallery(): Promise<void> {
  try {
    // 1. 配置选择器选项
    const photoSelectOptions = new picker.PhotoSelectOptions();
    photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
    photoSelectOptions.maxSelectNumber = 1;  // 只选择一张

    // 2. 打开相册选择器
    const photoPicker = new picker.PhotoViewPicker();
    const photoSelectResult = await photoPicker.select(photoSelectOptions);

    // 3. 获取选中的图片URI
    if (photoSelectResult && photoSelectResult.photoUris &&
        photoSelectResult.photoUris.length > 0) {
      this.selectedImageUri = photoSelectResult.photoUris[0];
      console.info('[ImageScanPage] 选中图片URI:', this.selectedImageUri);

      // 4. 将URI转换为PixelMap
      await this.convertUriToPixelMap(this.selectedImageUri);
    }
  } catch (error) {
    const err = error as BusinessError;
    console.error('[ImageScanPage] 选择图片失败:', err);
    promptAction.showToast({
      message: '选择图片失败',
      duration: 2000
    });
  }
}

/**
 * 将URI转换为PixelMap(RGBA_8888格式)
 */
async convertUriToPixelMap(uri: string): Promise<void> {
  try {
    // 1. 打开文件
    const file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY);

    // 2. 创建ImageSource
    const imageSourceApi: image.ImageSource = image.createImageSource(file.fd);

    // 3. 创建PixelMap,指定格式为RGBA_8888(Vision Kit要求)
    const pixelMap: image.PixelMap = await imageSourceApi.createPixelMap({
      desiredPixelFormat: image.PixelMapFormat.RGBA_8888
    });

    // 4. 保存PixelMap
    this.selectedPixelMap = pixelMap;

    // 5. 释放资源
    await imageSourceApi.release();
    fileIo.closeSync(file);

    console.info('[ImageScanPage] PixelMap创建成功');
  } catch (error) {
    const err = error as BusinessError;
    console.error('[ImageScanPage] 转换PixelMap失败:', err);
    promptAction.showToast({
      message: '图片加载失败',
      duration: 2000
    });
  }
}

转换流程

  1. 打开图片文件获取文件描述符(fd)
  2. 使用ImageSource创建图像源
  3. 创建PixelMap并指定RGBA_8888格式
  4. 释放资源避免内存泄漏

重要提示

  • Vision Kit要求PixelMap格式为RGBA_8888
  • 必须释放ImageSource和文件资源
  • 转换过程是异步的,需要使用await

2.7 相机拍照

除了从相册选择,还可以调用相机拍照:

/**
 * 拍照
 */
async takePhoto(): Promise<void> {
  try {
    const context = getContext(this) as common.UIAbilityContext;

    // 1. 配置相机参数
    const pickerProfile: cameraPicker.PickerProfile = {
      cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,  // 后置摄像头
      saveUri: ''  // 空表示使用默认路径
    };

    // 2. 调用系统相机拍照
    const result: cameraPicker.PickerResult = await cameraPicker.pick(
      context,
      [cameraPicker.PickerMediaType.PHOTO],  // 拍照模式
      pickerProfile
    );

    // 3. 获取拍照结果
    if (result && result.resultCode === 0 && result.resultUri) {
      this.selectedImageUri = result.resultUri;
      console.info('[ImageScanPage] 拍照URI:', this.selectedImageUri);

      // 4. 转换为PixelMap
      await this.convertUriToPixelMap(this.selectedImageUri);
    }
  } catch (error) {
    const err = error as BusinessError;
    console.error('[ImageScanPage] 拍照失败:', err);
    promptAction.showToast({
      message: '拍照失败',
      duration: 2000
    });
  }
}

相机配置说明

  • CAMERA_POSITION_BACK:使用后置摄像头(也可选择前置)
  • PickerMediaType.PHOTO:拍照模式(也可选择视频)
  • resultCode === 0:表示拍照成功

三、Core Speech Kit集成(TTS语音合成)

3.1 Core Speech Kit简介

Core Speech Kit提供了文字转语音(TTS)和语音识别(ASR)能力,本项目使用TTS功能实现语音播报。

TTS功能特点

  • 🎙️ 支持多种音色(男声、女声)
  • 🌐 支持多语言(中文、英文等)
  • ⚙️ 可调节语速、音量、音调
  • 📱 支持在线和离线模式

3.2 创建TTS服务类

为了方便复用,我们创建一个单例的TTS服务类:

文件位置entry/src/main/ets/services/TTSService.ets

/**
 * AI语音合成服务 - 使用 TextToSpeech API
 */
import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * TTS服务类(单例模式)
 */
export class TTSService {
  private static instance: TTSService | null = null;
  private ttsEngine: textToSpeech.TextToSpeechEngine | null = null;
  private isInitialized: boolean = false;

  private constructor() {}

  /**
   * 获取单例实例
   */
  static getInstance(): TTSService {
    if (TTSService.instance === null) {
      TTSService.instance = new TTSService();
    }
    return TTSService.instance;
  }

  /**
   * 初始化TTS引擎
   */
  async initialize(): Promise<void> {
    if (this.isInitialized) {
      console.info('[TTSService] 已经初始化');
      return;
    }

    try {
      // 1. 配置引擎参数
      let extraParam: Record<string, Object> = {
        'style': 'interaction-broadcast',  // 交互播报风格
        'locate': 'CN',                    // 中国地区
        'name': 'LangduTTS'                // 引擎名称
      };

      let initParamsInfo: textToSpeech.CreateEngineParams = {
        language: 'zh-CN',  // 中文
        person: 0,          // 音色:0=聆小珊(女声)
        online: 1,          // 在线模式
        extraParams: extraParam
      };

      // 2. 创建TTS引擎
      this.ttsEngine = await textToSpeech.createEngine(initParamsInfo);
      this.isInitialized = true;
      console.info('[TTSService] 初始化成功');
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[TTSService] 初始化失败: ${err.code} - ${err.message}`);
      throw Error(`TTS初始化失败: ${err.message}`);
    }
  }
}

// 导出单例实例
export const ttsService = TTSService.getInstance();

初始化参数说明

参数 说明 可选值
language 语言 ‘zh-CN’(中文)、‘en-US’(英文)
person 音色 0(女声)、1(男声)
online 模式 0(离线)、1(在线)
style 风格 ‘interaction-broadcast’(交互播报)

3.3 实现语音播报方法

/**
 * 朗读文本
 * @param text 要朗读的文本(最大10000字符)
 * @param speed 语速(0.5-2.0),默认1.0
 * @param volume 音量(0.0-1.0),默认1.0
 */
async speak(text: string, speed: number = 1.0, volume: number = 1.0): Promise<void> {
  if (!this.isInitialized || this.ttsEngine === null) {
    console.error('[TTSService] 服务未初始化');
    throw Error('TTS服务未初始化');
  }

  if (text.length === 0) {
    console.warn('[TTSService] 文本为空');
    return;
  }

  // 文本长度限制
  if (text.length > 10000) {
    console.warn('[TTSService] 文本过长,截断到10000字符');
    text = text.substring(0, 10000);
  }

  try {
    // 1. 配置播报参数
    let extraParam: Record<string, Object> = {
      'speed': speed,      // 语速
      'volume': volume,    // 音量
      'pitch': 1.0,        // 音调
      'languageContext': 'zh-CN',
      'audioType': 'pcm'
    };

    let speakParams: textToSpeech.SpeakParams = {
      requestId: Date.now().toString(),  // 请求ID(用于标识)
      extraParams: extraParam
    };

    // 2. 设置监听器
    return new Promise<void>((resolve, reject) => {
      let speakListener: textToSpeech.SpeakListener = {
        // 开始播报
        onStart: (requestId: string, response: textToSpeech.StartResponse) => {
          console.info(`[TTSService] 开始播报, requestId: ${requestId}`);
        },
        // 播报完成
        onComplete: (requestId: string, response: textToSpeech.CompleteResponse) => {
          console.info(`[TTSService] 播报完成, requestId: ${requestId}`);
          resolve();
        },
        // 停止播报
        onStop: (requestId: string, response: textToSpeech.StopResponse) => {
          console.info(`[TTSService] 停止播报, requestId: ${requestId}`);
          resolve();
        },
        // 播报错误
        onError: (requestId: string, errorCode: number, errorMessage: string) => {
          console.error(`[TTSService] 播报错误: ${errorCode} - ${errorMessage}`);
          reject(new Error(`TTS错误: ${errorMessage}`));
        },
        // 音频数据回调(可选)
        onData: (requestId: string, audio: ArrayBuffer,
                 response: textToSpeech.SynthesisResponse) => {
          // 音频数据回调,可用于自定义处理
        }
      };

      // 3. 设置监听器并开始播报
      this.ttsEngine!.setListener(speakListener);
      this.ttsEngine!.speak(text, speakParams);
    });
  } catch (error) {
    const err = error as BusinessError;
    console.error(`[TTSService] 播报失败: ${err.message}`);
    throw Error(`TTS播报失败: ${err.message}`);
  }
}

/**
 * 停止当前播报
 */
stop(): void {
  if (this.ttsEngine !== null) {
    this.ttsEngine.stop();
    console.info('[TTSService] 已停止');
  }
}

/**
 * 判断是否正在播报
 */
isBusy(): boolean {
  if (this.ttsEngine !== null) {
    return this.ttsEngine.isBusy();
  }
  return false;
}

/**
 * 释放资源
 */
async release(): Promise<void> {
  if (this.ttsEngine !== null) {
    await this.ttsEngine.shutdown();
    this.ttsEngine = null;
  }
  this.isInitialized = false;
  console.info('[TTSService] 资源已释放');
}

播报参数说明

参数 类型 范围 说明
speed number 0.5-2.0 语速,1.0为正常速度
volume number 0.0-1.0 音量,1.0为最大音量
pitch number 0.5-2.0 音调,1.0为正常音调

3.4 在页面中使用TTS服务

import { ttsService } from '../../services/TTSService';

@Entry
@ComponentV2
struct ImageScanPage {
  async aboutToAppear(): Promise<void> {
    // 初始化TTS服务
    await ttsService.initialize();
  }

  onPageHide(): void {
    // 页面隐藏时停止TTS
    ttsService.stop();
  }

  // 朗读图片加载完成提示
  async speakImageLoadedTip(): Promise<void> {
    try {
      const tipText = '图片选择完成,请长按图片进行分享或者搜索';
      await ttsService.speak(tipText);
      console.info('[ImageScanPage] TTS提示已播报');
    } catch (error) {
      console.error('[ImageScanPage] TTS播报失败:', error);
    }
  }
}

使用要点

  • 在页面加载时初始化TTS服务
  • 在页面隐藏时停止播报,避免后台播放
  • 使用try-catch捕获播报错误

四、权限配置

4.1 AI能力所需权限

虽然Vision Kit和Speech Kit是端侧AI,但仍需要一些基础权限:

module.json5配置

{
  "module": {
    "requestPermissions": [
      // 网络权限(在线模式需要)
      {
        "name": "ohos.permission.INTERNET"
      },
      // 相机权限(拍照需要)
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:camera_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      // 读取媒体库权限(选择图片需要)
      {
        "name": "ohos.permission.READ_MEDIA",
        "reason": "$string:media_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

权限说明

权限 用途 是否必需
INTERNET TTS在线模式、图片上传 可选
CAMERA 调用相机拍照 拍照功能必需
READ_MEDIA 从相册选择图片 选择图片必需

4.2 权限申请代码

对于敏感权限(如相机),需要在运行时动态申请:

import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 请求相机权限
 */
async requestCameraPermission(): Promise<boolean> {
  const permissions: Permissions[] = ['ohos.permission.CAMERA'];

  try {
    const context = getContext(this) as common.UIAbilityContext;
    const atManager = abilityAccessCtrl.createAtManager();

    // 请求权限
    const result = await atManager.requestPermissionsFromUser(context, permissions);

    // 检查授权结果
    const grantStatus = result.authResults;
    if (grantStatus[0] === 0) {
      console.info('[ImageScanPage] 相机权限已授权');
      return true;
    } else {
      console.warn('[ImageScanPage] 相机权限被拒绝');
      promptAction.showToast({
        message: '需要相机权限才能拍照',
        duration: 2000
      });
      return false;
    }
  } catch (error) {
    const err = error as BusinessError;
    console.error(`[ImageScanPage] 请求权限失败: ${err.code}, ${err.message}`);
    return false;
  }
}

权限申请时机

  • 在用户点击"拍照"按钮时申请相机权限
  • 在用户点击"选择图片"按钮时申请媒体库权限
  • 避免在应用启动时一次性申请所有权限

五、完整示例:图像识别页面

5.1 页面结构

@Entry
@ComponentV2
struct ImageScanPage {
  // 状态变量
  @Local selectedImageUri: string = '';
  @Local selectedPixelMap: image.PixelMap | null = null;

  // AI控制器
  private visionImageAnalyzerController: visionImageAnalyzer.VisionImageAnalyzerController =
    new visionImageAnalyzer.VisionImageAnalyzerController();

  // 生命周期
  async aboutToAppear(): Promise<void> {
    await ttsService.initialize();
  }

  onPageShow(): void {
    // 设置Vision Kit监听器
    this.setupVisionListeners();
  }

  onPageHide(): void {
    ttsService.stop();
  }

  build() {
    Column() {
      // 导航栏
      this.buildNavigationBar()

      Scroll() {
        Column({ space: 16 }) {
          // 图片预览区域
          if (this.selectedPixelMap) {
            this.buildImagePreview()
          } else {
            this.buildEmptyState()
          }

          // 操作按钮
          this.buildActionButtons()

          // 使用说明
          if (!this.selectedPixelMap) {
            this.buildInstructions()
          }
        }
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.background'))
  }
}

5.2 图片预览组件

@Builder
buildImagePreview() {
  Column({ space: 12 }) {
    // AI识别图片
    Image(this.selectedPixelMap, {
      types: [
        ImageAnalyzerType.TEXT,
        ImageAnalyzerType.SUBJECT,
        ImageAnalyzerType.OBJECT_LOOKUP
      ],
      aiController: this.visionImageAnalyzerController
    })
      .width('100%')
      .height(400)
      .objectFit(ImageFit.Contain)
      .borderRadius(12)
      .shadow({ radius: 8, color: '#20000000', offsetY: 2 })
      .enableAnalyzer(true)

    // 操作提示
    Row({ space: 8 }) {
      Text('💡')
        .fontSize(16)
      Text('长按图片识别花草或者物品分享给朋友')
        .fontSize(14)
        .fontColor($r('app.color.text_secondary'))
    }
    .width('100%')
    .padding(12)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)
  }
  .width('100%')
  .padding(16)
  .backgroundColor($r('app.color.card_background'))
  .borderRadius(16)
  .margin(16)
}

5.3 操作按钮

@Builder
buildActionButtons() {
  Row({ space: 12 }) {
    Button('选择图片')
      .fontSize(16)
      .layoutWeight(1)
      .backgroundColor($r('app.color.primary_home_gardening'))
      .onClick(() => {
        this.selectImageFromGallery();
      })

    Button('拍照')
      .fontSize(16)
      .layoutWeight(1)
      .backgroundColor($r('app.color.primary_professional'))
      .onClick(() => {
        this.takePhoto();
      })
  }
  .width('100%')
  .padding({ left: 16, right: 16 })
}

六、实操练习

练习1:测试图像识别

任务:选择一张包含文字的图片,测试文字识别功能

步骤

  1. 运行应用,进入"扫一扫"页面
  2. 点击"选择图片"按钮
  3. 从相册选择一张包含文字的图片
  4. 长按图片,观察识别结果
  5. 查看控制台日志,确认识别成功

预期结果

  • 图片加载后自动播报提示音
  • 长按图片后显示识别界面
  • 可以选择识别到的文字进行复制

练习2:测试语音播报

任务:修改TTS播报内容和参数

步骤

  1. 修改speakImageLoadedTip()方法中的文本
  2. 调整语速参数(如1.5倍速)
  3. 重新运行应用
  4. 选择图片,听取播报效果

代码示例

async speakImageLoadedTip(): Promise<void> {
  const tipText = '您好,图片已加载完成,请长按进行识别';
  await ttsService.speak(tipText, 1.5, 1.0);  // 1.5倍速
}

练习3:测试相机拍照

任务:使用相机拍照并识别

步骤

  1. 点击"拍照"按钮
  2. 授权相机权限
  3. 拍摄一张照片
  4. 长按照片进行识别
  5. 测试主体识别功能

预期结果

  • 相机正常启动
  • 拍照后图片正常显示
  • 可以识别照片中的主体

七、常见问题与解决方案

问题1:Vision Kit识别无响应

现象:长按图片没有任何反应

可能原因

  1. PixelMap格式不正确
  2. 未启用enableAnalyzer
  3. 监听器未正确设置

解决方案

// 1. 确保PixelMap格式为RGBA_8888
const pixelMap = await imageSourceApi.createPixelMap({
  desiredPixelFormat: image.PixelMapFormat.RGBA_8888
});

// 2. 确保启用分析器
Image(this.selectedPixelMap, {
  types: [ImageAnalyzerType.TEXT, ImageAnalyzerType.SUBJECT],
  aiController: this.visionImageAnalyzerController
})
  .enableAnalyzer(true)  // 必须设置

// 3. 在onPageShow中设置监听器
onPageShow(): void {
  this.visionImageAnalyzerController.on('textAnalysis', (text: string) => {
    console.info('识别结果:', text);
  });
}

问题2:TTS播报无声音

现象:调用speak()方法但没有声音

可能原因

  1. TTS引擎未初始化
  2. 设备音量为0
  3. 文本为空

解决方案

// 1. 确保初始化
async aboutToAppear(): Promise<void> {
  try {
    await ttsService.initialize();
    console.info('TTS初始化成功');
  } catch (error) {
    console.error('TTS初始化失败:', error);
  }
}

// 2. 检查文本
if (text && text.length > 0) {
  await ttsService.speak(text);
}

// 3. 检查引擎状态
if (ttsService.isBusy()) {
  console.info('TTS正在播报');
}

八、总结

本篇教程完成了HarmonyOS AI能力的基础集成,主要包括:

✅ 已实现功能

功能 说明
Vision Kit集成 图像识别控制器、监听器配置
文字识别 OCR文字识别功能
主体识别 图片主体识别与抠图
物体搜索 物体识别与搜索
TTS语音合成 文字转语音播报
图片选择 相册选择、相机拍照
权限管理 相机、媒体库权限申请

🎯 核心技术点

  1. VisionImageAnalyzerController:图像分析控制器
  2. ImageAnalyzerType:识别类型配置
  3. TextToSpeechEngine:TTS引擎
  4. PixelMap:图像像素数据(RGBA_8888格式)
  5. 权限动态申请:运行时权限管理

🚀 下一步

在下一篇教程中,我们将学习:

  • 植物识别功能实现
  • 识别结果处理与展示
  • 识别历史记录管理
  • 识别结果分享功能

教程版本:v1.0
更新日期:2024-01-20
作者:高高种地开发团队

相关资源


恭喜! 🎉 你已经完成了HarmonyOS AI能力的基础集成。现在你的应用具备了图像识别和语音播报的能力,为后续的智能功能打下了坚实的基础。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐