0. 说明
实现人物的姿势判断(当然是很简单的那种,KNN对于复杂的图像是解决不了的,另外还有经典的手写数字识别,也是简单的图像)
如上图所示,人物姿势有两种,【站】和【蹲】,实际上还有第三种【趴】,对于这种简单的图像,再添加许多种都是一样的。(实际上这就是在pubg游戏上截的图,每类图像不用很多)
直接贴代码
#训练(使用的话要修改根目录)
import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier as KNN
from sklearn.model_selection import cross_val_score
def main():
# 根目录
path = r"C:\Users\cun\Desktop\test"
# 训练目标数组和训练集数组
train = []
target = []
# 用于剔除根目录,子文件夹名称可以作为分类目标
index = -1
# 遍历根目录下的文件夹和文件
for root, dirs, files in os.walk(path):
# 在路径中筛选出分类目标
pathArr = root.split('\\')
type = pathArr[len(pathArr) - 1] # 当前类别
# 丢掉根目录
if index == -1:
index += 1
continue
# 遍历图像文件
for image in files:
# 读取图像文件
digit = cv2.imread(root + "\\" + image)
# 降维到二维
twoDimensional = digit[:, :, 0]
# 获取图像高度和宽度
height = twoDimensional.shape[0] # 高度
weight = twoDimensional.shape[1] # 宽度
# 降维到一维
res = twoDimensional.reshape(height * weight)
# 手工将人物和背景区分开
for rn in range(len(res)):
res[rn] = 0 if res[rn] < 220 else 1
# 加入训练集
train.append(res)
# 分类目标
target.append(type)
index += 1
# 训练
knn = KNN(n_neighbors=5, weights='distance', p=2, n_jobs=-1) # p=2 欧式距离;n_jobs=-1 所有线程都工作;
knn.fit(train, target) # KNN模型已生成
if __name__ == '__main__':
main()
#测试(使用的话要修改测试目录)
test, test_target = [], []
digit = cv2.imread(r"C:\Users\cun\Desktop\test\A\17.png")
plt.imshow(digit)
plt.show()
# 降维到二维
twoDimensional1 = digit[:, :, 0]
# 获取图像高度和宽度
height1 = twoDimensional1.shape[0] # 高度
weight1 = twoDimensional1.shape[1] # 宽度
# 降维到一维
res1 = twoDimensional1.reshape(height1 * weight1)
# 手工将人物和背景区分开
for rn in range(len(res1)):
res1[rn] = 0 if res1[rn] < 220 else 255
test.append(res1)
pred_res = knn.predict(test)
print(pred_res)
使用的包如下图所示。
1. 训练
1.1 IO
这里有一个io的操作,使用者不用写很多文件夹,只需要写一个根目录即可,里面放着图像的类别和对应的图像。
程序读到根目录后,获取到目录下的文件夹,并将文件夹的名称作为训练的目标,把文件夹内的图像数据当作训练集。
以test文件夹作为根目录,os.walk()可以找出特定目录下的所有文件夹和文件,
- root 表示当前正在访问的文件夹路径
- dirs 表示该文件夹下的子目录名list
- files 表示该文件夹下的文件list
以输出root为例
for root, dirs, files in os.walk(path):
print(root)
可以看到输出了根目录,和下属的两个子目录,而跟目录我们是不需要的,这里使用了一个索引直接抛弃了根目录。
接下来根据“\”拆分字符串,留下了需要的文件名作为训练目标。
# 在路径中筛选出分类目标
pathArr = root.split('\\')
type = pathArr[len(pathArr) - 1] # 当前类别
print(type)
1.2 降维
knn训练使用的是一维数组,所以必须从三维降到一维。
另外,在knn中,怎么让数组代表这种人物姿势呢?因为本示例的图像很简单,这里人工规定将一维数组中所有数值大于或等于220的都变为1,小于220的则变为0
为了便于理解,这里挑选了一张图像
将经过转化后并且二维化的数据输出成了txt文件(建议离远一点看下图,近视的童鞋摘掉眼镜看下图会更加直观)
感兴趣的可以试试,程序放到了下面
import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier as KNN
from sklearn.model_selection import cross_val_score
def main():
# 根目录
path = r"C:\Users\cun\Desktop\test"
# 读取图像文件
digit = cv2.imread(path + "\\A\\0.png")
plt.imshow(digit)
plt.show()
# 降维到二维
twoDimensional = digit[:, :, 0]
# 获取图像高度和宽度
height = twoDimensional.shape[0] # 高度
weight = twoDimensional.shape[1] # 宽度
# 手工将人物和背景区分开
for i in range(height):
for j in range(weight):
twoDimensional[i][j] = 0 if twoDimensional[i][j] < 220 else 1
arr = np.array(twoDimensional)
np.savetxt(r"C:\Users\cun\Desktop\test\aaa.txt", arr, fmt="%d")
if __name__ == '__main__':
main()
1.3 训练
记得把训练数据和目标数据存储到数组中
这里直接使用sklearn中的knn模型进行训练
# 训练
knn = KNN(n_neighbors=5, weights='distance', p=2, n_jobs=-1) # p=2 欧式距离;n_jobs=-1 所有线程都工作;
knn.fit(train, target) # KNN模型已生成
测试和训练使用了同样的程序,这里不再赘述。