MLKitObjectDetector 拓展:离线目标检测(找出物体并画框)

« 返回首页

logo MLKitObjectDetector 拓展

找出图片里有哪些物体,并给出每个物体的位置矩形框。

为什么选它:

  • 完全离线。模型随 .aix 打包,设备不需要 Google Play 服务,断网也能用。
  • 两种事件,各取所需:汇总事件 GotObjects 一次给全(含 JSON), 逐个事件 GotObject 带序号和框坐标 —— 初学者直接在逐个事件里画框最省事。
  • 可选只找最显眼的一个(更快)还是找出多个;可选是否要粗分类。
  • 不用先”初始化”,检测器按需创建、复用。

与 MLKitImageLabeler 的区别:图像标注只告诉你「图里有花」, 本拓展还告诉你「花在 (x, y) 起、宽 w 高 h 的框里」,并能一次框出多个物体。

  • .aix 拓展下载:

cn.fun123.MLKit.ObjectDetector.aix


快速上手

一、检测并逐个画框

设计器里放一个 MLKitObjectDetector、一个「图像选择器」、一个画布(用来画框)。

global scale = 1

when 图像选择器1.AfterPicking() {
  标签1.Text = "检测中…"
  ObjectDetector1.DetectFromFile(图像选择器1.Selection)
}
when ObjectDetector1.GotObjects(count, imageWidth, imageHeight, resultJson) {
  标签1.Text = join("找到 ", count, " 个物体")
  画布1.BackgroundImage = 图像选择器1.Selection
  scale = 画布1.Width / imageWidth
}
when ObjectDetector1.GotObject(index, x, y, width, height, label, confidence, trackingId) {
  画布1.PaintColor = -65536
  画布1.DrawLine(x * scale, y * scale, (x + width) * scale, y * scale)
  画布1.DrawLine((x + width) * scale, y * scale, (x + width) * scale, (y + height) * scale)
  画布1.DrawLine((x + width) * scale, (y + height) * scale, x * scale, (y + height) * scale)
  画布1.DrawLine(x * scale, (y + height) * scale, x * scale, y * scale)
  画布1.DrawText(label, x * scale, y * scale)
}

坐标要换算:事件给的是原图像素坐标,画到画布上要乘以 画布宽 / 原图宽。 这就是汇总事件里给 imageWidth/imageHeight 的用途。

二、只要最显眼的那一个(更快)

when Screen1.Initialize() {
  ObjectDetector1.MultipleObjects = false
  ObjectDetector1.Classification = true
}

三、只要位置不要分类(最快)

when Screen1.Initialize() {
  ObjectDetector1.Classification = false
}

四、拿完整结果自己处理

when ObjectDetector1.GotObjects(count, imageWidth, imageHeight, resultJson) {
  标签_原始结果.Text = resultJson
}

resultJson 的形状(用「JSON 文本解码」块解析):

[{"bounds":{"left":120,"top":80,"right":420,"bottom":560,"width":300,"height":480},
  "trackingId":-1,
  "labels":[{"label":"Fashion good","confidence":0.78,"index":0}]}]

五、什么都没检测到时给个提示

when ObjectDetector1.NoObjectFound(operation) {
  标签1.Text = "没检测到物体。目标检测适合画面里有明确主体的照片"
}

属性

MultipleObjects
是否检测多个物体。 「真」(默认)= 找出画面里最多 5 个物体;「假」= 只找最显眼的那一个(更快)。 改这个属性会重建检测器,立即生效。
Classification
是否同时给出粗分类。 「真」(默认)= 每个物体附带类别名和置信度;「假」= 只给位置框(更快)。 注意基础模型只有 5 个大类(时尚商品 / 食物 / 家居用品 / 地点 / 植物), 要精细分类请用自定义模型版拓展。
Busy
只读。是否正在检测。检测期间再次调用会触发 DetectFailed。

事件

GotObjects(count,imageWidth,imageHeight,resultJson)
检测完成的汇总,在逐个事件之前触发。 imageWidth/imageHeight 是原图尺寸 —— 画框换算坐标时必须用它。
GotObject(index,x,y,width,height,label,confidence,trackingId)
每检测到一个物体触发一次,方便逐个画框。
  • index — 从 1 开始的序号。
  • x/y — 框的左上角;width/height — 框的宽高。单位是原图像素。
  • label/confidence — 粗分类结果(是否分类 为「假」时 label 为空串)。
  • trackingId — 跨帧跟踪编号,单张图片检测时固定为 -1。
NoObjectFound(operation)
图里没检测到物体。这不是错误 —— 目标检测适合画面里有明确主体的照片, 纯风景 / 纯文字图常常检测不到。
DetectFailed(operation,errorMessage)
检测失败。operation 是出错的方法名。

方法

DetectFromFile(path)
检测图片文件。path 可以是素材文件名、设备路径、file:// 或 content:// 地址。
DetectFromBase64(base64)
检测 Base64 图片。支持纯 Base64,也支持带 data:image/...;base64, 前缀的写法。

运行环境:AI 伴侣联机需要 Android 11 及以上

本拓展的识别模型放在依赖库自带的 assets 里,AI 伴侣联机调试要把它挂进 AssetManager,用的是 Android 11(API 30)才有的 ResourcesLoader —— 这是系统提供的 唯一公开办法,更低版本没有等价 API。所以:

运行方式 Android 6 ~ 10 Android 11 及以上
打包 APK ✅ 正常 ✅ 正常
AI 伴侣联机 ❌ 模型加载不了 ✅ 正常

打包 APK 之所以不受限制,是因为模型在编译时就被并进了 APK 的 assets,装到手机上 就是 App 自己的资源,与系统版本无关。伴侣的 APK 是提前编好装在手机上的,运行时没法 往自己已安装的包里加文件,只能靠系统的运行时挂载 API。

低版本设备上想验证功能,直接打包 APK 测即可;要用伴侣边改边调,请换 Android 11+ 的设备。

常见问题

画的框位置全错 / 偏得很远。 坐标没换算。事件给的是原图像素坐标,而画布是按显示尺寸的。 用汇总事件里的 imageWidth 算出比例:比例 = 画布宽 / imageWidth,然后所有坐标乘以它(见示例一)。

分类结果只有”时尚商品”“食物”这种大类。 基础模型就只有 5 个大类,这是能力边界,不是 bug。要认具体品类请用自定义 TFLite 模型版拓展。

trackingId 一直是 -1。 跟踪编号只在摄像头连续帧模式下才有意义。本拓展是单张图片检测,所以固定 -1。

能检测摄像头实时画面吗? 本拓展做的是单张图片检测。实时检测需要摄像头预览 + 逐帧处理 + 叠加画框, 可以参考本仓库 MLKit.CodeScanner 拓展里的实时预览实现思路,但本拓展当前不提供该能力。

为什么 .aix 有 23 MB? 除了 1.8 MB 的检测模型,还有 18.7 MB 的推理引擎(4 个 CPU 架构的原生库), 这是「完全离线、不依赖 Google Play 服务」的代价。

文档反馈