import cv2
import math
import numpy as np
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier

neighbors = 2  # 邻居

# 加载动作数据集
warmup_df = pd.read_csv('dataset_warm-up.csv')
combat_df = pd.read_csv('dataset_SHIZHAN POSE.csv')
attack_df = pd.read_csv('dataset_hit.csv')
respect_df = pd.read_csv('dataset_respect.csv')
gongbu_df = pd.read_csv('dataset_gongbu.csv')

# 数据清洗
# 将每个小数据集中偏离平均值超过2倍标准差的样本删除
print('数据清洗')
for df in [warmup_df, combat_df, attack_df, respect_df, gongbu_df]:
    df.drop(df[(np.abs(df[['angle1', 'angle2', 'angle3', 'angle4', 'angle5', 'angle5_1', 'angle6', 'angle7', 'angle8', 'angle9', 'angle10', 'angle11']] - df[['angle1', 'angle2', 'angle3', 'angle4', 'angle5', 'angle5_1', 'angle6', 'angle7', 'angle8', 'angle9', 'angle10', 'angle11']].mean()) > 2 * df[['angle1', 'angle2', 'angle3', 'angle4', 'angle5', 'angle6', 'angle7', 'angle8', 'angle9', 'angle10', 'angle11']].std()).any(axis=1)].index, inplace=True)

# 将数据集合并为一个大的数据集
data = pd.concat([warmup_df, combat_df, attack_df, respect_df, gongbu_df], ignore_index=True)

# 训练KNN分类器
print('开始训练knn')
knn = KNeighborsClassifier(n_neighbors=neighbors, weights='distance', metric='manhattan')
knn.fit(data[['angle1', 'angle2', 'angle3', 'angle4', 'angle5', 'angle5_1', 'angle6', 'angle7', 'angle8', 'angle9', 'angle10', 'angle11']], data['label'])

# 加载测试视频
cap = cv2.VideoCapture('test.mp4')
# 定义字典,用于将数字标签转换为动作名称
actions = {0: 'warm-up', 1: 'combat', 2: 'attack', 3: 'respect', 4: 'gongbu'}
# 定义字典,用于将动作名称转换为颜色
colors = {'warm-up': (0, 255, 0), 'combat': (255, 0, 0), 'attack': (0, 0, 255), 'respect': (255, 255, 0), 'gongbu': (0, 255, 255)}

# 定义函数,用于绘制骨架
def draw_skeleton(frame, angles, color):
    # 定义骨架关键点的坐标
    points = [(100, 100),
              (100, 50),
              (100, 0),
              (75, 75),
              (50, 50),
              (25, 25),
              (25, 75),
              (0, 50),
              (100, 125),
              (75, 125),
              (50, 125),
              (25, 125)]
    # 定义骨架关键点的连接方式
    connections = [(0, 1),
                   (1, 2),
                   (1, 3),
                   (3, 4),
                   (4, 5),
                   (3, 6),
                   (6, 7),
                   (1, 8),
                   (8, 9),
                   (9, 10),
                   (10, 11)]
    # 绘制骨架
    for connection in connections:
        start_point = points[connection[0]]
        end_point = points[connection[1]]
        cv2.line(frame, start_point, end_point, color, 2)
    # 绘制关键点
    for i, angle in enumerate(angles):
        x = int(points[i][0] + 25 * math.cos(math.radians(angle)))
        y = int(points[i][1] + 25 * math.sin(math.radians(angle)))
        cv2.circle(frame, (x, y), 3, color, -1)

# 定义函数,用于预处理帧图像
def preprocess(frame):
    # 将图像转换为灰度图像
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # 使用高斯滤波去除噪声
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    # 使用Canny边缘检测算法检测边缘
    edges = cv2.Canny(blur, 50, 150)
    # 使用膨胀操作填充边缘
    kernel = np.ones((5, 5), np.uint8)
    dilation = cv2.dilate(edges, kernel, iterations=1)
    # 返回处理后的图像
    return dilation

# 定义函数,用于从帧图像中提取角度特征
def extract_angles(frame, points):
    angles = []
    for i, connection in enumerate([(0, 1), (1, 2), (1, 3), (3, 4), (4, 5), (3, 6), (6, 7), (1, 8), (8, 9), (9, 10), (10, 11)]):
        start_point = points[connection[0]]
        end_point = points[connection[1]]
        dx = end_point[0] - start_point[0]
        dy = end_point[1] - start_point[1]
        angle = math.degrees(math.atan2(dy, dx))
        angles.append(angle)
    return angles

# 定义函数,用于将预测结果可视化
def visualize_prediction(frame, label):
    # 获取动作名称和颜色
    action = actions[label]
    color = colors[action]
    # 在帧图像上绘制动作名称和颜色
    cv2.putText(frame, action, (20, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

# 处理视频帧
while True:
    # 读取视频帧
    ret, frame = cap.read()
    if not ret:
        break
    # 预处理帧图像
    processed = preprocess(frame)
    # 使用OpenCV的findContours函数查找轮廓
    contours, _ = cv2.findContours(processed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 如果没有找到轮廓,则跳过该帧
    if len(contours) == 0:
        continue
    # 找到最大的轮廓
    contour = max(contours, key=cv2.contourArea)
    # 使用OpenCV的convexHull函数计算凸包
    hull = cv2.convexHull(contour)
    # 使用OpenCV的approxPolyDP函数近似凸包
    approx = cv2.approxPolyDP(hull, 0.001 * cv2.arcLength(hull, True), True)
    # 如果近似凸包的顶点数不足12个,则跳过该帧
    if len(approx) < 12:
        continue
    # 将顶点按照x坐标排序
    approx = sorted(approx, key=lambda x: x[0][0])
    # 提取关键点坐标
    points = [(approx[0][0][0], approx[0][0][1]),
              (approx[1][0][0], approx[1][0][1]),
              (approx[2][0][0], approx[2][0][1]),
              (approx[3][0][0], approx[3][0][1]),
              (approx[4][0][0], approx[4][0][1]),
              (approx[5][0][0], approx[5][0][1]),
              (approx[6][0][0], approx[6][0][1]),
              (approx[7][0][0], approx[7][0][1]),
              (approx[8][0][0], approx[8][0][1]),
              (approx[9][0][0], approx[9][0][1]),
              (approx[10][0][0], approx[10][0][1]),
              (approx[11][0][0], approx[11][0][1])]
    # 提取角度特征
    angles = extract_angles(frame, points)
    # 预测动作
    label = knn.predict([angles])[0]
    # 可视化预测结果
    visualize_prediction(frame, label)
    # 绘制骨架
    draw_skeleton(frame, angles, colors[actions[label]])
    # 显示帧图像
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) == ord('q'):
        break
# 释放视频捕获对象和窗口
cap.release()
cv2.destroyAllWindows()

原文地址: https://www.cveoy.top/t/topic/gQ1e 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录