1.问题描述

使用CNN,识别如下三种不同的手势:

Resnet网络手势识别原理及方案 cnn手势识别_python

提供的数据集:
共提供五个数据集,其中Set1、Set2、Set3为训练集,Set4和Set5位测试集。
每个数据集中包含0000-0008九个文件夹,0000-0002,0003-0005,0006-0008分别为手势一、手势二和手势三。每个文件夹中有0000-0019共二十张32x32像素的灰阶图。

2.数据预处理

①定义得到训练集和测试集所有图片的path和label的function

首先要得到数据,通过读取五个数据集内的图片,先统一获取到测试集和训练集,稍后再将训练集和测试集分开。

# 得到训练集和测试集的所有图片path和label
import cv2
import numpy as np
import os
def enumerate_files(base_path = 'C:/Users/NOTEBOOK/DeepLearningNote/All_gray_1_32_32'):
    filenames,labels = [],[]
    for file1 in os.listdir(base_path):#得到根目录的下一级目录,内有“Set1”...
        for file2 in os.listdir(base_path+'/'+file1):#得到set1到set5的0000-0008
            for file3 in os.listdir(base_path+'/'+file1+'/'+file2):#得到所有的0000-0019
                for file4 in os.listdir(base_path+'/'+file1+'/'+file2+'/'+file3):#得到所有的图片
                    filenames += [base_path+'/'+file1+'/'+file2+'/'+file3+'/'+file4]
                    #将三种手势分别对应0,1,2
                    if(file2 in ['0000','0001','0002']):
                        labels += [0]
                    if(file2 in ['0003','0004','0005']):
                        labels += [1]
                    if(file2 in ['0006','0007','0008']):
                        labels += [2]
    return filenames,labels

②定义将图片转换为神经网络可以处理的array的function

需要注意的是,在我的这种将图片转换为array的时候,img_to_array方法产生的结果是一个三通道的彩色图片结果,由于我们数据为灰阶图,所以三个通道的数值会是一样的,在此我只保留RGB通道的index=0的通道。

#将enumerate_files方法获取到得图片的path,转换为array
from keras.preprocessing.image import img_to_array, load_img
def read_images(images):
    imgs = []
    for image in images:
        img = load_img(image)
        img = img_to_array(img)
        img = img[:,:,0]/255.0#由于img_to_array方法得到的通道数是3,是彩色图,所以最后会有三个通道,我们只取三个中的一个(三个颜色的通道内容相同)
        imgs.append(img)
    return imgs

③利用前面两个function,得到images和labels,并且划分为train_data,test_data

原始的数据集中,训练集为Set1、Set2、Set3,测试集为Set4和Set5,所以我们按照顺序得到的所有图片前540张为训练集,540之后为测试集。

#使用enumerate_files(),read_images()将图片转换为array,以及每张图片对应的label标签
from keras.utils import to_categorical
filenames,labels = enumerate_files()
images = read_images(filenames)
images = np.array(images)#这个时候,images.shape = 900,32,32
images = images.reshape((900,32,32,1))
labels = to_categorical(labels)

train_images = images[:540]
train_labels = labels[:540]
test_images = images[540:]
test_labels = labels[540:]
print(test_labels.shape)

3.建立模型

因为要做两组判断,一组用数据增强,一组不用数据增强,在此我们使用一个function来构造model

#建立构造model的function
#建立模型的function
from keras import models,layers
def createModel():
    model = models.Sequential()
    model.add(layers.Conv2D(32,(2,2),activation='relu',input_shape=(32,32,1)))
    model.add(layers.MaxPooling2D((2,2)))
    model.add(layers.Conv2D(64,(2,2),activation='relu'))
    model.add(layers.MaxPooling2D((2,2)))
    model.add(layers.Conv2D(128,(2,2),activation='relu'))
    model.add(layers.MaxPooling2D((2,2)))
    model.add(layers.Conv2D(128,(2,2),activation='relu'))
    model.add(layers.MaxPooling2D((2,2)))

    model.add(layers.Flatten())
# model.add(layers.Dropout(0.3))
    model.add(layers.Dense(512,activation='relu'))
    model.add(layers.Dense(3,activation='softmax'))

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

4.训练模型

①打乱数据集顺序

由于原始数据集是存在一定的规律顺序,先是手势1,然后手势2,然后手势3,所以在训练模型之前,我们要先将train_data的顺序打乱

# 简单分类之前要先打乱一下
shuffle_index= np.arange(train_images.shape[0])
np.random.shuffle(shuffle_index)
train_images = train_images[shuffle_index]
train_labels = train_labels[shuffle_index]
print(shuffle_index)

②划分出验证集

得到了打乱的训练集后,再划分出验证集validation_data,在本测试中,选取了validation的长度为100

#划分出validation集和train集
validation_images = train_images[:100]
validation_labels = train_labels[:100]
images = train_images[100:]
labels = train_labels[100:]

③不使用数据增强来训练模型

model = createModel()
history = model.fit(images,labels,epochs=40,batch_size=32,validation_data=(validation_images,validation_labels))

④使用数据增强来训练模型

#使用数据增强
from keras.preprocessing.image import ImageDataGenerator,img_to_array
datagen = ImageDataGenerator(
        rotation_range=40,
        width_shift_range=0.2,
        height_shift_range=0.2,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True,
        fill_mode='nearest')
model1 = createModel()

history1 = model1.fit_generator(datagen.flow(images,labels,batch_size=32),
                    steps_per_epoch=len(train_images)/32,epochs = 40,validation_data=(validation_images,validation_labels))

5.打印训练过程

“蓝色”为不使用数据增强的训练过程图
“红色”为使用数据增强的训练过程图

import matplotlib.pyplot as plt
acc = histroy.history["accuracy"]
loss = histroy.history['loss']
epochs = range(1,len(acc)+1)
val_acc = histroy.history["val_accuracy"]
val_loss = histroy.history["val_loss"]

plt.plot(epochs,acc,'bo',label="Training acc")
plt.plot(epochs,val_acc,'b',label="Validation acc")
plt.legend()
plt.show()

Resnet网络手势识别原理及方案 cnn手势识别_Resnet网络手势识别原理及方案_02

plt.plot(epochs,loss,'bo',label="Training loss")
plt.plot(epochs,val_loss,'b',label="Validation loss")
plt.legend()
plt.show()

Resnet网络手势识别原理及方案 cnn手势识别_tensorflow_03

import matplotlib.pyplot as plt
acc = history1.history["accuracy"]
loss = history1.history['loss']
epochs = range(1,len(acc)+1)
val_acc = history1.history["val_accuracy"]
val_loss = history1.history["val_loss"]

plt.plot(epochs,acc,'ro',label="Training acc")
plt.plot(epochs,val_acc,'r',label="Validation acc")
plt.legend()
plt.show()

Resnet网络手势识别原理及方案 cnn手势识别_深度学习_04

plt.plot(epochs,loss,'ro',label="Training loss")
plt.plot(epochs,val_loss,'r',label="Validation loss")
plt.legend()
plt.show()

Resnet网络手势识别原理及方案 cnn手势识别_python_05

6.评估模型

不使用数据增强

loss_and_metries = model.evaluate(test_images,test_labels)
print(loss_and_metries)

评估结果如下:

360/360 [==============================] - 0s 260us/step
[0.09706378592074745, 0.9638888835906982]

使用数据增强

result = model1.evaluate(test_images,test_labels)
print(result)

评估结果如下:

360/360 [==============================] - 0s 255us/step
[0.11562680713379653, 0.9638888835906982]

两个方法相差较少,可能以为这三个手势的识别较为简单,不使用数据增强也能得到较好的结果

7.总结

此神经网络为第一次使用keras实践,在过程中出现很多小问题,如:
1.最初忘记了打乱一下训练集(由于原始数据是有规律的,也导致后续划分的validation有问题),所以出现validation_acc和validation_loss的图像震荡幅度很大,acc和loss在0和1之间来回震荡。
2.得到了灰阶图的张量化表示后,要注意再增加一个维度,使符合神经网络的输入规格