当前位置: 首页 > news >正文

3dmax的python通过普通的摄像头动捕表情

1、安装python
进入cdm,打python要能显示版本号
>>>(进入python提示符模式)
import sys
sys.path显示python的安装路径,
进入到python.exe的路径
在python目录中安装(ctrl+z退出python交互模式)
2、pip install mediapipe    mediapipe 官网 

用阿里云镜像     mediapipe的github托管

pip install mediapipe -i https://mirrors.aliyun.com/pypi/simple/

3、pip install opencv -python

pip install opencv-python -i https://mirrors.aliyun.com/pypi/simple/

opencv官方网站 (有关摄像头动捕关键点说明)

进入到python.exe的路径,新建 FaceCapture.py

import cv2
import mediapipe as mp
import socket
import json
import time

# 初始化 mediapipe
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(
    static_image_mode=False,
    max_num_faces=1,
    refine_landmarks=True,
    min_detection_confidence=0.8,  # 增加检测置信度
    min_tracking_confidence=0.8  # 增加检测置信度
)

# 切换摄像头请切换设备索引
device_index = 0
cap = cv2.VideoCapture(device_index, cv2.CAP_DSHOW)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
target_addr = ('127.0.0.1', 5005)

total_duration = 15  # 总运行时间,单位:秒
start_time = time.time()
frame_count = 0
prev_time = 0

# 定义需要的关键点索引
# 眉毛
left_eyebrow = [70, 74, 78, 336]
right_eyebrow = [300, 304, 308, 105]
# 眼睛
left_eye = [36, 70, 105, 133]
right_eye = [267, 301, 336, 362]
# 嘴巴
mouth = [61, 146, 178, 291]
# 鼻翼
left_nostril = [129]
right_nostril = [358]
# 下巴
chin = [152]
# 眼角
left_inner_corner = [133]
left_outer_corner = [33]
right_inner_corner = [362]
right_outer_corner = [263]
# 嘴角
left_mouth_corner = [61]
right_mouth_corner = [291]

# 合并所有需要的关键点索引
selected_indices = left_eyebrow + right_eyebrow + left_eye + right_eye + mouth + left_nostril + right_nostril + chin + left_inner_corner + left_outer_corner + right_inner_corner + right_outer_corner + left_mouth_corner + right_mouth_corner

if not cap.isOpened():
    print("无法打开摄像头")
else:
    try:
        while True:
            elapsed = time.time() - start_time  # 提前计算运行时间
            remaining = total_duration - elapsed
            try:
                ret, frame = cap.read()
                frame_count += 1
                print(f"正在读取第 {frame_count} 帧,状态: {ret},程序将在 {remaining:.2f} 秒后自动关闭")
                if remaining <= 0:
                    print("运行时间已到,自动退出")
                    break
            except Exception as e:
                print("读取视频帧异常:", e)
                continue

            if not ret:
                print("无法获取摄像头数据,帧号:", frame_count)
                break

            current_time = time.time()
            fps = 1 / (current_time - prev_time)
            prev_time = current_time

            rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            result = face_mesh.process(rgb_frame)
            data_to_send = {}

            if result.multi_face_landmarks:
                landmarks = result.multi_face_landmarks[0].landmark
                keypoints = [{"id": i, "x": landmarks[i].x, "y": landmarks[i].y, "z": landmarks[i].z} for i in selected_indices]
                data_to_send['keypoints'] = keypoints
                # 绘制跟踪点
                height, width, _ = frame.shape
                for keypoint in keypoints:
                    x = int(keypoint["x"] * width)
                    y = int(keypoint["y"] * height)
                    cv2.circle(frame, (x, y), 2, (0, 255, 0), -1)
            else:
                data_to_send['keypoints'] = []

            data_to_send['fps'] = int(fps)

            json_data = json.dumps(data_to_send)
            # 实时驱动
            sock.sendto(json_data.encode('utf-8'), target_addr)
            # 离线驱动
            # with open(f"frames/frame_{frame_count:04d}.json", "w") as f:
            #    json.dump(data_to_send, f)

            # 文字提示,添加 fps 信息
            countdown_text = f"remainTime: {remaining:.1f} second, FPS: {int(fps)}"
            cv2.putText(frame, countdown_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1,
                        (0, 255, 0), 2, cv2.LINE_AA)

            # 进度条提示
            bar_x, bar_y = 10, 60
            bar_width = 300
            bar_height = 20
            progress = remaining / total_duration
            cv2.rectangle(frame, (bar_x, bar_y), (bar_x + bar_width, bar_y + bar_height), (180, 180, 180), 2)
            cv2.rectangle(frame, (bar_x, bar_y), (bar_x + int(bar_width * progress), bar_y + bar_height), (0, 255, 0), -1)

            cv2.imshow('Face Capture', frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                print("用户手动退出")
                break

            # 自动退出机制(30 秒)
            if time.time() - start_time > total_duration:
                message = "已运行 {} 秒,自动退出".format(total_duration)
                print(message)
                break

    finally:
        # 发送关闭信息
        close_message = {'type': 'close'}
        json_close_message = json.dumps(close_message)
        sock.sendto(json_close_message.encode('utf-8'), target_addr)

        cap.release()
        sock.close()
        cv2.destroyAllWindows()

python安装目录,进去后cmd命令提示符,然后 python   FaceCapture.py

 遇到 ImportError: DLL load failed while importing _framework_bindings: 动态链接库(DLL)初始化例程失败。

最新受支持的 Visual C++ 可再发行程序包下载 | Microsoft Learn

进入到python.exe的路径,新建 StartCam.bat 文件

@echo off
python FaceCapture.py
pause

进入到python.exe的路径,新建 启动摄像头.vbs 文件,这样就可以隐藏掉cmd命令行的界面只显示摄像头界面

Set objShell = CreateObject("WScript.Shell")
Dim strPath, strBatFile
strPath = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
strBatFile = strPath & "\StartCam.bat"
objShell.Run strBatFile, 0, False

新建一个max的ms文件GetUDP.ms ,这个可以创建十个dmmy物体,用来接受摄像头的表情捕捉数据,

--引入必要的 .NET类
dotNet.loadAssembly "System.Threading"
dotNet.loadAssembly "System.Net"
dotNet.loadAssembly "System.Net.Sockets"
dotNet.loadAssembly "System.Text"
dotNet.loadAssembly "Newtonsoft.Json"
-- dotNet.loadAssembly @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Threading.dll"

--清理之前的资源
try (if isProperty udpClient "Close" do (udpClient.Close())) catch ()
try (if isProperty thread "Abort" do (thread.Abort())) catch ()

--初始化UDP接收器
global localEndpoint = dotNetObject "System.Net.IPEndPoint" (dotNetClass "System.Net.IPAddress").Any  5005
global udpClient = dotNetObject "System.Net.Sockets.UdpClient"
udpClient.ExclusiveAddressUse = false 
udpClient.Client.SetSocketOption (dotNetClass "System.Net.Sockets.SocketOptionLevel").Socket (dotNetClass "System.Net.Sockets.SocketOptionName").ReuseAddress true
udpClient.Client.Bind localEndpoint
--定义定时器	
global delayTimer = dotnetobject "Windows.Forms.Timer"	
-- 定义后台线程
global BgThread = dotNetObject "System.ComponentModel.BackgroundWorker"
BgThread.WorkerSupportsCancellation = true

--重置场景
resetMaxFile #noPrompt

-- 创建 10 个 Dummy 物体并命名为 Dummy001, Dummy002, ..., Dummy010
global dummyArray = for i = 1 to 10 collect (
    local mydummy = dummy()  -- 创建 Dummy 物体
    mydummy.name = "Dummy" + formattedPrint i format:"03d"  -- 命名为 Dummy001, Dummy002, ...
    mydummy.position = [i * 50, 0, 0]  -- 设置一个简单的初始位置,您可以根据需要调整
    mydummy  -- 返回创建的 Dummy 物体
)

-- 接收 UDP 数据并解析为 JSON 结构体的函数
fn receiveAndParseJson =
(
    local remoteEndpoint = dotNetObject "System.Net.IPEndPoint" (dotNetClass "System.Net.IPAddress").Any 0
    local receiveBytes = udpClient.Receive remoteEndpoint
    local jsonString = (dotNetClass "System.Text.Encoding").UTF8.GetString receiveBytes
    
    try (
        -- 引用 System.Web.Extensions(包含 JSON 解析器)
        dotNet.loadAssembly "System.Web.Extensions"
        -- 创建内建 JSON 解析器
        jsonParser = dotNetObject "System.Web.Script.Serialization.JavaScriptSerializer"
        -- 反序列化 JSON 字符串为 MaxScript 可用的结构体(Hashtable/Array等)
        jsonStruct = jsonParser.DeserializeObject jsonString
        return jsonStruct
    )
    catch (
        print("解析 JSON 时出错:" + getCurrentException())
        return undefined
    )
)

-- 处理关键点数据并更新 Dummy 位置的函数
fn processKeypointsData keypoints =
(
    if keypoints != undefined do
    (
        for id = 0 to 9 do (
			for pt in keypoints do (
				if pt.Item["id"] == id then (
					local x = pt.Item["x"] * 100
					local y = pt.Item["y"] * 100
					local z = pt.Item["z"] * 100
					--dotNetClass "System.Windows.Forms.Control".Invoke (dotNetDelegate updateDummyPosition id x y z)
                    local mydummy = dummyArray[id+1]
					if isValidNode mydummy do (
						mydummy.position = [pt.Item["x"]*100, pt.Item["y"]*100, pt.Item["z"]*100] 
					
					)
				)
			)
        print("Dummies 位置更新完成!")
		)
	)
)

-- 定时器触发时执行的函数
fn timerCallback sender e =
(
 if not BgThread.CancellationPending do
	(
		local jsonStruct = receiveAndParseJson()
		format "json结构体为:% \n" jsonStruct
		if jsonStruct != undefined do
		(
			-- 获取帧率
			local fps = jsonStruct.Item["fps"]
			if fps != undefined do
			(
				-- 根据帧率计算定时器间隔(毫秒)
				local interval = 1000 / fps
				delayTimer.Interval = interval
			)
			-- 处理关键点数据
			local keypoints = jsonStruct.Item["keypoints"]
			processKeypointsData keypoints
			
			-- 检查是否接收到关闭信息,则关闭后台线程
			if jsonStruct.Item["type"] == "close" do
			(
				BgThread.CancelAsync()
				return true
			)
		)
		sleep 0.1
	)
)

--主执行命令
if (timerCallback sender e )then(
	delayTimer.enabled = true
	-- 添加定时器事件处理程序
	dotnet.AddEventHandler delayTimer "Tick" (timerCallback sender e)
	-- 添加后台线程事件处理程序
	dotnet.AddEventHandler BgThread "DoWork" (fn sender e = timerCallback sender e)
	-- 监听键盘事件,设置取消标志
	if keyboard.escPressed do (
		BgThread.CancelAsync()
		print "已发送取消请求"
	)
)
else(	
	delayTimer.enabled = false
	udpClient.Close()
	BgThread.CancelAsync()
)


启动启动摄像头.vbs,出现摄像头窗口,和倒计时进度条,30秒后自动关闭,你可以设定的不关闭。

启动GetUDP.ms,接收动捕数据,传递到做表情的dmmy物体上面
 

相关文章:

  • 健康与好身体笔记
  • 项目学习总结001
  • 《算法笔记》3.3小节——入门模拟->图形输出
  • Android学习总结之OKHttp拦截器和缓存
  • 【leetcode hot 100 152】乘积最大子数组
  • OpenCV图像形态学详解
  • 树莓派4B配置wifi热点,可访问http协议
  • 不再卡顿!如何根据使用需求挑选合适的电脑内存?
  • ViewModel vs AndroidViewModel:核心区别与使用场景详解
  • 云服务器10M带宽实际速度能达到多少?
  • 大唐杯省赛安排来了!还有7天,该如何准备?
  • BERT、T5、ViT 和 GPT-3 架构概述及代表性应用
  • 《从零搭建Vue3项目实战》(AI辅助搭建Vue3+ElemntPlus后台管理项目)零基础入门系列第十篇:商品管理功能实现
  • MOS管的发热原因和解决办法
  • TGRS 2024 | 基于光谱相关的高光谱图像超分辨率融合网络
  • 开源Cursor替代品——Void
  • 二维偏序-蓝桥20102,没写完
  • 996引擎-源码学习:PureMVC Lua 中的 Facade 类
  • 【状态适配器模式:级联选择器多状态数据处理完整解决方案】
  • layui中transfer两个table展示不同的数据列
  • 如何做网站预览/桂林seo排名
  • 手把手教你如何建立自己的网站/网站展示型推广
  • 海山网站建设/青岛seo杭州厂商
  • 政府门户网站建设的必要性/站长综合查询工具
  • 淘宝建设网站的理由/百度app官方下载安装到手机
  • 国家网站建设/网址大全名称