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

# 定义计算角度的函数
def calculate_angle(a, b, c):
    a = np.array(a)  # First
    b = np.array(b)  # Mid
    c = np.array(c)  # End

    radians = np.arctan2(c[1] - b[1], c[0] - b[0]) - np.arctan2(a[1] - b[1], a[0] - b[0])
    angle = np.abs(radians * 180.0 / np.pi)

    if angle > 180.0:
        angle = 360 - angle

    return angle

# 设置KNN模型参数
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_video.mp4')
# 定义字体
font = cv2.FONT_HERSHEY_SIMPLEX
# 定义颜色
color = (0, 255, 0)
# 定义字体大小
fontScale = 1
# 定义线条粗细
thickness = 2

while(cap.isOpened()):
    # 读取视频帧
    ret, frame = cap.read()
    if ret == True:
        # 转换为灰度图像
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 检测人脸
        face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)
        # 检测到人脸
        if len(faces) > 0:
            # 取第一个人脸
            (x, y, w, h) = faces[0]
            # 裁剪人脸部分
            face = gray[y:y+h, x:x+w]
            # 缩放为统一大小
            face = cv2.resize(face, (200, 200))
            # 计算人脸关键点
            predictor_path = 'shape_predictor_68_face_landmarks.dat'
            predictor = dlib.shape_predictor(predictor_path)
            detector = dlib.get_frontal_face_detector()
            dets = detector(face, 1)
            for k, d in enumerate(dets):
                shape = predictor(face, d)
                # 将关键点转换为numpy数组
                landmarks = np.zeros((68, 2), dtype=int)
                for i in range(0, 68):
                    landmarks[i] = (shape.part(i).x, shape.part(i).y)
                # 计算角度
                angle1 = calculate_angle(landmarks[36], landmarks[39], landmarks[33])
                angle2 = calculate_angle(landmarks[42], landmarks[45], landmarks[33])
                angle3 = calculate_angle(landmarks[31], landmarks[37], landmarks[41])
                angle4 = calculate_angle(landmarks[35], landmarks[40], landmarks[34])
                angle5 = calculate_angle(landmarks[48], landmarks[54], landmarks[57])
                angle5_1 = calculate_angle(landmarks[51], landmarks[57], landmarks[54])
                angle6 = calculate_angle(landmarks[16], landmarks[0], landmarks[1])
                angle7 = calculate_angle(landmarks[2], landmarks[16], landmarks[0])
                angle8 = calculate_angle(landmarks[27], landmarks[33], landmarks[31])
                angle9 = calculate_angle(landmarks[27], landmarks[33], landmarks[35])
                angle10 = calculate_angle(landmarks[27], landmarks[33], landmarks[29])
                angle11 = calculate_angle(landmarks[27], landmarks[33], landmarks[62])
                # 预测动作类型
                label = knn.predict([[angle1, angle2, angle3, angle4, angle5, angle5_1, angle6, angle7, angle8, angle9, angle10, angle11]])[0]
                # 在视频帧上绘制动作类型
                cv2.putText(frame, label, (x, y), font, fontScale, color, thickness, cv2.LINE_AA)
        # 显示视频帧
        cv2.imshow('frame',frame)
        # 按q退出
        if cv2.waitKey(25) & 0xFF == ord('q'):
            break
    else:
        break

# 释放视频资源
cap.release()

# 关闭窗口
cv2.destroyAllWindows()
基于OpenCV和KNN的人体动作识别

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

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