失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > CNN实现剪刀石头布手势识别(python)

CNN实现剪刀石头布手势识别(python)

时间:2022-07-17 08:43:25

相关推荐

CNN实现剪刀石头布手势识别(python)

一:图片收集

收集训练图片、测试图片

调用摄像头获取图像 -> 肤色检测处理图像 -> 轮廓查找获取手势图片并保存

import cv2 as cvif __name__ == "__main__":m_0 = 0 #剪刀m_1 = 0 #石头m_2 = 0 #布m_3 = 0 #人脸(加个人脸标签用于避免将人脸错误识别)flag = 0cap = cv.VideoCapture(0) # 调用摄像头while True:success, frame = cap.read() # 读取每一帧new_img = cv.flip(frame, 1) # 翻转roi = new_img# YCrCb之Cr分量 + OTSU二值化(肤色检测)ycrcb = cv.cvtColor(roi, cv.COLOR_BGR2YCrCb) # 把图像转换到YUV色域(y, cr, cb) = cv.split(ycrcb) # 图像分割, 分别获取y, cr, br通道图像# 高斯滤波, cr 是待滤波的源图像数据, (5,5)是值窗口大小, 0 是指根据窗口大小来计算高斯函数标准差cr1 = cv.GaussianBlur(cr, (5, 5), 0) # 对cr通道分量进行高斯滤波# 根据OTSU算法求图像阈值, 对图像进行二值化_, skin1 = cv.threshold(cr1, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)cv.imshow('skin1', skin1) # 展示处理后的图片# 轮廓查找image, contours, hierarchy = cv.findContours(skin1, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)for item in contours: # 遍历所有轮廓(x, y, w, h) = cv.boundingRect(item) # 获得最小矩形框架if w >= 50 and h >= 50: # 在较大的框架中查找img = skin1[y : y + h, x : x + w] # 获得矩形轮廓图cv.imshow('img', img) # 展示矩形轮廓图cv.rectangle(new_img, (x, y), (x + w, y + h), (255, 0, 0), 0) # 在new_img中用矩形框出k = cv.waitKey(1) # 等待键盘促发if k == ord(' '): # 按下空格退出flag = 1breakelif k == ord('a'): # 按A收集剪刀图片# 按下后将图片保存到指定路径(imencode函数可以有中文路径)cv.imencode('.jpg', img)[1].tofile("D:\\pythonfile\\人工智能\\手势识别\\gesture_data\\0\\{}.png".format(m_0))m_0 += 1print('正在保存0-roi图片,本次图片数量:', m_0)elif k == ord('s'): # 按S收集石头图片cv.imencode('.jpg', img)[1].tofile("D:\\pythonfile\\人工智能\\手势识别\\gesture_data\\1\\{}.png".format(m_1))m_1 += 1print('正在保存1-roi图片,本次图片数量:', m_1)elif k == ord('d'): # 按D收集布图片cv.imencode('.jpg', img)[1].tofile("D:\\pythonfile\\人工智能\\手势识别\\gesture_data\\2\\{}.png".format(m_2))m_2 += 1print('正在保存2-roi图片,本次图片数量:', m_2)elif k == ord('f'): # 按F收集人脸图片cv.imencode('.jpg', img)[1].tofile("D:\\pythonfile\\人工智能\\手势识别\\gesture_data\\3\\{}.png".format(m_3))m_3 += 1print('正在保存3-roi图片,本次图片数量:', m_3)cv.imshow("frame", new_img) # 展示new_img图像if flag == 1:breakcap.release() #释放占用资源cv.destroyAllWindows() #释放opencv创建的所有窗口

二:训练模型

获取所收集的图像并转为numpy数组 -> 处理数据(修改大小、归一化、one-hot)-> 将数据放入所创建的模型中进行训练 -> 评估模型、保存模型

import numpy as npimport osimport cv2 as cvimport matplotlib.pyplot as pltfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropoutfrom keras.layers import Flattenfrom keras.layers.convolutional import Conv2Dfrom keras.layers.convolutional import MaxPooling2Dfrom keras.utils import np_utilsfrom keras import backendfrom PIL import Imagebackend.set_image_data_format('channels_first')# 更改动态分配内存import tensorflow as tfimport kerasconfig = tf.ConfigProto()config.gpu_options.allow_growth = Truekeras.backend.tensorflow_backend.set_session(tf.Session(config=config))# 设定随机种子seed = 7np.random.seed(seed)# 读取图片,调整大小(100*100),转为numpy数组def pre_pic(picName):# 先打开传入的原始图片img = Image.open(picName)# 使用消除锯齿的方法resize图片reIm = img.resize((100,100),Image.ANTIALIAS)# 变成灰度图,转换成矩阵im_arr = np.array(reIm.convert("L"))return im_arr# 用pre_pic函数将图片转为numpy数组,并将所有图片的数组合并为一个数组def get_files(file_dir):flag = 0for file in os.listdir(file_dir):image_file_path = os.path.join(file_dir,file)if file == '0': # 文件名为‘0’表示剪刀temp = 0 # 设置标签temp=0elif file == '1': # 文件名为‘1’表示石头temp = 1 # 设置标签temp=1elif file == '2': # 文件名为‘2’表示布temp = 2 # 设置标签temp=2elif file == '3': # 文件名为‘3’表示人脸temp = 3 # 设置标签temp=3for image_name in os.listdir(image_file_path):image_name_path = os.path.join(image_file_path,image_name)img = pre_pic(image_name_path) # 将图片通过pre_pic函数转为numpy数组,例如img.shape=(100,100)if flag == 0: # 第一次处理X_image = img[np.newaxis,:] # X_image.shape=(1,100,100)Y_image = np.array([temp]) # Y_image.shape=(1,)flag = 1else: # 第n次处理(n!=1)#将(n-1,100,100)与(1,100,100)合并为(n,100,100)X_image = np.vstack((X_image,img[np.newaxis,:]))#将(n-1,)与(1,)合并为(n,)Y_image = np.hstack((Y_image,np.array([temp])))return X_image,Y_image # X_image为图片数据,Y_image为标签# 创建、编译模型def create_model():model = Sequential()model.add(Conv2D(filters=8, kernel_size=(3,3),strides=(1,1),padding='same',input_shape=(1,100,100),activation='relu'))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Conv2D(filters=16, kernel_size=(3,3),strides=(1,1),padding='same',activation='relu'))model.add(Dropout(0.5))model.add(MaxPooling2D(pool_size=(4,4)))model.add(Dense(128,activation='relu'))model.add(Flatten())model.add(Dense(4,activation='softmax'))pile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])return modelif __name__ == "__main__":filetrain = "D:\\pythonfile\\人工智能\\手势识别\\gesture_data"filetest = "D:\\pythonfile\\人工智能\\手势识别\\gesturetest"print('start')X_train,Y_train = get_files(filetrain)X_test,Y_test = get_files(filetrain)print(X_train.shape)print(Y_train.shape)# 修改数据格式X_train = X_train.reshape(X_train.shape[0], 1, 100, 100).astype('float32')X_test = X_test.reshape(X_test.shape[0], 1, 100, 100).astype('float32')# 格式化数据到0-1之前X_train = X_train / 255X_test = X_test / 255# one-hot编码Y_train = np_utils.to_categorical(Y_train)Y_test = np_utils.to_categorical(Y_test)# 创建、编译模型model = create_model()# 训练模型model.fit(X_train, Y_train, epochs=10, batch_size=300, verbose=2)# 评估模型score = model.evaluate(X_test, Y_test, verbose=0)print('acc: %.2f%%' % (score[1] * 100))# 保存模型model.save('my_model')

三:动态识别

调用摄像头获取图像 -> 肤色检测处理图像 -> 轮廓查找获取手势图片 -> 将图片转为numpy数组并处理(修改大小、归一化)-> 调用前面所训练的模型进行预测 -> 预测结果在图像中展示

import numpy as npimport cv2 as cvfrom keras.models import load_modelimport matplotlib.pyplot as pltfrom PIL import Imagemodel = load_model('my_model') # 调用所训练的模型# 读取图片,调整大小(100*100),转为numpy数组def pre_pic(picName):# 先打开传入的原始图片img = Image.open(picName)# 使用消除锯齿的方法resize图片reIm = img.resize((100,100),Image.ANTIALIAS)# 变成灰度图,转换成矩阵im_arr = np.array(reIm.convert("L"))return im_arrif __name__ == '__main__':cap = cv.VideoCapture(0) # 调用摄像头filename = '00.jpg'while True:success,frame = cap.read() # 读取每一帧new_img = cv.flip(frame, 1) # 翻转roi = new_img# YCrCb之Cr分量 + OTSU二值化(肤色检测)ycrcb = cv.cvtColor(roi, cv.COLOR_BGR2YCrCb) # 把图像转换到YUV色域(y, cr, cb) = cv.split(ycrcb) # 图像分割, 分别获取y, cr, br通道图像# 高斯滤波, cr 是待滤波的源图像数据, (5,5)是值窗口大小, 0 是指根据窗口大小来计算高斯函数标准差cr1 = cv.GaussianBlur(cr, (5, 5), 0) # 对cr通道分量进行高斯滤波# 根据OTSU算法求图像阈值, 对图像进行二值化_, skin1 = cv.threshold(cr1, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)cv.imshow('skin',skin1) # 展示处理后的图片# 轮廓查找image, contours, hierarchy = cv.findContours(skin1, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 轮廓查找for item in contours:(x, y, w, h) = cv.boundingRect(item) # 获得最小矩形框架if w >= 50 and h >= 50: # 在较大的框架中查找img = skin1[y : y + h, x : x + w] # 获得矩形轮廓图cv.imshow('img',img) # 展示矩形轮廓图cv.imwrite(filename, img) # 将矩形轮廓图保存img = pre_pic(filename)img = img.reshape(1, 1, 100, 100).astype('float32') # 修改数据格式img = img / 255 # 归一化predictions = model.predict_classes(img) # 预测结果flag = model.predict(img) # 预测概率if max(flag[0]) > 0.5: # 概率大于0.5才框出print(predictions)if predictions[0] == 0:s = "jiandao"elif predictions[0] == 1:s = "shitou"elif predictions[0] == 2:s = "bu"elif predictions[0] == 3: # 预测为人脸则跳过continuecv.rectangle(new_img, (x, y), (x + w, y + h), (255, 0, 0), 0) # 用矩形框出cv.putText(new_img, s, (x, y), cv.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0), 2, 8) # 在矩形上方显示文字cv.imshow('image', new_img)Key = cv.waitKey(1)if Key == ord(' '): #按下空格键退出breakcap.release() #释放占用资源cv.destroyAllWindows() #释放opencv创建的所有窗口

如果觉得《CNN实现剪刀石头布手势识别(python)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。