基于KNN的手势识别系统:Python实现
基于KNN的手势识别系统:Python实现
本项目使用Python开发了一个基于KNN算法的手势识别系统。系统通过摄像头采集图像,识别手势,并根据预训练的模型预测手势类别。
步骤:
-
数据准备:
- 加载动作数据集:
warmup_df,combat_df,attack_df,respect_df,gongbu_df,每个数据集包含手势图像和对应的动作标签。 - 数据清洗:删除每个小数据集中偏离平均值超过2倍标准差的样本。
- 将数据集合并为一个大的数据集
data。
- 加载动作数据集:
-
数据可视化:
- 可视化数据集,展示每个图像及其对应的动作标签。
-
特征提取:
- 定义函数
extract_features,用于提取手势图像的特征。本项目中,特征是手部轮廓点的角度差。
- 定义函数
-
模型训练:
- 训练KNN模型,使用提取的特征和动作标签。
-
测试:
- 打开摄像头,实时捕获图像。
- 使用OpenCV进行人脸检测,找到人脸区域。
- 在人脸区域进行手部检测,找到手部区域。
- 对手部区域进行预处理:
- 调整大小
- 高斯模糊
- 二值化
- Canny边缘检测
- 计算手部轮廓点的角度差,作为特征。
- 使用训练好的KNN模型预测手势类别。
- 在图像上显示预测结果。
代码:
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)
# 可视化数据集
print('可视化数据集')
for i in range(len(data)):
img_path = data['img_path'][i]
img = cv2.imread(img_path)
img = cv2.resize(img, (400, 400))
cv2.putText(img, data['action'][i], (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow('Dataset', img)
if cv2.waitKey(0) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
# 特征提取函数
def extract_features(df):
features = []
for i in range(len(df)):
angles = df.iloc[i][['angle1','angle2','angle3', 'angle4','angle5','angle5_1' ,'angle6', 'angle7','angle8','angle9','angle10','angle11']]
# 计算角度差
diff_angles = []
for j in range(len(angles) - 1):
diff_angles.append(angles[j+1] - angles[j])
features.append(diff_angles)
return features
# 特征提取
print('特征提取')
X = extract_features(data)
y = data['action']
# 训练KNN模型
print('训练模型')
knn = KNeighborsClassifier(n_neighbors=neighbors)
knn.fit(X, y)
# 测试
print('开始测试')
cap = cv2.VideoCapture(0)
angles = []
while(True):
# 读取摄像头的帧
ret, frame = cap.read()
# 将帧转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 显示摄像头的帧
cv2.imshow('frame',gray)
# 按下q键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 人脸检测
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_roi = gray[y:y+h, x:x+w]
# 手部检测
hand_cascade = cv2.CascadeClassifier('hand_cascade.xml')
hands = hand_cascade.detectMultiScale(face_roi, 1.3, 5)
# 如果检测到手部
if len(hands) > 0:
# 取第一个手部
(hx,hy,hw,hh) = hands[0]
# 将手部部分提取出来
hand_roi = face_roi[hy:hy+hh, hx:hx+hw]
# 手势识别
hand_roi = cv2.resize(hand_roi, (100, 100))
hand_roi = cv2.GaussianBlur(hand_roi, (5, 5), 0)
_, hand_roi = cv2.threshold(hand_roi, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
hand_roi = cv2.Canny(hand_roi, 100, 200)
contours, _ = cv2.findContours(hand_roi, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) > 0:
cnt = max(contours, key=cv2.contourArea)
hull = cv2.convexHull(cnt)
cv2.drawContours(hand_roi, [hull], 0, 255, 2)
cnt = cnt.reshape(cnt.shape[0], cnt.shape[2])
angles = []
for i in range(cnt.shape[0]):
x1, y1 = cnt[i-1]
x2, y2 = cnt[i]
x3, y3 = cnt[(i+1)%cnt.shape[0]]
angle = math.degrees(math.atan2(y2-y1, x2-x1) - math.atan2(y3-y2, x3-x2))
angles.append(angle)
angles = np.array(angles)
diff_angles = []
for i in range(len(angles) - 1):
diff_angles.append(angles[i+1] - angles[i])
diff_angles = np.array([diff_angles])
action = knn.predict(diff_angles)
cv2.putText(frame, action[0], (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 显示结果
cv2.imshow('frame',frame)
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
注意:
- 该代码需要OpenCV库,可以使用
pip install opencv-python安装。 - 需要准备动作数据集,并将其保存在
dataset_warm-up.csv,dataset_SHIZHAN POSE.csv,dataset_hit.csv,dataset_respect.csv,dataset_gongbu.csv文件中。 - 需要使用
haarcascade_frontalface_default.xml和hand_cascade.xml人脸和手部检测器,可以从OpenCV官方网站下载。
原文地址: https://www.cveoy.top/t/topic/gQ1f 著作权归作者所有。请勿转载和采集!