import eventlet
eventlet.monkey_patch()
from eventlet import wsgi
import time
from multiprocessing import Process
import mediapipe as mp
import numpy as np
from flask import Flask, render_template
from flask_socketio import SocketIO, Namespace
import cv2
import base64
from threading import Lock
import redis
r = redis.Redis(host='localhost', port=6379)
frame_lock = Lock()
current_time = 0
last_frame_time = 0
frame_interval = 1 / 30 # 30FPS对应的间隔
# 优化后的初始化配置(平衡精度与性能)
mp_pose = mp.solutions.pose
pose = mp_pose.Pose(
static_image_mode=False, # 视频流模式
model_complexity=1, # 改用中等复杂度模型(0-2范围)
smooth_landmarks=True,
enable_segmentation=False, # 关闭不必要的分割掩码
min_detection_confidence=0.7, # 提高检测阈值减少误判
min_tracking_confidence=0.3 # 降低跟踪阈值保持连续性
)
mp_drawing = mp.solutions.drawing_utils
class Channel2(Namespace):
def __init__(self, namespace):
super().__init__(namespace)
self.pubsub = r.pubsub()
self.pubsub.subscribe('frame_channel')
self.running = True
self.thread = None
def calculate_angle(self, a, b, c):
#"""计算三个关节点构成的夹角(单位:度)"""
a = np.array(a) # 起点
b = np.array(b) # 顶点
c = np.array(c) # 终点
ba = a - b
bc = c - b
cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle = np.degrees(np.arccos(cosine_angle))
return angle
def is_landmark_visible(self, landmark, threshold=0.5):
return hasattr(landmark, 'visibility') and landmark.visibility > threshold
def process_image(self, imgRGB, img):
global last_frame_time, current_time
if imgRGB is not None and img is not None:
results = pose.process(imgRGB)
if results.pose_landmarks:
mp_drawing.draw_landmarks(img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 80]
ret, buffer = cv2.imencode('.jpg', img, encode_param)
b64_frame = base64.b64encode(buffer).decode('utf-8')
last_frame_time = current_time
return b64_frame
else:
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 80]
ret, buffer = cv2.imencode('.jpg', img, encode_param)
b64_frame = base64.b64encode(buffer).decode('utf-8')
last_frame_time = current_time
return b64_frame
def getImgs(self, data):
# 处理原始帧
img_np = np.frombuffer(data, dtype=np.uint8)
img = cv2.imdecode(img_np, cv2.IMREAD_COLOR)
imgRGB = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
outputs = self.process_image(imgRGB, img)
self.emit('server_callback', {
'type': 'processed',
'frame': f'data:image/jpeg;base64,{outputs}'
}, namespace='/processor', callback=lambda status: print(f"Client received: {status}"))
def on_connect(self, auth):
print('通道2连接建立')
print(auth, '=====')
def listener():
while self.running:
message = self.pubsub.get_message()
if message and message['type'] == 'message':
self.getImgs(message['data'])
eventlet.sleep(0.001)
listener()
def on_disconnect(self):
print('通道2连接关闭')
self.running = False
if self.thread:
self.thread.kill()
def create_app(port):
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins='*', async_mode='eventlet', ping_interval=5000)
@app.route('/')
def index():
return render_template('rtc2.html')
return app, socketio
class Channel1(Namespace):
def on_connect(self):
print("通道1连接建立")
def passImg(self, data):
global last_frame_time, frame_interval, current_time
current_time = time.time()
# 帧率控制
if current_time - last_frame_time < frame_interval:
print('/////////////')
return
else:
with frame_lock:
r.publish('frame_channel', data)
last_frame_time = current_time
def on_frame_exchange(self, data):
self.passImg(data)
def on_disconnect(self):
print('通道1连接关闭')
def run_primary():
app, socketio = create_app(5001)
socketio.on_namespace(Channel1('/upload'))
socketio.run(app, port=5001, debug=True)
def run_secondary():
app, socketio = create_app(5002)
socketio.on_namespace(Channel2('/processor'))
socketio.run(app, port=5002, debug=True)
if __name__ == '__main__':
Process(target=run_primary).start()
Process(target=run_secondary).start()