HarmonyOS 鸿蒙Next中物体识别问题难题求助
HarmonyOS 鸿蒙Next中物体识别问题难题求助 需求描述: 我在做一个盲人用的环境识别及引导功能,需要结合物体识别与 深度测量数据实现;
问题描述:
在验证 yoloV8n .ms 目标识别+ARengine深度数据 方案;碰到如下问题:
-
NPU无法运行,CPU能运行,但识别成功率极低(不靠谱);卡壳了
-
yolov8n.pt 转 yolov8n.onnx 转 yolov8n.ms 经过三天一番折腾,
-
yolov8n.pt在windows 测试图片 识别成功,并提供位置框;
已验证的两种方案,识别效果太差,希望提供一下解决方案。
方案1 . MindSpore Lite实现图像分类(ArkTS) mobilenetv2 ----已放弃 物体识别准确度太低 ,完全错误;远低于 小艺看世界 的物体识别效果;所用相关例程:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/mindspore-guidelines-based-js物体识别问题难题求助/HarmonyOS_Samples/guide-snippets/tree/master/MindSporeLiteKit/MindSporeLiteArkTSDemo
方案2. 系统自带的 core vision kit 识别类别太少,识别准确度极低,未采用。----已放弃
更多关于HarmonyOS 鸿蒙Next中物体识别问题难题求助的实战教程也可以访问 https://www.itying.com/category-93-b0.html
尊敬的开发者,您好,因为有的算子在NPU上目前无法支持,模型中某些算子在NPU上存在兼容性限制,会把整图或者一部分子图回退到CPU上执行,另外模型中某些算子的数据类型在NPU上也存在兼容性限制,而且模型如果是动态shape一些算子在NPU上也会回退。
具体支持的算子列表参考昇思大模型开源社区文档:Lite算子支持
关于您所属参考 MindSpore Lite实现图像分类(ArkTS)物体识别准确度太低,Core Vision Kit识别类别太少,识别准确度极低,麻烦您提供如下信息:
1、麻烦您提供下能复现问题的最小demo(描述下具体实现步骤);
2、版本信息(如:IDE版本信息、手机系统版本信息);
3、麻烦您提供下完整的日志信息;
4、麻烦您详细描述下您所需求识别哪些物品,具体需要哪些物品类别;
更多关于HarmonyOS 鸿蒙Next中物体识别问题难题求助的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
我也用AREngine做App,感觉你可以用AREngine的距离检测(深度估计https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arengine-get-depth-conversion)了做一定的优化,同时结合
环境Mesh识别介绍https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arengine-get-mesh-conversion
做出智能化地提醒。
import { arEngine, ARView, arViewController } from '@kit.AREngine';
import { Node, Scene } from '@kit.ArkGraphics3D';
import { BusinessError } from '@kit.BasicServicesKit';
let centerDistance: number;
let centerConfidence: number;
@Builder
export function ARDepthBuilder(): void {
ARDepth();
}
@Component
struct ARDepth {
private delayInterval: number = 33;
private intervalId: number = -1;
@State arContext?: arViewController.ARViewContext = undefined;
@State depthConfidence: number = 0;
@State depthDistance: string = '0';
build(): void {
NavDestination() {
RelativeContainer() {
if (this.arContext) {
ARView({ context: this.arContext })
.height('100%')
.width('100%')
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
// 在屏幕上显示中心点、深度估计值及置信度
Text('●')
.fontSize(8)
.fontColor(Color.Red)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
Column() {
Text(`${this.depthDistance} | ${this.depthConfidence}`)
.fontColor(Color.Yellow)
.fontSize(24)
.textShadow({
radius: 10,
color: Color.Black,
offsetX: 0,
offsetY: 0
})
}
.alignItems(HorizontalAlign.Center)
.margin({ bottom: 10 })
.alignRules({
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}
}
}
.onAppear(() => {
this.initARView();
this.renderDepthMsg();
})
.onWillAppear(() => {
this.stopARView();
})
.onShown(() => {
this.resumeARView();
})
.onHidden(() => {
this.pauseARView();
})
.hideTitleBar(true)
.hideBackButton(true)
.hideToolBar(true)
}
private initARView(): void {
Scene.load().then((scene: Scene) => {
let viewContext: arViewController.ARViewContext = new arViewController.ARViewContext();
viewContext.scene = scene;
viewContext.callback = new ARViewCallbackImpl();
viewContext.config = {
type: arEngine.ARType.WORLD,
planeFindingMode: arEngine.ARPlaneFindingMode.HORIZONTAL_AND_VERTICAL,
powerMode: arEngine.ARPowerMode.NORMAL,
semanticMode: arEngine.ARSemanticMode.NONE,
poseMode: arEngine.ARPoseMode.GRAVITY,
depthMode: arEngine.ARDepthMode.AUTOMATIC,
meshMode: arEngine.ARMeshMode.DISABLED,
focusMode: arEngine.ARFocusMode.AUTO
};
viewContext.init().then(() => {
this.arContext = viewContext;
console.info('Succeeded in initializing ARView.');
}).catch((err: BusinessError) => {
console.error(`Failed to init ARView. Code is ${err.code}, message is ${err.message}`);
});
});
}
private renderDepthMsg(): void {
this.intervalId = setInterval(() => {
if (centerDistance === undefined || centerConfidence === undefined) {
return;
}
this.depthDistance = centerDistance.toFixed(4);
this.depthConfidence = centerConfidence;
}, this.delayInterval);
}
private stopARView(): void {
if (!this.arContext) {
return;
}
try {
clearInterval(this.intervalId);
this.arContext.destroy();
centerDistance = 0;
centerConfidence = 0;
} catch (error) {
const err: BusinessError = error as BusinessError;
console.error(`Failed to stop context. Code is ${err.code}, message is ${err.message}`);
}
}
private resumeARView(): void {
// ...
}
private pauseARView(): void {
// ...
}
}
class ARViewCallbackImpl extends arViewController.ARViewCallback {
onAnchorAdd(ctx: arViewController.ARViewContext, node: Node, anchor: arEngine.ARAnchor): void {
// ...
}
onAnchorUpdate(ctx: arViewController.ARViewContext, node: Node, anchor: arEngine.ARAnchor): void {
// ...
}
onFrameUpdate(ctx: arViewController.ARViewContext, sysBootTs: number): void {
if (!ctx.session) {
return;
}
let session: arEngine.ARSession | undefined = ctx.session;
try {
let frame: arEngine.ARFrame = session.getFrame();
let depthImage: arEngine.ARImage = frame.acquireDepthImage16Bits();
let confidenceImage: arEngine.ARImage = frame.acquireDepthConfidenceImage();
let depthPlane: number[] = arrayBufferInt32ToNumber(depthImage.planes[0].buffer);
let confidencePlane: number[] = arrayBufferInt32ToNumber(confidenceImage.planes[0].buffer);
const index: number = depthImage.height * depthImage.width / 2 + depthImage.width / 2;
centerDistance = depthPlane[index] / 1000;
centerConfidence = confidencePlane[index];
} catch (error) {
const err: BusinessError = error as BusinessError;
console.error(`Failed to acquire depth information. Code is ${err.code}, message is ${err.message}`);
}
}
}
从你的描述来看,其实你已经踩中了很多做视觉项目的人都会遇到的坑:
问题不在于 AREngine,也不在于深度数据,而是在“目标检测模型部署”这一层。
先说结论
对于盲人环境识别这种场景:
摄像头
↓
目标检测(YOLO)
↓
目标框
↓
深度测距(AR Engine)
↓
语义决策
↓
语音播报
其中最关键的是:
目标检测准确率
而不是深度测量。
如果目标识别错了:
把椅子识别成桌子
把门识别成墙
把楼梯识别成地面
深度再准也没有意义。
你目前两个方案为什么效果差
方案1:MobilenetV2 图像分类
这个方案本质上不适合你的需求。
因为:
图像分类
≠
目标检测
MobilenetV2只能回答:
这张图大概率是什么
例如:
桌子 60%
椅子 20%
门 10%
但无法告诉你:
桌子在哪里
距离多少
有几个
对于盲人导航基本没法用。
所以放弃是正确的。
方案2:Core Vision Kit
Core Vision Kit 的定位更偏向:
OCR
条码
文档
基础视觉能力
而不是:
复杂环境目标检测
类别数量有限是正常现象。
它不是 YOLO 的替代品。
关于 YOLOv8 的问题
你说:
Windows:
yolov8n.pt
识别正常
而:
HarmonyOS:
yolov8n.ms
识别极差
这种情况一般只有三个原因。
原因1(概率最高)
后处理错了
很多人:
pt
↓
onnx
↓
ms
转换成功了。
但:
NMS
sigmoid
坐标还原
处理错了。
表现就是:
框乱飞
类别乱跳
置信度异常
看起来像:
识别率极低
实际上模型本身没问题。
原因2
输入预处理不一致
Windows YOLO:
letterbox
RGB
640×640
归一化
而 ArkTS 侧经常变成:
BGR
或者
RGBA
或者:
resize方式不同
结果:
准确率断崖式下降
这是最常见问题之一。
原因3
模型转换损失
虽然 MindSpore Lite 支持:
ONNX
→
MS
并支持麒麟 NPU。
但并不是所有 YOLOv8 算子都能无损转换。
尤其:
Detect Head
动态Shape
部分后处理
经常出问题。
关于 NPU
你说:
CPU能跑
NPU不能跑
最近社区其实已经有人反馈:
CPU正常
NPU加载失败
getInputs为空
类似问题。
所以:
不是你一个人遇到
当前 HarmonyOS + MindSpore Lite + NPU 的生态还不像 Android TensorRT 那么成熟。
我更推荐的路线
如果项目目标是:
盲人环境识别
不要直接上:
YOLOv8n
+
AR深度
建议:
第一步
先把检测跑通
只做:
摄像头
↓
YOLOv8
↓
播报
例如:
前方1米处有椅子
前方有门
右侧有垃圾桶
不要加深度。
第二步
换模型
YOLOv8n 太小。
对于室内复杂场景:
YOLOv8s
YOLOv8m
效果会明显提升。
YOLOv8n 本来就是:
速度优先
不是精度优先。
第三步
自建数据集
你这个场景:
门
楼梯
扶手
电梯
垃圾桶
障碍物
属于特殊场景。
COCO 数据集本身就不够。
最有效的方法是:
自己采集几千张数据
重新训练
很多项目精度提升最大的来源其实是数据,而不是模型。
第四步
再接 AREngine
此时:
YOLO
得到目标框
然后:
框中心点
↓
对应深度图
↓
获取距离
例如:
门
2.3米
楼梯
1.1米
椅子
0.8米
这样架构才合理。
第五步(最终方案)
如果预算允许,我甚至建议:
YOLOv8
+
视觉大模型
+
深度数据
因为你提到:
小艺看世界
它并不是简单的:
Mobilenet
或者:
传统分类模型
而是更接近:
多模态视觉理解
所以你会感觉差距非常大。
针对你目前的情况,我建议先重点排查:
- ONNX → MS 转换后的输出是否与 Windows ONNX Runtime 一致;
- ArkTS 侧图片预处理(RGB/BGR、归一化、letterbox)是否完全一致;
- 后处理(NMS、坐标映射)是否正确;
- NPU 是否是模型兼容问题,而不是代码问题。
如果你能贴出:
- 使用的 YOLOv8 版本(n/s/m)
- ONNX 导出命令
- 转 MS 的 converter 命令
- ArkTS 推理后的输出 tensor 结构
基本可以进一步判断到底是模型转换问题、预处理问题还是 NPU 兼容问题。
根本原因在于模型转换与部署流程不完全匹配 HarmonyOS 的 NPU 算子集。
直接解决方案:使用官方已验证的 YOLO 示例代码与转换步骤。
不要使用通用的 MindSpore Lite 分类示例,请直接使用华为官方提供的目标检测示例,该示例包含正确的 YOLOv8 模型转换脚本和完整的 ARKTS 推理代码。
- 模型转换:按照随示例提供的
convert_yolov8.sh脚本进行转换,关键参数必须一致(--optimize=ascend_oriented和对应的量化配置),不能使用默认的 ONNX 转 MS 参数。这是 NPU 无法运行的根本原因。 - 推理代码:直接复制示例中的 ARKTS 推理部分,重点在于:
- 数据预处理:必须与模型训练时的归一化方式(通常
mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])和RGB排布完全一致。 - 后处理:YOLOv8 的后处理(NMS、坐标反算)必须正确实现,示例代码已包含此逻辑。
- 性能配置:在创建 Model 时,显式指定
deviceType为'npu',并设置enableFloat16为true。如果因个别算子不支持导致 NPU 失败,添加backend为'cpu'的回退配置。
- 数据预处理:必须与模型训练时的归一化方式(通常
示例获取:在你的 HarmonyOS SDK 目录下搜索 ObjectDetectionYoloV8 或者访问官方代码仓 applications_sample 中的 Media/AI 目录,查找此示例。严格按其中的 README 操作,即可在 NPU 上得到与电脑端一致的检测框和准确率。
替代方案:如果需追求 “小艺看世界” 级的效果,不应直接使用基础模型。应使用 HiAI Foundation 的模型zoo 中适配完成的 YOLOv8s 或更优模型,其推理精度和性能通过 NPU 调优,能提供更快的推理帧率和更高的识别准确度,更适合你的盲人引导场景。


