水果智能识别 App:手机现拍现教,镜头一对就报出水果名和热量

« 返回首页

水果智能识别 App:手机现拍现教,镜头一对就报出水果名和热量

一句话结论:用即教即识组件在手机上给每种水果拍几十张样本即可做水果识别 App,镜头对准就显示名称、置信度和热量,无需电脑训练和联网,需要 Android 7.0 以上。

做完的效果:手机镜头对准一个苹果,屏幕上立刻显示「苹果 96%」和「约 52 千卡 / 100 克」,同时语音说出「这是苹果」;换成香蕉,结果马上跟着变;什么都不放,就提示「请把水果放到镜头前」。

用的是本站内置的 即教即识 组件:不用电脑训练模型、不用联网、不用导入拓展,在手机上对着水果拍几十张样本就教会了。原理很简单:每张画面先变成一串特征数字,识别时找和它最像的样本,所以加完样本立刻生效,不用等训练。

准备

  • 手机:安卓 7.0 以上,装好 AI 伴侣(即教即识暂不支持鸿蒙)。
  • 水果:苹果、香蕉、橙子各一个(换成你手边的任意水果都行,类别名改一下即可)。
  • 一块干净的桌面或一张白纸当背景。
组件 命名 关键属性
垂直布局 垂直布局_预览 宽「充满」、高 300 像素;里面不放别的组件
标签 标签_结果 字号 28、粗体,文字「准备中…」
标签 标签_介绍 字号 16
水平布局(放 4 个按钮) — 宽「充满」
按钮 按钮_苹果、按钮_香蕉、按钮_橙子、按钮_背景 文字「教苹果」「教香蕉」「教橙子」「教背景」
按钮 按钮_保存 文字「保存模型」
即教即识(机器学习套件分类) 即教即识1 「预览容器」选 垂直布局_预览
文本朗读器(多媒体分类) 文本朗读器1 默认

第一步:打开摄像头

when Screen1.Initialize() {
  即教即识1.StartLiveCamera()
  标签_结果.Text = "请先教几种水果"
}

跑起来看:连上 AI 伴侣,允许相机权限后,布局里出现实时画面,左上角还没有标注(因为一个类别都没教过)。看不到画面先查布局的高度是不是 300 像素。

第二步:教会四个类别

每个按钮从摄像头连续拍 20 张样本,每张间隔约 0.15 秒,3 秒左右拍完:

when 按钮_苹果.Click() {
  即教即识1.AddSamplesFromCamera("苹果", 20)
}
when 按钮_香蕉.Click() {
  即教即识1.AddSamplesFromCamera("香蕉", 20)
}
when 按钮_橙子.Click() {
  即教即识1.AddSamplesFromCamera("橙子", 20)
}
when 按钮_背景.Click() {
  即教即识1.AddSamplesFromCamera("背景", 20)
}
when 即教即识1.SampleAdded(类别, 数量) {
  标签_介绍.Text = join("正在教「", 类别, "」:", 数量, " / 20 张")
}

怎么教:点「教苹果」后,把苹果放在镜头前慢慢转动、拉远拉近,让 20 张样本各不相同;香蕉、橙子照做。最后点「教背景」,镜头对着空桌面拍 20 张。

跑起来看:标签从「正在教「苹果」:1 / 20 张」一路数到 20。教完苹果后,画面左上角就开始出现「苹果」标注了。

为什么要教「背景」:即教即识只会在教过的类别里挑最像的。不教背景,镜头对着空桌子时它也会硬说是某种水果。

第三步:实时显示识别结果

when 即教即识1.LiveClassification(类别, 置信度, 结果JSON) {
  if 类别 == "" or 类别 == "背景" {
    标签_结果.Text = "请把水果放到镜头前"
  } else {
    标签_结果.Text = join(类别, " ", round(置信度 * 100), "%")
  }
}

「实时分类」每秒最多触发 5 次(「实时事件间隔」默认 200 毫秒)。类别为空表示拿不准:最像的类别置信度低于「最低置信度」(默认 0.6),比如镜头前放了一个没教过的梨。

跑起来看:苹果放到镜头前,显示「苹果 9x%」;拿走,显示「请把水果放到镜头前」。

第四步:显示热量,换了水果才播报

用一个字典存每种水果的介绍。语音不能每次事件都念(一秒 5 次会念个不停),所以用一个变量记住上一次念过的水果,换了水果才念:

global 水果资料 = {"苹果": "约 52 千卡 / 100 克,富含膳食纤维", "香蕉": "约 93 千卡 / 100 克,富含钾", "橙子": "约 48 千卡 / 100 克,富含维生素 C"}
global 上次水果 = ""

when 即教即识1.LiveClassification(类别, 置信度, 结果JSON) {
  if 类别 == "" or 类别 == "背景" {
    标签_结果.Text = "请把水果放到镜头前"
    标签_介绍.Text = ""
    上次水果 = ""
  } else {
    标签_结果.Text = join(类别, " ", round(置信度 * 100), "%")
    标签_介绍.Text = dictGet(水果资料, 类别, "还没有这种水果的介绍")
    if 类别 != 上次水果 {
      上次水果 = 类别
      文本朗读器1.Speak(join("这是", 类别))
    }
  }
}

这段替换第三步的「实时分类」事件(同一个事件只能有一个)。

跑起来看:苹果放上去,手机说一次「这是苹果」,下面显示热量;苹果一直放着不会重复念;换成香蕉,立刻说「这是香蕉」;拿走再放回苹果,又会念一次。

第五步:保存模型,下次打开直接能认

教好的样本在关闭 App 后就没了。点「保存模型」存成文件,下次启动自动载入:

when Screen1.Initialize() {
  即教即识1.StartLiveCamera()
  即教即识1.LoadModel("fruit.json")
}
when 按钮_保存.Click() {
  即教即识1.SaveModel("fruit.json")
}
when 即教即识1.ModelSaved(路径) {
  标签_介绍.Text = join("模型已保存,共 ", 即教即识1.SampleCount, " 张样本")
}
when 即教即识1.ModelLoaded(类别数, 样本数) {
  标签_结果.Text = join("已载入 ", 类别数, " 种类别,请把水果放到镜头前")
}
when 即教即识1.ClassifierError(操作, 错误信息) {
  if 操作 == "LoadModel" {
    标签_结果.Text = "还没有模型,请先教几种水果"
  } else {
    标签_介绍.Text = join("出错:", 错误信息)
  }
}

这段的「Screen1.初始化」替换第一步那个。模型只存特征数字、不存照片,80 张样本约 650KB,存在 App 自己的目录里,不需要存储权限。

文件名用英文:只在手机上存取时,中文文件名也能用;但模型文件要作为素材上传时,App Inventor 的素材名不支持中文,上传会被自动改成英文名,LoadModel 里写的中文名就对不上了。所以一开始就用字母、数字取名,如 fruit.json。

跑起来看:教完点「保存模型」,提示「模型已保存,共 80 张样本」;退出 App 重新打开,提示「已载入 4 种类别」,不用再教就能认。

想让别人装上就能用:把手机里保存的模型文件(或用电脑上的即教即识训练台导出的模型)作为素材上传到项目,LoadModel 写素材名即可,编译出的 APK 一打开就会认。

排错

现象 原因与解决
布局里没有画面 预览布局没设高度,或「预览容器」没选它;首次运行要允许相机权限
点「教苹果」没反应 要先「打开实时摄像头」;看「分类出错」事件给出的错误信息
空桌子也说是苹果 没教「背景」类,或背景样本太少
苹果和橙子总认混 两类样本多拍几张不同角度;拍苹果时别让橙子也在画面里
一直显示「请把水果放到镜头前」 置信度都低于 0.6:靠近一点、光线亮一点,或把「最低置信度」调到 0.5
语音一直重复念 漏了「上次水果」变量的判断
鸿蒙手机上报错 鸿蒙系统暂未开放通用图像特征提取接口,即教即识暂不支持鸿蒙

下一步

  • 多认几种:加按钮、加字典条目就行。类别上几十种、要求很高的准确率时,改用电脑训练的 TFLite 模型配合自定义图像分类。
  • 称重算价:接蓝牙电子秤读重量,按识别出的水果查单价,做一个自助称重收银台。
  • 成熟度:同一种水果分「青香蕉」「熟香蕉」「过熟香蕉」三类来教,就成了成熟度检测。

几种图像分类方案(即教即识、自定义图像分类、PIC、Teachable Machine)的区别,看图像分类方案对比。

文档反馈