基于mediapipe的动作捕捉和Unity的球棍模型同步

article/2025/10/22 20:36:55

基于mediapipe的动作捕捉和Unity的球棍模型同步

  • 所需环境
  • python端
  • unity端
  • 效果

所需环境

这是我所使用的环境
python3.9 安装mediapipe和opencv-python包
python和Unity通信使用socket
Unity2021.3

python端

如何安装那两个包我就不说了,大家有不明白可以去百度
mediapipe和opencv-python

1.把我们要使用的mediapipe的功能封装成一个module
这个module返回一个列表,列表中存放mediapipe识别到的特征点

import cv2
import mediapipe as mp
import timeclass poseDetector():def __init__(self, mode=False, upBody=False, smooth=True, detectionCon=0.5, trackCon=0.5):self.mode = modeself.upBody = upBodyself.smooth = smoothself.detectionCon = detectionConself.trackCon = trackConself.mpDraw = mp.solutions.drawing_utilsself.mpPose = mp.solutions.poseself.pose = self.mpPose.Pose(self.mode, self.upBody, self.smooth, False, True, # 这里的False 和True为默认self.detectionCon, self.trackCon)  # pose对象 1、是否检测静态图片,2、姿态模型的复杂度,3、结果看起来平滑(用于video有效),4、是否分割,5、减少抖动,6、检测阈值,7、跟踪阈值'''STATIC_IMAGE_MODE:如果设置为 false,该解决方案会将输入图像视为视频流。它将尝试在第一张图像中检测最突出的人,并在成功检测后进一步定位姿势地标。在随后的图像中,它只是简单地跟踪那些地标,而不会调用另一个检测,直到它失去跟踪,以减少计算和延迟。如果设置为 true,则人员检测会运行每个输入图像,非常适合处理一批静态的、可能不相关的图像。默认为false。MODEL_COMPLEXITY:姿势地标模型的复杂度:0、1 或 2。地标准确度和推理延迟通常随着模型复杂度的增加而增加。默认为 1。SMOOTH_LANDMARKS:如果设置为true,解决方案过滤不同的输入图像上的姿势地标以减少抖动,但如果static_image_mode也设置为true则忽略。默认为true。UPPER_BODY_ONLY:是要追踪33个地标的全部姿势地标还是只有25个上半身的姿势地标。ENABLE_SEGMENTATION:如果设置为 true,除了姿势地标之外,该解决方案还会生成分割掩码。默认为false。SMOOTH_SEGMENTATION:如果设置为true,解决方案过滤不同的输入图像上的分割掩码以减少抖动,但如果 enable_segmentation设置为false或者static_image_mode设置为true则忽略。默认为true。MIN_DETECTION_CONFIDENCE:来自人员检测模型的最小置信值 ([0.0, 1.0]),用于将检测视为成功。默认为 0.5。MIN_TRACKING_CONFIDENCE:来自地标跟踪模型的最小置信值 ([0.0, 1.0]),用于将被视为成功跟踪的姿势地标,否则将在下一个输入图像上自动调用人物检测。将其设置为更高的值可以提高解决方案的稳健性,但代价是更高的延迟。如果 static_image_mode 为 true,则忽略,人员检测在每个图像上运行。默认为 0.5。'''def findPose(self, img, draw=True):imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 将BGR格式转换成灰度图片self.results = self.pose.process(imgRGB)  # 处理 RGB 图像并返回检测到的最突出人物的姿势特征点。if self.results.pose_landmarks:if draw:self.mpDraw.draw_landmarks(img, self.results.pose_landmarks, self.mpPose.POSE_CONNECTIONS)# results.pose_landmarks画点 mpPose.POSE_CONNECTIONS连线return imgdef findPosition(self, img, draw = True):#print(results.pose_landmarks)lmList = []if self.results.pose_landmarks:for id, lm in enumerate(self.results.pose_landmarks.landmark):  # enumerate()函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标h, w, c = img.shape  # 返回图片的(高,宽,位深)cx, cy, cz = int(lm.x * w), int(lm.y * h), int(lm.z * w)  # lm.x  lm.y是比例  乘上总长度就是像素点位置lmList.append([id, cx, cy, cz])if draw:cv2.circle(img, (cx, cy), 5, (255, 0, 0), cv2.FILLED)  # 画蓝色圆圈return lmListdef main():# cap = cv2.VideoCapture(0)  # 调用电脑摄像头# cap = cv2.VideoCapture('video/2.mp4')  # 视频# cap = cv2.VideoCapture('video/3.png')cap = cv2.VideoCapture('video/ASOUL.mp4')pTime = 0detector = poseDetector()while True:success, img = cap.read()  # 第一个参数代表有没有读取到图片True/False 第二个参数frame表示截取到一帧的图片  读进来直接是BGR 格式数据格式img = detector.findPose(img)lmList = detector.findPosition(img)if len(lmList) != 0:print(lmList)  # print(lmList[n]) 可以打印第n个# 计算帧率cTime = time.time()fps = 1 / (cTime - pTime)pTime = cTimecv2.putText(img, str(int(fps)), (70, 50), cv2.FONT_HERSHEY_PLAIN, 3,(255, 0, 0), 3)  # 图片上添加文字  参数:图片 要添加的文字 文字添加到图片上的位置 字体的类型 字体大小 字体颜色 字体粗细cv2.imshow("Image", img)  # 显示图片cv2.waitKey(3)  # 等待按键if __name__ == "__main__":main()

2.把一帧图像的33个特征点的信息变成一个字符串,以 “,”隔开
通过socket构建一个客户端client,把包含特征点信息的字符串发送到unity的服务端


import cv2
import time
import PoseModule as pm
import socketpTime = 0def computeFPS():global  pTimecTime = time.time()fps = 1 / (cTime - pTime)pTime = cTimecv2.putText(img, str(int(fps)), (70, 50), cv2.FONT_HERSHEY_PLAIN, 3,(255, 0, 0), 3)  # 图片上添加文字  参数:图片 要添加的文字 文字添加到图片上的位置 字体的类型 字体大小 字体颜色 字体粗细# cap = cv2.VideoCapture(0)  # 调用电脑摄像头
cap = cv2.VideoCapture('video/2.mp4')  # 视频# 构建一个实例,去连接服务端的监听端口。
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 1234))
#  msg=client.recv(1024)
#  print('New message from server: %s' % msg.decode('utf-8'))detector = pm.poseDetector()
strdata = ""  # 定义字符串变量
while True:success, img = cap.read()  # 第一个参数代表有没有读取到图片True/False 第二个参数frame表示截取到一帧的图片  读进来直接是BGR 格式数据格式img = detector.findPose(img)lmList = detector.findPosition(img)# if len(lmList) != 0:#     print(lmList)if len(lmList) != 0:for data in lmList:print(data)  # print(lmList[n]) 可以打印第n个for i in range(1, 4):if i == 2:strdata = strdata + str(img.shape[0] - data[i]) + ','else:strdata = strdata + str(data[i]) + ','print(strdata)client.send(strdata.encode('utf-8'))strdata = ""computeFPS()  # 计算帧率cv2.imshow("Image", img)  # 显示图片cv2.waitKey(10)  # 等待按键

unity端

1.在场景中构建出人的球棍模型,不需要在意他们的位置,通过代码给他们赋值,场景中的层级结构如图
在这里插入图片描述

在这里插入图片描述
场景中33个红色的球表示特征点,绿色的线表示骨架
在这里插入图片描述
具体需要多少骨架可以自己决定,我没有弄头上的
2.通过socket创建一个服务端(server),接收python客户端传来的特征点坐标数据,赋值给unity场景中的特征点

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;public class Server : MonoBehaviour
{//public GameObject leftshoulder;public GameObject[] Body;private static int myProt = 9999;   //端口  static Socket serverSocket;Thread myThread;string str;Dictionary<string, Thread> threadDic = new Dictionary<string, Thread>();//存储线程,程序结束后关闭线程private void Start(){//服务器IP地址  ,127.0.0.1 为本机IP地址IPAddress ip = IPAddress.Parse("127.0.0.1");//IPAddress ip = IPAddress.Any; //本机地址Debug.Log(ip.ToString());serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);IPEndPoint iPEndPoint = new IPEndPoint(ip, myProt);//serverSocket.Bind(new IPEndPoint(ip, myProt));  //绑定IP地址:端口  serverSocket.Bind(iPEndPoint);  //绑定IP地址:端口  serverSocket.Listen(10);    //最多10个连接请求  //Console.WriteLine("creat service {0} success",//    serverSocket.LocalEndPoint.ToString());myThread = new Thread(ListenClientConnect);myThread.Start();//Console.ReadLine();Debug.Log("服务器启动...........");}public void Update(){if (str != null){Debug.Log(str);//接受的数据string[] points = str.Split(',');Debug.Log(points.Length);for (int i = 0; i <= 32; i++){float x = float.Parse(points[0 + (i * 3)]) / 100;float y = float.Parse(points[1 + (i * 3)]) / 100;float z = float.Parse(points[2 + (i * 3)]) / 300;Body[i].transform.localPosition = new Vector3(x, y, z);}}}// 监听客户端是否连接  private void ListenClientConnect(){while (true){Socket clientSocket = serverSocket.Accept(); //1.创建一个Socket 接收客户端发来的请求信息 没有消息时堵塞clientSocket.Send(Encoding.ASCII.GetBytes("Server Say Hello")); //2.向客户端发送 连接成功 消息Thread receiveThread = new Thread(ReceiveMessage); //3.为已经连接的客户端创建一个线程 此线程用来处理客户端发送的消息receiveThread.Start(clientSocket); //4.开启线程//添加到字典中string clientIp = ((IPEndPoint)clientSocket.RemoteEndPoint).Address.ToString();//Debug.Log( clientSocket.LocalEndPoint.ToString()); //获取ip:端口号if (!threadDic.ContainsKey(clientIp)){threadDic.Add(clientIp, receiveThread);}}}private byte[] result = new byte[1024]; //1.存入的byte值 最大数量1024//开启线程接收数据 (将Socket作为值传入)private void ReceiveMessage(object clientSocket){Socket myClientSocket = (Socket)clientSocket; //2.转换传入的客户端Socketwhile (true){try{//接收数据  int receiveNumber = myClientSocket.Receive(result); //3.将客户端得到的byte值写入//Debug.Log(receiveNumber);//子节数量if (receiveNumber > 0){str = Encoding.UTF8.GetString(result, 0, receiveNumber);//将接受的数据存到str变量中// Debug.Log(str);}else{Debug.Log("client: " + ((IPEndPoint)myClientSocket.RemoteEndPoint).Address.ToString() + "断开连接");threadDic[((IPEndPoint)myClientSocket.RemoteEndPoint).Address.ToString()].Abort(); //清除线程}}catch (Exception ex){//myClientSocket.Shutdown(SocketShutdown.Both); //出现错误 关闭SocketDebug.Log(" 错误信息" + ex); //打印错误信息break;}}}void OnApplicationQuit(){//结束线程必须关闭 否则下次开启会出现错误 (如果出现的话 只能重启unity了)myThread.Abort();//关闭开启的线程foreach (string item in threadDic.Keys){Debug.Log(item);//de.Key对应于key/value键值对key//item.Value.GetType()threadDic[item].Abort();}}}

3.让骨架连接对应的特征点

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class linecode : MonoBehaviour
{LineRenderer lineRenderer;public Transform oringin;public Transform destination;// Start is called before the first frame updatevoid Start(){lineRenderer = GetComponent<LineRenderer>();lineRenderer.startWidth = 0.1f;lineRenderer.endWidth = 0.1f;}// Update is called once per framevoid Update(){lineRenderer.SetPosition(0, oringin.position);lineRenderer.SetPosition(1, destination.position);}
}

具体场景中的脚本挂载情况可以下载工程查看

效果

在这里插入图片描述
在这里插入图片描述

资源下载:
链接:https://pan.baidu.com/s/1XBBWV1wCxyW0FyRTOtorkw?pwd=sbyq
提取码:sbyq
参考:https://www.youtube.com/watch?v=BtMs0ysTdkM


http://chatgpt.dhexx.cn/article/KoEf0y7s.shtml

相关文章

unity 原型_使用Unity和React快速进行原型制作

unity 原型 Web applications are great way to quickly reach a lot of users without the hassle of native client installs and play store downloads. Web frameworks such as React allow page components to communicate and respond to user interaction much like tra…

使用 命令行/WinForm 来打包Unity可执行程序

使用 命令行/WinForm 来打包Unity可执行程序 前言一、编辑Editor打包工具1.编辑打包脚本2.Unity编辑器中样式 二、命令行调用Unity打包函数1.Unity命令行常用参数2.命令行调用静态打包函数 三、使用WinForm创建可视化操作界面1.可视化界面2.代码详细&#xff1a;①CmdHelper类&…

Unity + Jenkins自动打包 (二)构建Jenkins项目以及编写Python、Unity脚本

1、新建Jenkens项目 在上一篇中&#xff0c;完成了Jenkins的安装和初始化&#xff0c;以及权限设置。 查看上一篇&#xff1a;Jenkins安装 点此 现在打开浏览器&#xff0c;输入http://localhost:8081&#xff0c;当然&#xff0c;需要改成你自己设置的Jenkins端口号&#xff…

unity python服务器_Unity如何连接服务器: 一个简单的例子

Unity3D本身是用来做客户端的通用游戏引擎, 要建立网络连接的话, 其实需要使用的是C#本身的网络和线程模块, 即System.Net.Sockets & System.Threading. 本文中我做了一个简单的例子, 适合那些需要做Unity客户端连接服务器功能的人入门. 整体项目 客户端: 我做的项目主要是…

unity + python socket通信,自定义数据包

unity和python相互之间通过socket通信来发送自定义数据包是一个利用unity构建场景和通过python来做数据处理的方式&#xff0c;能够有效的利用两种不同语言的优势。 我已经将对应的操作封装为对应的一个模块&#xff0c;SocketTools.cs&#xff0c;我们先来看一下具体的代码用…

假设电话收费标准为: (1)国际长途1.00元/分钟,(2) 国内长途0.60元/分钟,(3)市话前3分钟0.20元,3分钟以后0.10元/分钟。现假设某话单文件中每条话单包含如下信息:通话日期(10

你好&#xff0c;帮我做个C语言题目 你好&#xff0c;我是Assistant。很高兴为您做题。 请提供题目的完整题面&#xff0c;并提供任何相关的输入、输出、约束条件等信息。 如果您有任何其他问题&#xff0c;请随时与我联系。我将竭诚为您服务。 897354667qq.com 假设电话收…

电商用户行为数据分析实战(MySQL +PowerBI)

目录 一、项目概况二、数据源三、数据清洗3.1 选择子集导入&#xff0c;匹配适合的数据类型3.2 列重命名3.3重复值处理3.4 缺失值处理3.5 异常值处理从timestamps字段中提取日期数据列查看日期列数据异常情况 四、数据分析4.1 整体购物情况&#xff0c;基于AARRR模型4.1.1 各字…

【业务数据分析】——十大常用数据分析方法

&#x1f935;‍♂️ 个人主页&#xff1a;Lingxw_w的个人主页 ✍&#x1f3fb;作者简介&#xff1a;计算机科学与技术研究生在读 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4a…

基于订单的数据分析

目录 项目背景 数据理解 指标维度 指标梳理 维度梳理 导入数据 数据预处理 数据格式整理 规范字段名 增加字段 简化地址 缺失值处理 异常值分析​ 重复值处理 数据分析 描述性统计 总体销售情况 周趋势、日趋势分析 产品价格分析 地区分析 转化率分析 总结…

大数据培训 | 电商用户行为分析之订单支付实时监控

在电商网站中&#xff0c;订单的支付作为直接与营销收入挂钩的一环&#xff0c;在业务流程中非常重要。对于订单而言&#xff0c;为了正确控制业务流程&#xff0c;也为了增加用户的支付意愿&#xff0c;网站一般会设置一个支付失效时间&#xff0c;超过一段时间不支付的订单就…

订单数据分析

订单背景 订单&#xff1a;对订单的预测不仅为了企业更好的制定物料采购计划、控制库存、提升生产效率、控制生产进度&#xff0c;还为了帮助企业更好的把控市场潜在需求&#xff0c;分析目前经营状态和未来发展趋势。 宽厚板材市场价格&#xff08;只能查询到近三个月的&…

关于订单功能的处理和分析

这两天看了一下RABC的权限管理处理&#xff0c;梳理了一下订单功能的表创建&#xff0c;界面&#xff0c;功能分析。 目录 RABC RBAC0模型 那么对于RABC模型我们怎么创建数据库表&#xff1f; 订单模块的梳理 RABC RABC说的是在用户和权限之间多一个角色&#xff0c;用户与…

订单数据分析-实战

1. 京东订单数据准备 1.1 京东订单数据介绍 2020年5月25日10%抽样数据大家电-家用电器-冰箱70K 1.2 数据清洗 缺失值处理 用户城市和省份信息有部分缺失&#xff0c;部分订单的订单中支付时间为空值数据逻辑错误格式内容一致性 import pandas as pd import numpy as np im…

话单数据完整流程

原始数据__解析_____>>>解析后的数据___入库____>>>汇总的数据 1.原始数据 上游中兴的原始数据&#xff0c;在远程桌面Winscp软件中查看。丢失了下游也没法补充采集。得等上游补充采集后下游才能解析。当原始数据存在&#xff0c;而话单数据显示红点&…

话单分析账单分析行踪分析三合一数据分析

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Office Tool Plus(安装visio)

说明&#xff1a;需要提前卸载原先的Office&#xff08;Word、PPT、Excel等&#xff09; 一、Office Tool Plus官网 https://otp.landian.vip/zh-cn/download.html 二、下载Office Tool Plus 百度网盘链接&#xff08;Office Tool Plus安装包&#xff09; 链接&#xff1a;…

FFmpeg音频解码-音频可视化

最近在做一个音频可视化的业务&#xff0c;网上有Java层的实现方法&#xff0c;但是业务需要用C实现&#xff0c;从原理出发其实很简单&#xff0c;先对音频进行解码&#xff0c;再计算分贝。这比把大象放进冰箱还简单。本文从音频可视化的业务为依托&#xff0c;以FFmpeg为基础…

基于FFmpeg的视频播放器之七:音频解码

一.流程 音频解码的流程和视频解码几乎一样,最大的区别是解码后需要进行重采样。因为解码出的AVSampleFormat格式是AV_SAMPLE_FMT_FLTP(float, planar),该格式无法直接使用SDL进行播放,需要转换成SDL支持的AV_SAMPLE_FMT_S16(signed 16 bits)格式。关于重采样,详见下篇…

2020手机音频解码芯片_2020杰理音频芯片全解析,14款音频产品代表作拆解汇总...

珠海市杰理科技股份有限公司,成立于2010年。杰理科技主要从事射频智能终端、多媒体智能终端等系统级芯片(SoC)的研究、开发和销售。 杰理科技的芯片产品主要应用于AI智能音箱、蓝牙音箱、蓝牙耳机、智能语音玩具等物联网智能终端产品,下游应用产品市场十分广泛和巨大。 杰理科…

音频编解码原理

实例说明 音频编解码常用的实现方案有三 种。 第一种就是采用专用的音频芯片对 语音信号进行采集和处理&#xff0c;音频编解码算法集成在硬件内部&#xff0c;如 MP3 编解码芯片、语音合成 分析芯片等。使用这种方案的优点就是处理速度块&#xff0c;设计周期短&#xff1b;缺…