一:图片收集

收集训练图片、测试图片

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

import cv2 as cv

if __name__ == "__main__":
    m_0 = 0  #剪刀
    m_1 = 0  #石头
    m_2 = 0  #布
    m_3 = 0  #人脸(加个人脸标签用于避免将人脸错误识别)
    flag = 0
    cap = 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 = 1
                    break
                elif k == ord('a'): # 按A收集剪刀图片
                    # 按下后将图片保存到指定路径(imencode函数可以有中文路径)
                    cv.imencode('.jpg', img)[1].tofile("D:\\pythonfile\\人工智能\\手势识别\\gesture_data\\0\\{}.png".format(m_0))
                    m_0 += 1
                    print('正在保存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 += 1
                    print('正在保存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 += 1
                    print('正在保存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 += 1
                    print('正在保存3-roi图片,本次图片数量:', m_3)

        cv.imshow("frame", new_img) # 展示new_img图像
        if flag == 1:
            break

    cap.release() #释放占用资源
    cv.destroyAllWindows() #释放opencv创建的所有窗口

resnet50 网络手势识别 cnn手势识别_数组


resnet50 网络手势识别 cnn手势识别_数组_02


resnet50 网络手势识别 cnn手势识别_人工智能_03


resnet50 网络手势识别 cnn手势识别_神经网络_04


resnet50 网络手势识别 cnn手势识别_神经网络_05

二:训练模型

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

import numpy as np
import os
import cv2 as cv
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend
from PIL import Image
backend.set_image_data_format('channels_first')

# 更改动态分配内存
import tensorflow as tf
import keras
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
keras.backend.tensorflow_backend.set_session(tf.Session(config=config))

# 设定随机种子
seed = 7
np.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 = 0
    for file in os.listdir(file_dir):
        image_file_path = os.path.join(file_dir,file)
        if file == '0':  # 文件名为‘0’表示剪刀
            temp = 0  # 设置标签temp=0
        elif file == '1':  # 文件名为‘1’表示石头
            temp = 1  # 设置标签temp=1
        elif file == '2':  # 文件名为‘2’表示布
            temp = 2  # 设置标签temp=2
        elif file == '3':  # 文件名为‘3’表示人脸
            temp = 3  # 设置标签temp=3
        for 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 = 1
            else:  # 第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'))

    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model


if __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 / 255
    X_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 np
import cv2 as cv
from keras.models import load_model
import matplotlib.pyplot as plt
from PIL import Image

model = 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_arr

if __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: # 预测为人脸则跳过
                        continue
                    cv.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(' '):  #按下空格键退出
            break

    cap.release() #释放占用资源
    cv.destroyAllWindows() #释放opencv创建的所有窗口

resnet50 网络手势识别 cnn手势识别_人工智能_06