鸿蒙 AR 人体骨骼关键点识别实战:使用 AREngine 实现实时人体跟踪
**💥 踩坑**:`user_grant` 权限不仅要在 `module.json5` 中声明,还**必须**在代码中调用 `requestPermissionsFromUser`。**解决**:SDK 路径为 `DevEco-Studio.app/Contents/sdk/default/hms/`,确保通过 SDK Manager 安装了 AR Engine。**原因**:ArkTS 的 `
·
# 鸿蒙 AR 人体骨骼关键点识别实战:使用 AREngine 实现实时人体跟踪
> 参考文档:[AR Engine 开发指南 - 人体跟踪与骨骼关键点识别](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arengine-body)
## 一、背景
HarmonyOS 从 6.1.0(23) 版本开始,AR Engine 新增了对人体骨骼关键点识别与跟踪的支持(`ARType.BODY`)。通过该能力,开发者可以实时获取摄像头画面中人体的 20 个骨骼关键点坐标,并在此基础上实现体感游戏、健身姿态矫正、运动分析等应用。
本文以新华字典应用为基础,为其添加 AR 人体骨骼识别功能,完整记录从环境配置、API 调用到设备调试的全过程。
---
## 二、开发环境
| 工具 | 版本 |
|------|------|
| HarmonyOS SDK | 23(API 11)+ |
| AR Engine Kit | @kit.AREngine |
| 3D 图形 Kit | @kit.ArkGraphics3D |
| 目标设备 | 支持 AR Engine 的 HarmonyOS 设备 |
| 开发语言 | ArkTS |
| UI 框架 | ArkUI |
> **注意**:AR Engine 是 HMS SDK 的一部分,需要通过 DevEco Studio 的 SDK Manager 额外安装。路径位于 `DevEco-Studio.app/Contents/sdk/default/hms/`。
---
## 三、AR Engine Kit 简介
### 3.1 Kit 架构
AR Engine 的 Kit 结构如下:
```
@kit.AREngine # 入口 Kit
└── @hms.core.ar.arengine # AR 核心 API(arEngine 命名空间)
└── @hms.core.ar.arview # AR 视图组件(ARView、arViewController)
```
### 3.2 支持的 AR 能力
| ARType | 能力 | 最低 API 版本 |
|--------|------|:----------:|
| `WORLD` | 环境追踪 | 18 |
| `BODY` | 人体骨骼跟踪 | **23** |
| `FACE` | 人脸跟踪 | 23 |
| `IMAGE` | 图像跟踪 | 18 |
---
## 四、权限配置
AR Engine 需要以下权限,其中 `CAMERA` 属于 **user_grant** 权限,需要运行时动态申请。
### 4.1 在 module.json5 中声明
```json5
{
"requestPermissions": [
{
"name": "ohos.permission.CAMERA",
"reason": "$string:reason_camera",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.GYROSCOPE"
},
{
"name": "ohos.permission.ACCELEROMETER"
}
]
}
```
### 4.2 运行时申请权限
`CAMERA` 是敏感权限,必须使用 `abilityAccessCtrl.requestPermissionsFromUser()` 在运行时动态申请:
```typescript
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
async requestPermission(): Promise<void> {
let atManager = abilityAccessCtrl.createAtManager();
let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
let permissions: Array<Permissions> = ['ohos.permission.CAMERA'] as Array<Permissions>;
atManager.requestPermissionsFromUser(context, permissions, (err, result) => {
if (err) {
this.errorMsg = '权限请求失败: ' + err.message;
return;
}
if (result.authResults[0] === 0) {
// 权限已授予,初始化 AR
this.initARView();
} else {
this.errorMsg = '需要相机权限才能使用AR人体骨骼识别';
}
});
}
```
> **💥 踩坑**:`user_grant` 权限不仅要在 `module.json5` 中声明,还**必须**在代码中调用 `requestPermissionsFromUser`。只声明不请求,运行时仍然会被拒绝。
---
## 五、核心 API
### 5.1 关键类与接口
| 类/接口 | 说明 |
|---------|------|
| `ARViewContext` | AR 会话上下文,管理 AR Engine 系统状态 |
| `ARView` | 相机预览流组件,展示 AR 画面 |
| `ARViewCallback` | 帧更新回调,需要实现 `onFrameUpdate` 方法 |
| `ARSession` | AR 会话,通过 `getFrame()` 获取帧数据 |
| `ARFrame` | 单帧数据,通过 `acquireBodySkeleton()` 获取人体数据 |
| `ARBody` | 人体跟踪对象,通过 `getLandmarks2D()` 获取骨骼关键点 |
| `ARBodyLandmark2D` | 2D 骨骼关键点,包含坐标、置信度、类型等 |
| `ARBodyLandmarkType` | 骨骼关键点类型枚举(共 20 个点) |
### 5.2 人体骨骼关键点(20 个)
| 类型 | 部位 | 类型 | 部位 |
|------|------|------|------|
| `NECK` | 颈部 | `RIGHT_SHOULDER` | 右肩 |
| `RIGHT_ELBOW` | 右肘 | `RIGHT_WRIST` | 右腕 |
| `LEFT_SHOULDER` | 左肩 | `LEFT_ELBOW` | 左肘 |
| `LEFT_WRIST` | 左腕 | `RIGHT_HIP` | 右髋 |
| `RIGHT_KNEE` | 右膝 | `RIGHT_ANKLE` | 右踝 |
| `LEFT_HIP` | 左髋 | `LEFT_KNEE` | 左膝 |
| `LEFT_ANKLE` | 左踝 | `MID_HIP` | 髋中 |
| `RIGHT_EAR` | 右耳 | `RIGHT_EYE` | 右眼 |
| `NOSE` | 鼻子 | `LEFT_EYE` | 左眼 |
| `LEFT_EAR` | 左耳 | `SPINE` | 脊柱 |
---
## 六、实现步骤
### 6.1 导入模块
```typescript
import { arEngine, ARView, arViewController } from '@kit.AREngine';
import { Node, Scene } from '@kit.ArkGraphics3D';
import { BusinessError } from '@kit.BasicServicesKit';
import { display, router } from '@kit.ArkUI';
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
```
### 6.2 实现 ARViewCallback
`ARViewCallback` 是 AR Engine 的回调类,需要在 `onFrameUpdate` 中获取帧数据并提取人体骨骼信息:
```typescript
class ARViewCallbackImpl extends arViewController.ARViewCallback {
private callback?: OnBodyInfoCallback;
setCallback(cb: OnBodyInfoCallback) {
this.callback = cb;
}
async onFrameUpdate(ctx: arViewController.ARViewContext, sysBootTs: number): Promise<void> {
if (!ctx.session) return;
const arSession: arEngine.ARSession = ctx.session;
try {
const frame: arEngine.ARFrame = arSession.getFrame();
const bodies: arEngine.ARBody[] = frame.acquireBodySkeleton();
if (this.callback) {
this.callback(bodies);
}
} catch (error) {
const err: BusinessError = error as BusinessError;
console.error(`Failed to update body data. Code: ${err.code}, message: ${err.message}`);
}
}
}
```
**执行流程**:
```
onFrameUpdate
→ arSession.getFrame() // 获取当前帧
→ frame.acquireBodySkeleton() // 获取人体对象数组
→ body.getLandmarks2D() // 获取骨骼关键点
```
### 6.3 初始化 ARViewContext
```typescript
async initARView(): Promise<void> {
await Scene.load().then(async (scene: Scene) => {
let viewContext: arViewController.ARViewContext = new arViewController.ARViewContext();
viewContext.scene = scene;
// 设置回调
let callback = new ARViewCallbackImpl();
callback.setCallback(this.onBodyInfoCb);
viewContext.callback = callback;
// 配置 AR 参数
viewContext.config = {
type: arEngine.ARType.BODY, // 人体跟踪模式
planeFindingMode: arEngine.ARPlaneFindingMode.DISABLED,
powerMode: arEngine.ARPowerMode.NORMAL,
semanticMode: arEngine.ARSemanticMode.NONE,
poseMode: arEngine.ARPoseMode.GRAVITY,
depthMode: arEngine.ARDepthMode.DISABLED,
meshMode: arEngine.ARMeshMode.DISABLED,
focusMode: arEngine.ARFocusMode.AUTO,
maxDetectedBodyNum: 1, // 最多检测 1 个人体
cameraLensFacing: 0 // 后置摄像头
};
await viewContext.init();
this.arContext = viewContext;
this.isReady = true;
});
}
```
### 6.4 展示 AR 预览流
使用 `ARView` 组件展示摄像头预览流:
```typescript
if (this.arContext) {
ARView({ context: this.arContext })
.height('100%')
.width('100%')
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}
```
### 6.5 绘制骨骼关键点和骨骼连线
将获取到的骨骼关键点坐标(归一化值)转换为屏幕坐标,然后使用 `Shape` + `Circle` + `Line` 组件绘制:
```typescript
// 坐标转换:归一化 → 屏幕像素
landmarks.forEach((landmark) => {
landmark.x = landmark.x * this.displayWidth;
landmark.y = landmark.y * this.displayHeight;
});
// 绘制关键点
@Builder
drawBodyLandmarks(bodyLandmarks: arEngine.ARBodyLandmark2D[]) {
ForEach(bodyLandmarks, (landmark: arEngine.ARBodyLandmark2D) => {
Circle({ width: 6, height: 6 })
.position({
x: px2vp(landmark.x) - 3,
y: px2vp(landmark.y) - 3
})
.fill(Color.White).stroke(Color.Red).strokeWidth(1)
})
}
// 绘制骨骼连线
@Builder
drawBodyBoneLine(..., start, end, color) {
if (isValidBoneLine(start, end)) {
Line()
.startPoint([px2vp(start.x), px2vp(start.y)])
.endPoint([px2vp(end.x), px2vp(end.y)])
.stroke(color).strokeWidth(3)
}
}
```
**颜色方案**:
| 部位 | 颜色 |
|------|:----:|
| 躯干 | 🟠 橙色 |
| 左臂 + 左腿 | 🟢 绿色 |
| 右臂 + 右腿 | 🔵 蓝色 |
| 头部 | 🟡 黄色 |
---
## 七、完整代码结构
```
entry/src/main/ets/pages/
└── ARBodyPage.ets # AR 人体骨骼识别页面
├── BodyInfo # 数据结构定义
├── arLandmarksToMap() # 工具函数
├── ARViewCallbackImpl # 帧回调实现
├── ARBodyPage(struct) # 主页面
│ ├── requestPermission() # 权限申请
│ ├── initARView() # AR 初始化
│ ├── stopARView() # AR 停止
│ ├── drawBodyPerception() # 绘制入口
│ ├── drawBodyLandmarks() # 绘制关键点
│ ├── drawBodyBones() # 绘制骨骼线
│ └── drawBodyBoneLine() # 绘制单条骨骼线
└── ARView + Shape # UI 组件
```
---
## 八、遇到的坑与解决方案
### 8.1 权限 denied
**现象**:AR 初始化失败,日志输出:
```
permission check failed, permission:ohos.permission.CAMERA, result:-1
Error: Permission denied. create native session failed.
```
**原因**:`CAMERA` 是 `user_grant` 权限,需要在代码中运行时申请,仅声明不够。
**解决**:调用 `abilityAccessCtrl.requestPermissionsFromUser()` 动态请求权限,用户授权后再初始化 AR。
### 8.2 @Builder 内不能使用 let/const
**现象**:编译错误 `Only UI component syntax can be written here`
**原因**:ArkTS 的 `@Builder` 函数内不能包含 `let`/`const` 声明语句,只能有 UI 组件语法。
**解决**:将逻辑提取到普通方法中,`@Builder` 只包含 UI 组件调用:
```typescript
// ✅ 正确:逻辑放在普通方法
getBonePoint(type): number[] {
const p = map.get(type);
return p ? [px2vp(p.x), px2vp(p.y)] : [0, 0];
}
// UI 渲染放在 @Builder
@Builder
drawBoneLine(start, end, color) {
if (this.isValid(start, end)) {
Line().startPoint(this.getBonePoint(start))...
}
}
```
### 8.3 AREngine 在 OpenHarmony SDK 中不存在
**现象**:找不到 `@kit.AREngine` 模块。
**原因**:AR Engine 属于 HarmonyOS(HMS)SDK,不在 OpenHarmony SDK 中。
**解决**:SDK 路径为 `DevEco-Studio.app/Contents/sdk/default/hms/`,确保通过 SDK Manager 安装了 AR Engine。
### 8.4 Object literal 类型错误
**现象**:编译错误 `Object literal must correspond to some explicitly declared class or interface`
**解决**:使用 `as` 显式指定类型:
```typescript
return { trackId, landmarks } as BodyInfo;
```
---
## 九、设备兼容性
AR Engine 的人体骨骼识别功能对硬件有一定要求:
| 要求 | 说明 |
|------|------|
| 系统版本 | HarmonyOS 6.1.0(23)+ |
| 摄像头 | 支持自动对焦的后置摄像头 |
| 处理器 | 麒麟系列处理器(推荐) |
| 传感器 | 陀螺仪 + 加速度计 |
> 可以通过 `ARViewContext.init()` 的异常信息判断设备是否支持。
---
## 十、总结
本文详细介绍了使用 HarmonyOS AR Engine 实现人体骨骼关键点识别与跟踪的完整过程,包括:
- AR Engine Kit 的架构和 API
- 权限配置(声明 + 运行时申请)
- 帧数据获取与骨骼关键点提取
- 实时绘制骨骼点和连线
- 4 个实战踩坑经验
人体骨骼识别在体感游戏、运动健康、虚拟试穿等领域有广泛的应用前景,希望本文能帮助鸿蒙开发者快速上手 AR Engine。
---
## 项目地址
本文所有代码已开源:[https://gitcode.com/jianguoxu/myapplication](https://gitcode.com/jianguoxu/myapplication)
更多推荐



所有评论(0)