基于OpenCV和KNN的人体动作识别
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()
原文地址: https://www.cveoy.top/t/topic/gQ07 著作权归作者所有。请勿转载和采集!