当初学校那边考虑到大部分同学在考研没有时间做,所以给的要求比较低,一组六个人实际上就我一个人做。所以我给自己的目标就是找个简单的方法,同时尽量学明白。找了很多教程之后,选择了最简单的算法进行分类。
基本前提是利用openpose提取特征点,并基于特征点进行识别(区分),所以我是更具自己的目标进行动作设计的。这个目标就是自己所使用的【K聚类分类算法】,因为动作之间的区分明显,算法很好区分。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jraTK7sO-1641805254276)(C:\Users\LittleDC\Pictures\12_LI (2)].jpg)
拍摄照片大小统一处理成64*64像素大小进行归一化。
每张图以3个数据作为邻居样本:分别是左右手腕位置、手腕与肩部距离的左右差值。
计算待分类的图像的这三个数据,与已有10组图像样本的数据进行对比,每组差别最小的获取它的手势标签作为识别结果。
一共得到10组结果,取众数作为识别结果。
说明:(标签定义为:左侧–0,右侧–1,中间–2)
# 处理一张图片
def train_pose(image_path, out_dir, inWidth=368, inHeight=368, threshhold=0.2):
# net = cv.dnn.readNetFromTensorflow(model_path) # 调用预训练好的tf模型
frame = cv.imread(image_path) # 一帧图片
frame = cv.resize(frame, (480, 480)) # 修改图像尺寸
frameWidth = frame.shape[1]
frameHeight = frame.shape[0] # 图片的大小
net = cv.dnn.readNetFromCaffe(protoFile, weightsFile)
inp = cv.dnn.blobFromImage(frame, 1.0 / 255, (inWidth, inHeight), (0, 0, 0), swapRB=False, crop=False)
net.setInput(inp)
out = net.forward()
out = out[:, :9, :, :] # MobileNet output [1, 57, -1, -1], we only need the first 19 elements
## 3. 基于openpose的身体姿态提取
- 标定需要用到的点:上肢姿态点,左三个右三个。肩膀、手肘、手腕
# 图像的左上角为坐标原点
# 字典变量
BODY_PARTS = {"Nose": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
"LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
"RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "REye": 14,
"LEye": 15, "REar": 16, "LEar": 17, "Background": 18}
# 颈部1;左右肩25;左右手肘36;左右手腕47
# 列表变量
POSE_PAIRS = [["Neck", "RShoulder"], ["Neck", "LShoulder"], ["RShoulder", "RElbow"],
["RElbow", "RWrist"], ["LShoulder", "LElbow"], ["LElbow", "LWrist"],
["Neck", "RHip"], ["RHip", "RKnee"], ["RKnee", "RAnkle"], ["Neck", "LHip"],
["LHip", "LKnee"], ["LKnee", "LAnkle"], ["Neck", "Nose"], ["Nose", "REye"],
["REye", "REar"], ["Nose", "LEye"], ["LEye", "LEar"]]
# 前六个为手势相关的六条连接
protoFile = "pose_deploy_linevec.prototxt"
weightsFile = "pose_iter_440000.caffemodel"
model_path = "graph_opt.pb"
# 调用预训练好的tf模型
def train_pose(image_path, out_dir, inWidth=368, inHeight=368, threshhold=0.2):
# net = cv.dnn.readNetFromTensorflow(model_path)
net = cv.dnn.readNetFromCaffe(protoFile, weightsFile)
inp = cv.dnn.blobFromImage(frame, 1.0 / 255, (inWidth, inHeight), (0, 0, 0), swapRB=False, crop=False)
实现一个分类器的基础是一个预先给定的类别集合C={C1,C2,…,Cm}和一批已知类别的样本数据集D={d1,d2,…,dn}。不同分类算法的区别一般体现在所形成的分类规则上。
在分类问题中,一个核心的概念是两个数据点之间的距离。所谓判断一个数据点该属于哪个类,本质上就是看它离哪个类的已知数据点更近。而“距离”在不同的应用背景下可能有不同的定义。以二维数据空间为例,给出三种常见的距离定义,如图2所示。
设(x1,y1)和(x2,y2)为两个数据点p1和p2的坐标,欧式距离、曼哈顿距离和余弦相似度(即平面上两个向量夹角的余弦值)分别为:
针对样本数据D,KNN算法计算待分类数据x与样本数据集D中所有数据的距离,然后取其中最小的K个(也就是“KNN”中的K,而NN表示“最近的邻点”),看它们分别属于哪一个类,判定x应该属于K中出现较多的那个类。针对样本数据D,KNN算法计算待分类数据x与样本数据集D中所有数据的距离,然后取其中最小的K个(也就是“KNN”中的K,而NN表示“最近的邻点”),看它们分别属于哪一个类,判定x应该属于K中出现较多的那个类。
利用openpose识别身体姿态点,标定需要用到的六个上肢姿态点,分别为左半身和右半身的三个肩膀点、手肘点、手腕点。确定3种手势,在不同环境下由不同人拍摄制作采集成10组数据,作为数据集。图片统一处理成64*64像素大小,进行归一化处理。每张图片采用欧式距离定义以3个数据作为样本:分别是左右手腕位置、手腕与肩部距离的左右差值。通过计算待分类的图像的这三个数据,与已有10组图像样本的数据进行对比,计算得到每组中与待分类图像差值最小的手势,获取它的手势标签,作为识别结果。其中第一种手势即左手抬起的标签定义为–0,第二种手势即右手抬起,左手放下的标签定义为–1,第三种手势即双手均放下的标签定义为–2。共得到10组识别结果,取众数作为识别结果。
# 读取待识别图像
path = 'detect.jpg'
result_path = r'C:\Users\viola\PycharmProjects\hand_re\openpose_dynamic\detect_result'
dfe = get_pose(path, result_path, inWidth=368, inHeight=368, threshhold=0.2)
# 计算与30个样本数据的距离
d = np.zeros((30, 5))
for w in range(30):
d[w] = np.sum((dfe - train_features[w, :]) ** 2)
d = d.tolist() # 转变为列表数据结构
ma = max(d)
result_index = []
k = 10 # 非3的倍数,可以出结果
for i in range(k):
a = d.index(min(d))
result_index.append(a)
d[a] = ma # 避免被反复查找
result_labels = [int(i / 10) for i in result_index]
r = np.zeros(3)
for n in result_labels:
r[int(n)] += 1
result_pose = hand_pose[int(np.argmax(r))] # 返回最大值的索引
print('the pose maybe is' + result_pose)
在机器学习中,当确定好一个模型后,我们需要将它保存下来,这样当新数据出现时,我们能够调出这个模型来对新数据进行预测。同时这些新数据将被作为历史数据保存起来,经过一段周期后,使用更新的历史数据再次训练,得到更好的模型。
如果模型的流转都在python内部,那么可以使用内置的pickle库来完成模型的存储和调取。
pickle是负责将python对象序列化(serialization)和反序列化(de- serialization)的模块。pickle模块可以读入任何python对象,然后将它们转换成字符串,我们再使用dump函数将其储存到文件中,这个过程叫做pickling;反之从文件中提取原始python对象的过程交错unpickling。
# 保存训练数据
pickle_file = 'parameter.pickle'
if not os.path.isfile(pickle_file): # 判断是否存在此文件,若无则存储
print('Saving data to pickle file...')
try:
with open('parameter.pickle', 'wb') as pfile:
pickle.dump({'train_dataset': fes, 'train_labels': train_labels}, pfile, pickle.HIGHEST_PROTOCOL)
except Exception as e:
print('Unable to save data to', pickle_file, ':', e)
raise
print('Data cached in pickle file.')
# 读取训练数据
pickle_file = 'parameter.pickle'
with open(pickle_file, 'rb') as f:
pickle_data = pickle.load(f) # 反序列化,与pickle.dump相反
train_features = pickle_data['train_dataset']
train_labels = pickle_data['train_labels']
del pickle_data # 释放内存
print('Data and modules loaded.')
因篇幅问题不能全部显示,请点此查看更多更全内容