
鸿蒙AI健身动作矫正系统开发指南 原创
鸿蒙AI健身动作矫正系统开发指南
一、系统架构设计
基于HarmonyOS的AI健身动作矫正系统,利用姿态识别和分布式能力实现以下功能:
实时姿态分析:通过@ohos.ai.body精准识别人体关键点
动作矫正:针对不同训练动作提供专业指导建议
多设备协同:手机捕捉动作,大屏展示矫正反馈
训练同步:多设备实时同步训练状态和进度
!https://example.com/harmony-ai-fitness-arch.png
二、核心代码实现
姿态识别服务封装
// PoseDetectionService.ets
import body from ‘@ohos.ai.body’;
import distributedData from ‘@ohos.distributedData’;
class PoseDetectionService {
private static instance: PoseDetectionService = null;
private bodyDetector: body.BodyDetector;
private dataManager: distributedData.DataManager;
private poseListeners: PoseListener[] = [];
private constructor() {
this.initBodyDetector();
this.initDataManager();
public static getInstance(): PoseDetectionService {
if (!PoseDetectionService.instance) {
PoseDetectionService.instance = new PoseDetectionService();
return PoseDetectionService.instance;
private async initBodyDetector(): Promise<void> {
try {
const context = getContext() as common.Context;
this.bodyDetector = await body.createBodyDetector(context);
await this.bodyDetector.setConfig({
processMode: body.ProcessMode.PROCESS_MODE_VIDEO,
performanceMode: body.PerformanceMode.PERFORMANCE_MODE_FAST
});
catch (err) {
console.error('初始化姿态检测器失败:', JSON.stringify(err));
}
private initDataManager(): void {
this.dataManager = distributedData.createDataManager({
bundleName: ‘com.example.aifitness’,
area: distributedData.Area.GLOBAL,
isEncrypted: true
});
this.dataManager.registerDataListener('pose_sync', (data) => {
this.handleSyncData(data);
});
public async detectPose(pixelMap: image.PixelMap): Promise<PoseDetectionResult> {
const result: PoseDetectionResult = {
keypoints: [],
corrections: []
};
try {
const detectionResults = await this.bodyDetector.detect(pixelMap);
result.keypoints = this.parseKeyPoints(detectionResults.keyPoints);
// 同步姿态数据
this.syncPoseData(result);
catch (err) {
console.error('姿态检测失败:', JSON.stringify(err));
return result;
private parseKeyPoints(keyPoints: body.KeyPoint[]): Map<body.PointType, Point> {
const keyPointsMap = new Map<body.PointType, Point>();
keyPoints.forEach(point => {
keyPointsMap.set(point.pointType, {
x: point.coordinateX,
y: point.coordinateY,
score: point.score
});
});
return keyPointsMap;
private syncPoseData(result: PoseDetectionResult): void {
this.dataManager.syncData('pose_sync', {
type: 'pose_data',
keypoints: result.keypoints,
timestamp: Date.now(),
deviceId: this.dataManager.getDeviceId()
});
private handleSyncData(data: any): void {
if (!data || data.type !== 'pose_data') return;
const result: PoseDetectionResult = {
keypoints: data.keypoints,
corrections: []
};
this.poseListeners.forEach(listener => {
listener.onPoseDetected(result);
});
public addPoseListener(listener: PoseListener): void {
if (!this.poseListeners.includes(listener)) {
this.poseListeners.push(listener);
}
public removePoseListener(listener: PoseListener): void {
this.poseListeners = this.poseListeners.filter(l => l !== listener);
}
interface PoseListener {
onPoseDetected(result: PoseDetectionResult): void;
interface PoseDetectionResult {
keypoints: Map<body.PointType, Point>;
corrections: Correction[];
interface Point {
x: number;
y: number;
score: number;
interface Correction {
part: string;
message: string;
severity: ‘low’ ‘medium’
‘high’;
export const poseService = PoseDetectionService.getInstance();
动作分析服务
// MotionAnalysisService.ets
import { poseService } from ‘./PoseDetectionService’;
class MotionAnalysisService {
private static instance: MotionAnalysisService = null;
private currentExercise: Exercise | null = null;
private analysisListeners: AnalysisListener[] = [];
private constructor() {
this.setupPoseListener();
public static getInstance(): MotionAnalysisService {
if (!MotionAnalysisService.instance) {
MotionAnalysisService.instance = new MotionAnalysisService();
return MotionAnalysisService.instance;
private setupPoseListener(): void {
poseService.addPoseListener({
onPoseDetected: (result) => {
if (this.currentExercise) {
this.analyzePose(result);
}
});
public setCurrentExercise(exercise: Exercise): void {
this.currentExercise = exercise;
private analyzePose(result: PoseDetectionResult): void {
if (!this.currentExercise) return;
const corrections: Correction[] = [];
switch (this.currentExercise.id) {
case 'squat':
corrections.push(...this.analyzeSquat(result.keypoints));
break;
case 'pushup':
corrections.push(...this.analyzePushup(result.keypoints));
break;
case 'lunge':
corrections.push(...this.analyzeLunge(result.keypoints));
break;
// 通知监听器
this.analysisListeners.forEach(listener => {
listener.onAnalysisResult(corrections);
});
// 同步矫正建议
this.syncCorrections(corrections);
private analyzeSquat(keypoints: Map<body.PointType, Point>): Correction[] {
const corrections: Correction[] = [];
const leftHip = keypoints.get(body.PointType.POINT_TYPE_HIP_LEFT);
const rightHip = keypoints.get(body.PointType.POINT_TYPE_HIP_RIGHT);
const leftKnee = keypoints.get(body.PointType.POINT_TYPE_KNEE_LEFT);
const rightKnee = keypoints.get(body.PointType.POINT_TYPE_KNEE_RIGHT);
// 膝盖超过脚尖检测
if (leftKnee && leftHip && leftKnee.x < leftHip.x) {
corrections.push({
part: 'left_knee',
message: '左膝盖超过脚尖,请调整姿势',
severity: 'high'
});
if (rightKnee && rightHip && rightKnee.x < rightHip.x) {
corrections.push({
part: 'right_knee',
message: '右膝盖超过脚尖,请调整姿势',
severity: 'high'
});
return corrections;
private syncCorrections(corrections: Correction[]): void {
poseService.syncData('pose_sync', {
type: 'corrections',
corrections: corrections,
timestamp: Date.now(),
deviceId: poseService.getDeviceId()
});
public addAnalysisListener(listener: AnalysisListener): void {
if (!this.analysisListeners.includes(listener)) {
this.analysisListeners.push(listener);
}
public removeAnalysisListener(listener: AnalysisListener): void {
this.analysisListeners = this.analysisListeners.filter(l => l !== listener);
}
interface AnalysisListener {
onAnalysisResult(corrections: Correction[]): void;
interface Exercise {
id: string;
name: string;
description: string;
difficulty: ‘beginner’ ‘intermediate’
‘advanced’;
export const motionService = MotionAnalysisService.getInstance();
手机端动作捕捉界面
// PhoneCaptureScreen.ets
import { motionService } from ‘./MotionAnalysisService’;
import { poseService } from ‘./PoseDetectionService’;
import camera from ‘@ohos.multimedia.camera’;
@Component
export struct PhoneCaptureScreen {
@State currentExercise: Exercise | null = null;
@State corrections: Correction[] = [];
@State isProcessing: boolean = false;
@State frameCount: number = 0;
private cameraManager: camera.CameraManager;
private previewOutput: camera.PreviewOutput | null = null;
build() {
Column() {
// 摄像头预览
XComponent({
id: ‘cameraPreview’,
type: ‘surface’,
controller: this.cameraController
})
.width(‘100%’)
.height(‘60%’)
.onLoad(() => {
this.initCamera();
})
// 训练信息
if (this.currentExercise) {
Column() {
Text(this.currentExercise.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 8 })
Text(this.currentExercise.description)
.fontSize(14)
.fontColor('#666666')
.padding(16)
.width('90%')
.backgroundColor('#F5F5F5')
.borderRadius(8)
.margin({ bottom: 16 })
// 矫正建议
if (this.corrections.length > 0) {
Column() {
Text('矫正建议:')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 8 })
ForEach(this.corrections, (correction) => {
Row() {
Image(this.getSeverityIcon(correction.severity))
.width(20)
.height(20)
.margin({ right: 10 })
Text(correction.message)
.fontSize(16)
.margin({ bottom: 8 })
})
.padding(16)
.width('90%')
.backgroundColor('#FFF3E0')
.borderRadius(8)
.margin({ bottom: 16 })
// 控制按钮
Button(this.isProcessing ? '结束训练' : '开始训练')
.width('80%')
.height(50)
.onClick(() => {
this.toggleProcessing();
})
.width(‘100%’)
.height('100%')
.padding(20)
.onAppear(() => {
motionService.addAnalysisListener({
onAnalysisResult: (corrections) => {
this.corrections = corrections;
});
})
.onDisappear(() => {
motionService.removeAnalysisListener({
onAnalysisResult: () => {}
});
this.releaseCamera();
})
private async initCamera(): Promise<void> {
try {
this.cameraManager = await camera.getCameraManager(getContext(this));
const cameras = await this.cameraManager.getSupportedCameras();
if (cameras.length === 0) {
console.error('未找到可用摄像头');
return;
// 使用后置摄像头
const cameraDevice = cameras.find(c => c.position === camera.CameraPosition.CAMERA_POSITION_BACK) || cameras[0];
// 创建相机输入
const cameraInput = await this.cameraManager.createCameraInput(cameraDevice);
await cameraInput.open();
// 创建预览输出
const surfaceId = this.cameraController.getSurfaceId();
this.previewOutput = await this.cameraManager.createPreviewOutput(surfaceId);
// 创建会话
const captureSession = await this.cameraManager.createCaptureSession();
await captureSession.beginConfig();
await captureSession.addInput(cameraInput);
await captureSession.addOutput(this.previewOutput);
await captureSession.commitConfig();
await captureSession.start();
// 开始帧捕获
this.startFrameCapture();
catch (err) {
console.error('初始化相机失败:', JSON.stringify(err));
}
private startFrameCapture(): void {
this.previewOutput?.on(‘frameStart’, () => {
if (this.isProcessing && this.frameCount % 5 === 0) { // 每5帧处理一次
this.captureAndProcess();
this.frameCount++;
});
private async captureAndProcess(): Promise<void> {
try {
const imageReceiver = await this.previewOutput?.createImageReceiver();
if (!imageReceiver) return;
const image = await imageReceiver.readNextImage();
const pixelMap = await image.createPixelMap();
// 进行姿态检测
await poseService.detectPose(pixelMap);
image.close();
catch (err) {
console.error('捕获和处理帧失败:', JSON.stringify(err));
}
private toggleProcessing(): void {
this.isProcessing = !this.isProcessing;
private getSeverityIcon(severity: string): Resource {
switch (severity) {
case 'high': return $r('app.media.ic_error');
case 'medium': return $r('app.media.ic_warning');
default: return $r('app.media.ic_info');
}
大屏矫正反馈界面
// TVFeedbackScreen.ets
import { motionService } from ‘./MotionAnalysisService’;
import { poseService } from ‘./PoseDetectionService’;
@Component
export struct TVFeedbackScreen {
@State currentExercise: Exercise | null = null;
@State corrections: Correction[] = [];
@State poseView: PoseView | null = null;
build() {
Column() {
// 标题
Text(‘AI健身教练’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 })
// 3D姿态展示
Row() {
// 标准动作
Column() {
Text('标准动作')
.fontSize(18)
.margin({ bottom: 10 })
PoseView({
pose: this.getStandardPose(),
color: '#4CAF50'
})
.width('90%')
.height(300)
.width(‘50%’)
// 用户动作
Column() {
Text('你的动作')
.fontSize(18)
.margin({ bottom: 10 })
PoseView({
pose: this.poseView,
color: '#2196F3'
})
.width('90%')
.height(300)
.width(‘50%’)
.margin({ bottom: 20 })
// 矫正建议
if (this.corrections.length > 0) {
Column() {
Text('矫正建议:')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
ForEach(this.corrections, (correction) => {
Row() {
Image(this.getSeverityIcon(correction.severity))
.width(20)
.height(20)
.margin({ right: 10 })
Text(correction.message)
.fontSize(16)
.margin({ bottom: 8 })
})
.width(‘90%’)
.padding(20)
.backgroundColor('#FFF3E0')
.borderRadius(8)
else if (this.currentExercise) {
Text('动作标准,继续保持!')
.fontSize(18)
.fontColor('#4CAF50')
.margin({ top: 20 })
}
.width('100%')
.height('100%')
.padding(20)
.onAppear(() => {
motionService.addAnalysisListener({
onAnalysisResult: (corrections) => {
this.corrections = corrections;
});
poseService.addPoseListener({
onPoseDetected: (result) => {
this.poseView = this.createPoseView(result.keypoints);
});
})
.onDisappear(() => {
motionService.removeAnalysisListener({
onAnalysisResult: () => {}
});
poseService.removePoseListener({
onPoseDetected: () => {}
});
})
private getStandardPose(): PoseView | null {
if (!this.currentExercise) return null;
// 根据当前训练动作返回标准姿态
const standardPose = new Map<body.PointType, Point>();
switch (this.currentExercise.id) {
case 'squat':
standardPose.set(body.PointType.POINT_TYPE_SHOULDER_LEFT, { x: 300, y: 200, score: 1 });
standardPose.set(body.PointType.POINT_TYPE_SHOULDER_RIGHT, { x: 500, y: 200, score: 1 });
standardPose.set(body.PointType.POINT_TYPE_HIP_LEFT, { x: 320, y: 400, score: 1 });
standardPose.set(body.PointType.POINT_TYPE_HIP_RIGHT, { x: 480, y: 400, score: 1 });
standardPose.set(body.PointType.POINT_TYPE_KNEE_LEFT, { x: 350, y: 600, score: 1 });
standardPose.set(body.PointType.POINT_TYPE_KNEE_RIGHT, { x: 450, y: 600, score: 1 });
break;
case 'pushup':
// 俯卧撑标准姿态
break;
return this.createPoseView(standardPose);
private createPoseView(keypoints: Map<body.PointType, Point>): PoseView {
return {
keypoints: keypoints,
connections: this.getPoseConnections(keypoints)
};
private getPoseConnections(keypoints: Map<body.PointType, Point>): Connection[] {
const connections: Connection[] = [];
// 左臂
if (keypoints.has(body.PointType.POINT_TYPE_SHOULDER_LEFT) &&
keypoints.has(body.PointType.POINT_TYPE_ELBOW_LEFT)) {
connections.push({
from: body.PointType.POINT_TYPE_SHOULDER_LEFT,
to: body.PointType.POINT_TYPE_ELBOW_LEFT
});
// 右臂
if (keypoints.has(body.PointType.POINT_TYPE_SHOULDER_RIGHT) &&
keypoints.has(body.PointType.POINT_TYPE_ELBOW_RIGHT)) {
connections.push({
from: body.PointType.POINT_TYPE_SHOULDER_RIGHT,
to: body.PointType.POINT_TYPE_ELBOW_RIGHT
});
// 躯干
if (keypoints.has(body.PointType.POINT_TYPE_SHOULDER_LEFT) &&
keypoints.has(body.PointType.POINT_TYPE_HIP_LEFT)) {
connections.push({
from: body.PointType.POINT_TYPE_SHOULDER_LEFT,
to: body.PointType.POINT_TYPE_HIP_LEFT
});
// 更多连接…
return connections;
}
interface PoseView {
keypoints: Map<body.PointType, Point>;
connections: Connection[];
interface Connection {
from: body.PointType;
to: body.PointType;
三、项目配置与权限
权限配置
// module.json5
“module”: {
"requestPermissions": [
“name”: “ohos.permission.CAMERA”,
"reason": "捕捉训练动作"
},
“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,
"reason": "同步训练状态"
},
“name”: “ohos.permission.INTERNET”,
"reason": "加载AI模型"
},
“name”: “ohos.permission.READ_MEDIA”,
"reason": "读取训练资料"
},
“name”: “ohos.permission.ACCESS_DISTRIBUTED_DEVICE_MANAGER”,
"reason": "发现和连接其他设备"
],
"abilities": [
“name”: “MainAbility”,
"type": "page",
"visible": true
},
“name”: “CameraAbility”,
"type": "page",
"visible": true
},
“name”: “TVAbility”,
"type": "page",
"visible": true
},
“name”: “PoseDetectionAbility”,
"type": "service",
"backgroundModes": ["dataTransfer"]
]
}
四、总结与扩展
本AI健身动作矫正系统实现了以下核心功能:
精准识别:实时捕捉人体关键点并分析动作
智能矫正:针对不同训练提供专业指导建议
多屏互动:手机捕捉动作,大屏展示反馈
训练同步:多设备实时同步训练状态
扩展方向:
训练计划:根据用户水平制定个性化训练方案
进度追踪:记录训练数据并可视化进步曲线
社交功能:分享训练成果,好友间挑战
健康数据:接入穿戴设备监测心率等指标
VR集成:结合VR设备提供沉浸式训练体验
通过HarmonyOS的分布式能力和AI框架,我们构建了一个智能、互联的健身指导系统,让家庭健身更加科学高效。
