ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

树莓派+WebRTC+TensorFlow.js实现低延迟实时人体姿态识别

树莓派+WebRTC+TensorFlow.js实现低延迟实时人体姿态识别 简介本资源是一个面向嵌入式AI与Web前端开发者的学习型项目聚焦于低成本、低延迟的实时人体姿态识别智能交互系统构建。它解决了树莓派端视频采集、WebRTC流传输与浏览器端轻量级AI推理协同难的问题适用于智能健身指导、远程教育互动、体感游戏开发等场景。压缩包共29个文件192KB含14个核心JavaScript逻辑文件实现PoseNet加载与关键点渲染、4个HTML页面含rws.html流接入页与posenet.html识别页、2个配置文件media_config.conf与nginx.conf、2个CSS样式文件及README.md、说明文件.txt、附赠资源.docx等辅助文档结构清晰、开箱即用。目前已有110人学习下载读者可直接部署运行获得从树莓派摄像头采集→rpi-webrtc-streamer推流→TensorFlow.js PoseNet浏览器端实时姿态估计的完整链路代码、配置模板与实操指引特别适合具备基础JavaScript和Linux命令能力的中级开发者快速复现并二次拓展。1. 项目缘起从“玩具”到“智能交互”的蜕变几年前当我第一次把树莓派和摄像头模块接在一起看着屏幕上实时显示的画面时那种感觉就像小时候拆开一个新玩具。但很快这种简单的“视频监控”玩法就让我觉得索然无味。我一直在想能不能让这块小小的板子“看懂”画面里的人在做什么比如识别出一个人是在挥手、举手还是跳舞然后触发一些有趣的交互。这就是我启动这个项目的初衷让树莓派摄像头不再只是“眼睛”更要成为能理解人体动作的“大脑”。这个想法听起来很酷但实现起来却是一连串的挑战。最核心的问题有两个延迟和算力。如果我想在浏览器里实时看到姿态识别的效果视频流从摄像头采集、传输到浏览器再经过AI模型分析、渲染出骨骼点整个过程必须在几十毫秒内完成否则交互体验会非常糟糕。同时树莓派的CPU性能有限如果让它在本地运行一个复杂的姿态识别模型帧率会惨不忍睹。经过一番折腾和试错我最终确定了现在的技术栈树莓派 OV5647摄像头负责采集rpi-webrtc-streamer实现超低延迟的视频流推送最后在用户的浏览器端用TensorFlow.js的PoseNet模型完成实时姿态识别。这个架构的精妙之处在于“各司其职”树莓派只做它最擅长的视频采集和高效编码传输将最消耗算力的AI推理任务“卸载”到了拥有强大GPU的客户端浏览器上。这样一来树莓派的负载极低而用户端也能获得流畅的实时体验。整个系统非常适合那些想探索边缘AI、实时交互的开发者或者任何想给树莓派项目增加一点“智能”的朋友。无论是用来做体感游戏控制器、智能健身教练原型还是简单的安防人形检测这个框架都能提供一个坚实、低延迟的起点。2. 硬件选型与系统搭建为实时流打好地基工欲善其事必先利其器。硬件和系统环境的准备是项目成功的第一步这里面的门道不少选错了或者配不好后面会麻烦不断。2.1 树莓派与摄像头的选择为什么是OV5647首先说树莓派。树莓派4B 4GB版本是这个项目的黄金选择。它的CPU和内存足够流畅运行我们所需的流媒体服务并且价格适中。树莓派5性能更强但功耗和发热也更大对于这个项目来说有些性能过剩。树莓派Zero 2虽然便宜小巧但其孱弱的算力在处理视频编码时可能会成为瓶颈不推荐。摄像头的选择至关重要。标题和相关热词里提到了“树莓派ov5647摄像头模块”这并非偶然。树莓派官方摄像头模块主要有两种CSI接口的OV5647500万像素和IMX219800万像素。我强烈推荐使用OV5647原因有三驱动与兼容性OV5647是树莓派上历史最久、支持最完善的摄像头模块之一几乎所有基于Linux V4L2Video for Linux 2框架的软件都能即插即用减少了驱动层面的折腾。性能与带宽平衡500万像素对于实时视频流绰绰有余。我们通常只需要传输720p1280x720甚至480p640x480的视频OV5647在这些分辨率下能轻松跑到30fps以上。更高的像素意味着更大的数据量会给树莓派的CPU编码和网络传输带来不必要的压力。成本OV5647模块通常比IMX219更便宜。注意购买时请认准CSI排线接口。市面上有些USB摄像头虽然也能用但USB总线传输和编码的延迟通常高于树莓派专用的CSI总线不利于实现最低延迟。2.2 系统刷机与基础配置拿到硬件后第一步是给树莓派安装操作系统。系统选择使用Raspberry Pi OS原RaspbianLite版本64位。Lite版本是无桌面环境的纯命令行系统资源占用极少能把所有算力都留给我们的服务。通过官方工具“Raspberry Pi Imager”刷写镜像到MicroSD卡是最稳妥的方式。基础配置首次启动前可以在刷卡完成后在boot分区创建一个名为ssh的空文件开启SSH服务和一个包含countryCN等信息的wpa_supplicant.conf文件配置Wi-Fi。这样你就能通过SSH远程登录树莓派了无需连接键鼠显示器。系统更新与换源登录后第一件事是换源国内用户使用清华或中科大的镜像源能极大提升软件下载速度。执行sudo apt update sudo apt upgrade -y进行全系统更新。摄像头接口启用这是关键一步。运行sudo raspi-config进入 “Interface Options” - “Legacy Camera”选择 “Yes” 以启用旧的摄像头驱动栈。虽然新的“libcamera”是趋势但rpi-webrtc-streamer目前对旧版驱动支持更成熟稳定。2.3 网络环境考量有线优于无线为了追求最低延迟请务必使用千兆有线网络网线连接你的树莓派和路由器。Wi-Fi无论是树莓派连接Wi-Fi还是客户端在Wi-Fi下访问会引入不可预测的抖动和延迟在实时视频流和交互场景中是致命的。确保你的树莓派、开发电脑/客户端都在同一个局域网内这样可以走内网传输速度最快。3. 核心引擎rpi-webrtc-streamer的部署与调优视频流传输是整个系统的血管它的通畅与否直接决定了体验。我们选择rpi-webrtc-streamer是因为它专为树莓派优化直接调用硬件编码器H.264并通过WebRTC协议实现浏览器与树莓派间的点对点低延迟通信。3.1 编译与安装rpi-webrtc-streamer这个项目需要从源码编译过程稍显复杂但一步步来并不难。# 1. 安装必要的依赖包 sudo apt install -y git build-essential cmake pkg-config libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libv4l-dev # 2. 克隆仓库建议使用国内镜像或提前下载原始仓库较大 git clone https://github.com/kclyu/rpi-webrtc-streamer.git cd rpi-webrtc-streamer # 3. 创建并进入构建目录 mkdir build cd build # 4. 使用CMake配置关键是指定使用树莓派的MMAL多媒体抽象层硬件编码 cmake -DCMAKE_BUILD_TYPERelease -DUSE_MMAL_ENCODERON .. # 5. 开始编译树莓派4B上可能需要20-30分钟 make -j4 # 6. 编译完成后可执行文件webrtc-streamer就在当前目录下编译成功的关键在于-DUSE_MMAL_ENCODERON这个选项。它告诉编译器使用树莓派的GPU进行H.264视频编码这比用CPU软件编码效率高几十倍能极大降低CPU占用并保证高帧率。3.2 配置与启动流媒体服务直接运行编译好的程序即可启动服务。但我们需要通过参数进行一些优化配置。# 在build目录下运行 ./webrtc-streamer -C config.json这里的-C参数指定了一个配置文件。我们可以创建一个config.json来固化我们的设置{ webrtc: { port: 8000, ssl: false }, streams: { raspicam: { input: v4l2, device: /dev/video0, width: 1280, height: 720, framerate: 30, codec: H264, bitrate: 2000000, gop: 60 } } }参数解析与调优经验port: WebRTC信令服务器端口浏览器通过这个端口与树莓派建立连接。ssl: 局域网内测试设为false即可避免证书的麻烦。如需公网访问必须设为true并配置证书。device:/dev/video0是启用Legacy Camera后CSI摄像头的默认设备路径。width/height: 设置为720p。这是延迟和画质的一个很好平衡点。480p640x480延迟更低但画质稍差1080p对树莓派编码和网络压力都太大不推荐。framerate: 30fps对于人体姿态识别足够流畅。codec: 必须为H264这是WebRTC和浏览器硬件解码支持最好的编码。bitrate: 码率单位bps。20000002Mbps对于720p30帧的H.264是足够的。如果画面复杂、动态多导致模糊可以尝试提高到3000000。码率越高画质越好但网络带宽消耗和编码延迟也会增加。gop: 关键帧间隔设为帧率的2倍60。这个值影响视频的“seek”能力和网络波动后的恢复速度对于实时流不宜设置过大。启动服务后你应该能在树莓派上看到类似“Server listening on http://0.0.0.0:8000”的日志。此时在同一局域网内的电脑浏览器打开http://树莓派IP:8000就能看到一个简单的网页点击“播放”按钮应该就能看到来自树莓派摄像头的实时视频了。延迟通常可以控制在100-200毫秒以内肉眼几乎感觉不到。3.3 常见问题排查踩坑记录启动失败提示“Failed to open V4L2 device /dev/video0”检查摄像头是否启用再次确认sudo raspi-config中已启用Legacy Camera。检查摄像头连接重新插拔CSI排线确保金色触点面向网口方向。检查设备权限运行ls -l /dev/video0看是否属于video组。可以将当前用户加入video组sudo usermod -a -G video $USER然后重新登录生效。网页能打开但视频黑屏或无法播放检查防火墙确保树莓派的8000端口是开放的sudo ufw allow 8000如果使用了UFW。查看服务端日志在启动webrtc-streamer的终端里查看错误信息。常见的是编码器初始化失败确保编译时打开了USE_MMAL_ENCODER。浏览器控制台报错在浏览器按F12打开开发者工具查看“Console”和“Network”标签页是否有WebSocket连接失败或SSL相关的错误。视频卡顿、延迟高首要怀疑网络换用有线网络这是解决卡顿最有效的方法。降低分辨率和码率在config.json中将分辨率改为640x480码率改为1000000试试。检查树莓派负载运行htop命令查看CPU占用率。如果webrtc-streamer进程CPU占用长期超过50%可能是编码参数太高或后台有其他任务。4. 智能之眼在浏览器中集成TensorFlow.js PoseNet视频流畅通了接下来就是赋予它“理解”能力。我们将利用TensorFlow.js直接在用户的浏览器里运行PoseNet模型识别视频中的人体关键点如鼻子、肩膀、手肘、膝盖等。这样做的好处是服务器树莓派零压力且能利用客户端可能是高性能电脑的GPU加速。4.1 前端项目结构与基础HTML我们创建一个简单的前端项目。首先是一个index.html文件用于展示视频和绘制姿态。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title树莓派实时姿态识别/title style body { margin: 0; padding: 20px; font-family: sans-serif; background: #f5f5f5; } .container { display: flex; flex-wrap: wrap; gap: 20px; max-width: 1400px; margin: auto; } .video-box, .canvas-box { flex: 1; min-width: 300px; border: 2px solid #333; border-radius: 8px; overflow: hidden; background: #000; } h2 { color: #333; text-align: center; margin-top: 0; padding: 10px; background: #eee; } video, canvas { display: block; width: 100%; height: auto; } #stats { padding: 10px; background: #fff; border-radius: 5px; margin-top: 10px; font-family: monospace; } .controls { margin-bottom: 15px; text-align: center; } button { padding: 10px 20px; margin: 0 5px; font-size: 16px; cursor: pointer; } /style /head body div classcontainer div classvideo-box h2实时视频流/h2 div classcontrols button idconnectBtn连接视频流/button button iddisconnectBtn disabled断开连接/button /div video idvideoElement playsinline autoplay muted/video div idstats状态: 等待连接.../div /div div classcanvas-box h2姿态识别结果/h2 canvas idoutputCanvas/canvas /div /div !-- 引入TensorFlow.js和PoseNet -- script srchttps://cdn.jsdelivr.net/npm/tensorflow/tfjslatest/script script srchttps://cdn.jsdelivr.net/npm/tensorflow-models/posenetlatest/script !-- 引入我们自己的逻辑 -- script srcapp.js/script /body /html页面布局很简单左侧是来自树莓派的实时视频右侧是一个Canvas画布用于绘制识别出的骨骼关键点和连线。我们通过CDN引入了TensorFlow.js及其PoseNet模型库。4.2 连接WebRTC视频流接下来是核心的app.js。第一部分是连接我们刚才搭建的rpi-webrtc-streamer服务。// app.js const videoElement document.getElementById(videoElement); const outputCanvas document.getElementById(outputCanvas); const ctx outputCanvas.getContext(2d); const connectBtn document.getElementById(connectBtn); const disconnectBtn document.getElementById(disconnectBtn); const statsDiv document.getElementById(stats); let peerConnection null; let stream null; // 替换为你的树莓派IP地址和端口 const RASPBERRY_PI_IP 192.168.1.100; const SIGNALING_SERVER_URL http://${RASPBERRY_PI_IP}:8000; connectBtn.onclick async () { if (peerConnection) return; statsDiv.textContent 正在连接信令服务器...; connectBtn.disabled true; try { // 1. 从信令服务器获取SDP Offer配置 const response await fetch(${SIGNALING_SERVER_URL}/get_offer); const offer await response.json(); // 2. 创建RTCPeerConnection const configuration { iceServers: [{ urls: stun:stun.l.google.com:19302 }] // STUN服务器用于NAT穿透 }; peerConnection new RTCPeerConnection(configuration); // 3. 当有远程流到来时将其赋值给video元素 peerConnection.ontrack (event) { console.log(收到远程流); if (videoElement.srcObject ! event.streams[0]) { videoElement.srcObject event.streams[0]; stream event.streams[0]; statsDiv.textContent 已连接。视频分辨率: ${videoElement.videoWidth}x${videoElement.videoHeight}; // 视频加载后调整Canvas大小并开始姿态估计 videoElement.onloadedmetadata () { outputCanvas.width videoElement.videoWidth; outputCanvas.height videoElement.videoHeight; startPoseEstimation(); }; } }; // 处理ICE候选信息网络连接信息 peerConnection.onicecandidate (event) { if (event.candidate) { // 通常需要将candidate发送给信令服务器但rpi-webrtc-streamer的简单示例中可能不需要 // 这里我们使用一个简化流程 } }; // 4. 设置本地描述SDP await peerConnection.setRemoteDescription(new RTCSessionDescription(offer)); const answer await peerConnection.createAnswer(); await peerConnection.setLocalDescription(answer); // 5. 将Answer发送回信令服务器以完成握手此处为简化实际可能需要POST // 注意rpi-webrtc-streamer的默认示例可能使用不同的信令交互。 // 更通用的方式是使用WebSocket进行完整的信令交换。 // 这里假设服务器端能自动处理仅作演示。复杂场景需实现完整信令。 disconnectBtn.disabled false; } catch (error) { console.error(连接失败:, error); statsDiv.textContent 连接失败: ${error.message}; connectBtn.disabled false; peerConnection null; } }; disconnectBtn.onclick () { if (peerConnection) { peerConnection.close(); peerConnection null; } if (videoElement.srcObject) { videoElement.srcObject.getTracks().forEach(track track.stop()); videoElement.srcObject null; } stream null; ctx.clearRect(0, 0, outputCanvas.width, outputCanvas.height); statsDiv.textContent 连接已断开; connectBtn.disabled false; disconnectBtn.disabled true; };这段代码的核心是使用WebRTC的RTCPeerConnectionAPI与树莓派建立点对点连接。我们从一个简单的HTTP端点获取SDP Offer然后创建Answer并设置本地描述从而建立媒体通道。ontrack事件是成功的关键当视频流到达浏览器时它会被赋值给video标签。重要提示上述信令过程是极度简化的。rpi-webrtc-streamer的示例可能提供了一个更完整的网页http://ip:8000其中包含了处理信令的JavaScript。在实际项目中你可能需要参考其示例代码或者自己实现一个基于WebSocket的信令服务器来处理SDP和ICE候选信息的交换。这里为了聚焦核心流程使用了简化模型。4.3 加载PoseNet模型与实时估计连接视频成功后我们就可以在videoElement上运行PoseNet了。let net null; let isEstimating false; async function loadPoseNetModel() { statsDiv.textContent 正在加载PoseNet模型...; // 加载MobileNetV1架构的模型速度较快精度尚可 // 参数说明architecture - 模型架构inputResolution - 输入图像尺寸越小越快multiplier - 深度乘数越小越快 net await posenet.load({ architecture: MobileNetV1, inputResolution: { width: 640, height: 480 }, // 可以比视频分辨率小加速推理 multiplier: 0.75, // 平衡速度和精度 quantBytes: 2 // 使用2字节量化模型更小加载更快 }); statsDiv.textContent 模型加载完成; console.log(PoseNet模型加载成功); } async function startPoseEstimation() { if (!net || !stream || isEstimating) return; isEstimating true; statsDiv.textContent 开始姿态估计...; async function estimatePose() { if (!isEstimating) return; // 1. 从video元素中估计姿态 // 参数说明videoElement - 输入源imageScaleFactor - 图像缩放因子小于1可提速flipHorizontal - 是否水平翻转 const poses await net.estimatePoses(videoElement, { flipHorizontal: false, maxDetections: 2, // 最多检测2个人 scoreThreshold: 0.5, // 关键点置信度阈值 nmsRadius: 20 // 非极大值抑制半径 }); // 2. 清空画布 ctx.clearRect(0, 0, outputCanvas.width, outputCanvas.height); // 3. 绘制检测到的人体姿态 poses.forEach(pose { drawKeypoints(pose.keypoints, 0.2, ctx); // 绘制关键点阈值0.2 drawSkeleton(pose.keypoints, 0.2, ctx); // 绘制骨架连线 }); // 4. 计算并显示帧率简易版 // 在实际项目中可以使用更精确的stats.js库 // 5. 循环调用实现实时估计 requestAnimationFrame(estimatePose); } // 先加载模型然后开始循环估计 if (!net) { await loadPoseNetModel(); } estimatePose(); } // 停止姿态估计 function stopPoseEstimation() { isEstimating false; } // 绘制关键点函数 function drawKeypoints(keypoints, minConfidence, ctx, scale 1) { keypoints.forEach(keypoint { if (keypoint.score minConfidence) { const { y, x } keypoint.position; ctx.beginPath(); ctx.arc(x * scale, y * scale, 4, 0, 2 * Math.PI); ctx.fillStyle aqua; ctx.fill(); } }); } // 绘制骨架连线函数 function drawSkeleton(keypoints, minConfidence, ctx, scale 1) { // PoseNet定义的相邻关键点对 const adjacentKeyPoints posenet.getAdjacentKeyPoints(keypoints, minConfidence); adjacentKeyPoints.forEach((keypoints) { const [start, end] keypoints.map(kp kp.position); ctx.beginPath(); ctx.moveTo(start.x * scale, start.y * scale); ctx.lineTo(end.x * scale, end.y * scale); ctx.lineWidth 2; ctx.strokeStyle lime; ctx.stroke(); }); } // 页面加载时预加载模型可选 window.onload () { loadPoseNetModel(); // 提前加载减少首次检测延迟 };代码关键点解析与调优经验模型加载参数posenet.load()中的参数是性能调优的关键。inputResolution模型内部处理图像的大小。设为640x480或更低能显著提升帧率对精度影响在可接受范围内。因为我们的视频源是720p模型会先将其缩放到这个尺寸再处理。multiplierMobileNet的宽度乘数值越小如0.5网络越窄速度越快精度越低。0.75是一个不错的平衡点。quantBytes量化字节数。2表示使用16位浮点数模型更小加载和推理更快是推荐选项。姿态估计参数net.estimatePoses()中的参数控制检测行为。scoreThreshold关键点置信度阈值。调高如0.7可以减少误检但可能丢失部分关键点调低如0.3则更敏感但噪声也多。需要根据场景调整。maxDetections根据你的场景设置。如果只检测单人设为1效率最高。绘制优化drawKeypoints和drawSkeleton函数中的scale参数用于适配Canvas和视频源的分辨率。如果Canvas大小与视频分辨率一致如我们之前设置的scale应为1。性能瓶颈姿态估计是计算密集型任务。在低端电脑或手机浏览器上帧率可能下降。除了调整上述模型参数还可以降低估计频率例如不用requestAnimationFrame通常60fps而改用setInterval(estimatePose, 50)20fps。现在打开浏览器访问你的页面点击“连接视频流”再稍等片刻模型加载你应该能在右侧画布上看到实时绘制的人体骨骼点了。挥手、走动看看系统的反应速度。5. 从演示到应用构建智能交互逻辑有了稳定的视频流和准确的关键点数据我们就可以在此基础上构建真正的“智能交互”了。姿态数据只是一组坐标真正的价值在于如何解读它们。5.1 解析姿态数据与定义动作PoseNet输出的pose.keypoints是一个包含17个关键点如鼻子、左右眼、左右肩等的数组。每个关键点对象包含position:{x, y}和score置信度。一个简单的交互例子识别“举手”动作。我们可以通过比较左右手腕与肩膀的Y轴坐标来判断。// 在estimatePose函数中检测到姿态后添加逻辑判断 poses.forEach(pose { drawKeypoints(...); // 原有绘制代码 drawSkeleton(...); // 原有绘制代码 // 1. 获取关键点索引根据PoseNet模型定义 const KEYPOINTS pose.keypoints; const leftWrist KEYPOINTS[9]; // 左手腕索引 const rightWrist KEYPOINTS[10]; // 右手腕索引 const leftShoulder KEYPOINTS[5]; const rightShoulder KEYPOINTS[6]; // 2. 定义动作判断函数 function isHandRaised(wrist, shoulder, threshold 30) { if (wrist.score 0.5 || shoulder.score 0.5) return false; // 置信度太低忽略 return wrist.position.y (shoulder.position.y - threshold); // 手腕Y坐标小于肩膀Y坐标减去阈值 } // 3. 判断并触发事件 if (isHandRaised(leftWrist, leftShoulder)) { console.log(检测到左手举起); // 触发自定义事件例如改变页面背景色、发送控制指令等 document.body.style.backgroundColor lightblue; triggerAction(LEFT_HAND_RAISED); } if (isHandRaised(rightWrist, rightShoulder)) { console.log(检测到右手举起); document.body.style.backgroundColor lightcoral; triggerAction(RIGHT_HAND_RAISED); } }); function triggerAction(action) { // 这里可以实现具体的交互逻辑 switch(action) { case LEFT_HAND_RAISED: // 例如控制幻灯片翻页、调节音量、打开灯光... break; case RIGHT_HAND_RAISED: // 另一个动作 break; // ... 更多动作 } }这只是最简单的示例。更复杂的交互可以包括姿态分类计算关键点之间的角度、距离比例使用简单的逻辑或机器学习分类器如KNN来识别“深蹲”、“开合跳”、“太极拳起手式”等。手势识别追踪手部关键点手腕、食指、拇指的运动轨迹识别画圈、滑动、点击等手势。多人交互利用maxDetections检测多人并为每个人分配ID实现多人游戏或协作应用。5.2 系统优化与进阶思考要让这个系统更健壮、更实用还需要考虑以下几个方面延迟优化链条采集端确保树莓派摄像头曝光模式固定避免自动调整带来的延迟波动。在rpi-webrtc-streamer配置中尝试tuningfast等编码参数。传输端如前所述有线网络是必须。在路由器上为树莓派设置静态IP和可能的QoS服务质量优先规则。处理端浏览器中确保Canvas绘制操作高效。可以尝试使用OffscreenCanvas在Web Worker中进行绘制避免阻塞主线程。稳定性提升WebRTC重连机制网络不稳定时需要在peerConnection.onconnectionstatechange或oniceconnectionstatechange事件中监听连接状态实现自动重连。模型热更新PoseNet模型加载较慢。可以考虑使用localStorage或IndexedDB缓存模型文件第二次加载时从本地读取。降级策略当客户端性能不足时自动降低inputResolution或估计频率保证基础功能可用。从原型到产品封装与部署将前端代码HTML, JS, CSS部署到一个简单的HTTP服务器如树莓派上的Nginx并设置开机自启动rpi-webrtc-streamer服务。安全考虑如果需要在公网访问必须启用SSLHTTPS并为rpi-webrtc-streamer配置TLS证书。同时考虑添加简单的身份验证。与后端通信识别出的动作可以通过WebSocket或HTTP API发送到后端服务器可以是树莓派上的另一个服务也可以是云端服务器从而控制物联网设备、记录数据或触发更复杂的业务流程。这个项目就像搭积木核心的三块积木视频采集、低延迟传输、浏览器AI已经稳稳当当地拼好了。剩下的就是发挥你的想象力用姿态数据这根“线”去操控属于你的数字世界。无论是做一个体感互动的数字艺术墙还是一个纠正姿势的健身小助手技术的大门已经敞开。我在实际调试中发现最大的成就感往往来自于看到一个简单的坐标比较最终演变成屏幕上生动反馈的那一刻。本文还有配套的精品资源点击获取
返回列表