ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Project AIRI 中的 MediaPipe 单人体感动捕管线:从摄像头帧到 VRM 驱动的架构与实践

Project AIRI 中的 MediaPipe 单人体感动捕管线:从摄像头帧到 VRM 驱动的架构与实践 Project AIRI 中的 MediaPipe 单人体感动捕管线从摄像头帧到 VRM 驱动的架构与实践【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi本篇技术指南聚焦 Project AIRI 仓库中的实验性单人体感动捕mocap管线包proj-airi/model-driver-mediapipe。它以camera frame → mediapipe/tasks-vision → PerceptionState → overlay / VRM的闭环为骨架讲清引擎调度、丢帧策略、任务级限速与媒体后端边界并给出从摄像头采集到骨骼姿态应用至 VRM 模型的完整可运行方案。读完你将掌握一套可直接复用的浏览器端单人动捕架构以及将 2D/3D 关键点转换为 VRM 骨骼驱动方向的工程化实现。包定位与设计意图packages/model-driver-mediapipe/AGENTS.md 将该包定义为实验性单人体感动捕管线experimental single-person mocap pipeline服务对象是 stage-web 开发者工具devtools。其核心数据流是一条极简闭环camera frame → mediapipe/tasks-vision → PerceptionState → overlay在 packages/model-driver-mediapipe/README.md 中这一闭环进一步明确为 stage-web 可直接消费的最小回路并给出了实际体验入口开发工具页apps/stage-web/src/pages/devtools/model-driver-mediapipe.vue菜单入口Settings → System → Developer → MediaPipe Workshop路由注册见 apps/stage-web/src/pages/settings/system/developer.vue包本身位于 packages/model-driver-mediapipe/package.json依赖mediapipe/tasks-vision、pixiv/three-vrm、three、es-toolkit与moeru/std通过postinstall脚本自动准备推理任务资产。设计约定函数式、窄契约与干净的后端边界AGENTS.md 明确了几条对整个实现有约束力的编码约定读懂它们有助于理解后续每一层代码的结构偏好函数式编程FP与纯函数有状态模块用工厂函数 闭包实现例如createMocapEngine()除非是扩展浏览器 API 或被外部库要求避免使用 class。这与 src/engine.ts 中createStats、createScheduler、createMocapEngine三个工厂函数一一对应。保持后端边界干净引擎/调度器不得 importmediapipe/tasks-visionMediaPipe 相关细节全部收拢在 src/backends/ 下。事实上src/backends/mediapipe.ts 是唯一的后端实现。类型稳定且窄stage 消费方以 src/types.ts 为契约新增字段必须可选且向后兼容。中层契约PerceptionState 与配置类型src/types.ts 是整个管线的中间层契约也是 stage 消费方唯一依赖的类型面。它把底层 MediaPipe 结果归一化为三种感知状态与一套质量指标PoseStatelandmarks2d归一化 2D 关键点与worldLandmarks3D 世界关键点分别对应NormalizedLandmark与LandmarkHandStatehandednessLeft | Right、21 个 2D 关键点及置信度scoreFaceStatehasFace与 468 个 2D 关键点PerceptionQualityfps、latencyMs、droppedFrames并标记backend: mediapipe与mode: split-tasksPerceptionPartial上述三个子状态均为可选用于支持部分合并partial merge。运行配置MocapConfig的关键字段为字段类型含义enabledRecordMocapJob, boolean每个任务pose/hands/face的开关hzRecordMocapJob, number每个任务的调度速率Hz用于限流maxPeople1固定为单人同时类型层定义了后端与引擎的接口MocapBackendinit/isBusy/run与MocapEngineinit/start/stop/updateConfig/resetState这正是引擎不依赖 MediaPipe 具体实现得以成立的基础。完整导出见 src/index.ts。引擎调度限速、丢帧策略与状态合并src/engine.ts 实现了调度 丢帧策略 部分合并三件事全程采用函数式写法。帧率统计createStats以requestAnimationFrame的时间戳为基准计算瞬时 FPS并用指数滑动平均smoothedFps * 0.9 fps * 0.1平滑抖动。任务调度器createScheduler每个任务pose/hands/face独立记录上次执行时刻lastRunplan(nowMs)按1000 / hz判断本轮是否轮到某个任务从而把每一帧的推理开销控制在用户配置的速率之下——这是对同步detectForVideo()阻塞主线程的直接对冲手段。引擎主循环createMocapEngineconst tick async () { const frame source.getFrame() const now performance.now() // Skip this frame if the backend is still busy. if (backend.isBusy()) { droppedFrames rafId requestAnimationFrame(tick) return } const jobs scheduler.plan(now) const t0 performance.now() const partial jobs.length 0 ? await backend.run(frame, jobs, now) : {} const latencyMs performance.now() - t0 lastPartial { ...lastPartial, ...partial } onState({ t: now, ...lastPartial, quality: { fps, latencyMs, droppedFrames, backend: mediapipe, mode: split-tasks } }) rafId requestAnimationFrame(tick) }值得注意的实现细节丢帧策略当后端isBusy()返回 true上一帧推理尚未完成当前帧直接跳过并累加droppedFrames绝不排队积压避免 UI 线程被无限阻塞部分合并partial mergelastPartial { ...lastPartial, ...partial }只更新本轮实际推理过的任务子状态其余子状态沿用上一帧使各任务可以以不同速率独立刷新错误隔离异常会停止主循环并回调options.onError避免错误风暴消费方可决定是否重启apps/stage-web/src/pages/devtools/model-driver-mediapipe.vue 中的onError正是这一设计的使用方。MediaPipe 后端模型加载与同步推理src/backends/mediapipe.ts 是mediapipe/tasks-vision的适配层要点如下惰性加载init()动态import(mediapipe/tasks-vision)并通过FilesetResolver.forVisionTasks(visionTaskWasmRoot)解析 WASM 文件集仅首次调用时执行按需创建 landmarkerensurePoseLandmarker/ensureHandLandmarker/ensureFaceLandmarker三个工厂各自缓存实例配置分别为// 姿态 PoseLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: visionTaskAssets.pose }, runningMode: VIDEO, numPoses: 1, }) // 手部 HandLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: visionTaskAssets.hands }, runningMode: VIDEO, numHands: 2, }) // 面部 FaceLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: visionTaskAssets.face }, runningMode: VIDEO, numFaces: 1, })同步推理run()内以es-toolkit的Semaphore(1)保证并发安全置位busy标志供引擎查询再按任务列表依次调用detectForVideo(frame, nowMs)。正如 references/tasks-vision-api.md 所记录的detectForVideo()是同步调用、可能阻塞主线程这正是引擎限速与丢帧策略存在的根本原因结果归一化姿态取res.landmarks[0]与res.worldLandmarks[0]单人场景手部取res.handedness[i][0].categoryName判定左右手并附带置信度score面部只保留hasFace与关键点作为仅存在性处理468 个点开销较大参考任务注释。任务资产准备tasks/prepare-tasks.ts 是postinstall触发的资产准备脚本从 MediaPipe 官方模型存储下载pose_landmarker_lite、hand_landmarker、face_landmarker三个.task文件并把node_modules/mediapipe/tasks-vision/wasm复制到包内assets/wasm。资产路径在 tasks/tasks.ts 中以new URL(./assets/..., import.meta.url)的方式声明保证浏览器端可解析脚本内置withRetry重试与已存在文件的跳过逻辑。调试叠加层overlay 渲染器src/utils/overlay.ts 提供 canvas 叠加渲染。它使用 MediaPipe 的DrawingUtils分别绘制姿态PoseLandmarker.POSE_CONNECTIONS连接线 关键点手部HandLandmarker.HAND_CONNECTIONS连接线 关键点左右手使用不同调色板区分左手指向 palette 索引 1右手索引 2面部468 个点用小半径facePointRadius: 2绘制以减少视觉杂乱。调色板与线宽/点半径常量以面向 devtools 可读性为原则做了手工调优drawOverlay支持按enabled参数单独开关三类绘制绘制前先clearRect清空画布逐帧重绘。动捕到 VRM姿态骨骼驱动管线并不止步于叠加可视化而是进一步把 MediaPipe 的姿态输出映射为 VRM 骨骼驱动方向这是它区别于纯演示的核心价值所在。相关实现位于 src/three/pose → VRM 目标pose-to-vrm.tsposeToVrmTargets()以世界关键点为主、归一化关键点为兜底输出VrmPoseTargets——一组方向 pole 向量目标覆盖hips、spine、chest、左右肩/大臂/小臂/大腿/小腿等 13 个骨骼。工程细节包括轴重映射axis选项x/y/z各取1 | -1把 MediaPipe 世界坐标系映射到 three/VRM 空间默认{1,1,1}页面端可通过 flip 开关翻转见 model-driver-mediapipe.vue 的vrmMapping置信度门控confidence.minVisibility默认0.5/minPresence基于关键点的visibility/presence字段过滤当visibility缺失时直接不输出该关键点依赖的目标避免噪声驱动躯干朝向推导由hipCenter → shoulderCenter求 up、leftShoulder → rightShoulder求 right再以right × up得 forward并做符号校正稳定化stabilize.previousTargets/previousForward用于避免因极点歧义导致的 180° 翻转具体手段是当上一帧 pole 与当前 pole 点积为负时取反下肢保守策略腿只在大腿/膝盖/脚踝三者齐备时才输出目标减少下半身离屏时的幻觉翻转。应用至 VRMapply-pose-to-vrm.tscreateVrmPoseApplier()返回applyPoseDirectionsToVrm/applyPoseTargetsToVrm两个函数把上述目标应用到pixiv/three-vrm的人形骨骼。关键机制骨骼链映射CHAINS表把 13 个姿态键映射到 VRM 骨骼名及其候选子骨骼如spine的子骨骼候选为chest / upperChest / neck骨骼不存在时优雅降级静止方向/极点缓存首次应用时按骨骼世界坐标与子骨骼差向量推算 rest 方向与 rest pole并在局部空间缓存方向应用无 pole 时用Quaternion.setFromUnitVectors(currentDir, targetDir)求增量旋转有 pole 时构建 rest/target 两组 basis 矩阵makeBasis(dir, y, pole)求相对旋转矩阵把目标方向与极点同时映射到骨骼翻转拒绝minDotBeforeReject默认-0.2约拒绝 101°基于上一帧目标方向而非当前骨骼姿态判断瞬时 180° 翻转minPoleDotBeforeReject对 pole 做同样的保护平滑插值alpha默认0.35[0..1]对最终局部四元数做slerpalpha 越高越跟手、越低越平滑。端到端接线MediaPipe Workshop 页面apps/stage-web/src/pages/devtools/model-driver-mediapipe.vue 把以上所有模块串成可运行闭环可作为读者整合各层的参考范式startCamera()通过navigator.mediaDevices.getUserMedia({ video: true })获取摄像头流绑定video元素并play()startPipeline()依次createMediaPipeBackend()→createMocapEngine(backend, config)→engine.init()→engine.start({ getFrame: () video }, onState, { onError })其中FrameSource.getFrame直接返回视频元素onState回调中做三件事更新页面状态摘要enabled/hz/fps/latency/dropped调用poseToVrmTargets(state.pose, { axis, confidence, stabilize })生成 VRM 目标并通过vrmPoseApplier.applyPoseTargetsToVrm(vrm, targets)在ThreeScene的帧钩子中驱动模型最后drawOverlay(ctx, state, enabled)把关键点画到 canvas 叠加层页面watch(config, ...)深监听配置变化并调用engine.updateConfig()实现运行中动态调整任务开关与 Hz 限速stop()设计上考虑了MediaPipe 可能仍在处理进行中帧的情况通过ignoreErrorsUntil窗口吞掉停止期间的瞬时错误再释放摄像头轨道与清空画布。页面默认开启 pose/hands/face 三个任务且各 30Hz、maxPeople: 1、姿态过滤minVisibility: 0.5并在onMounted自动启动方便直接体验。上游 API 备忘与适用前提references/tasks-vision-api.md 是包内维护的最小 API 备忘记录了三项对本实现最关键的结论可视为理解整条管线的速查卡初始化FilesetResolver.forVisionTasks(wasmRoot)后以createFromOptions(vision, { baseOptions, runningMode: VIDEO, numPoses: 1 })创建 landmarker同步推理detectForVideo(videoEl, nowMs)同步执行、可能阻塞主线程因此引擎必须限速与丢帧结果形状单人场景姿态res.landmarks/res.worldLandmarks取[0]x/y归一化到[0..1]手部res.landmarks每只手 21 点、res.handedness[i][0]提供左右手与置信度面部res.faceLandmarks为 468 点、开销大默认仅作存在性使用。需要说明的适用前提与限制本包是实验性单人管线maxPeople固定为 1依赖浏览器端 WASM 推理性能受设备与所选模型姿态使用 lite 版影响手部支持最多 2 只手仓库未提供对多人、离线编译模型或非浏览器运行环境的支持。这些边界在 README.md 的 Backend assumptions 一节中亦有明确声明。【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表