# <h1>Hand Posture Recognition with CNN</h1>
###### tags: `深度學習` `Python` `大三`
## 目錄
<ul>
<li>目錄</li>
<li>
問題
<ul>
<li>問題內容</li>
</ul>
</li>
<li>
解決過程
<ul>
<li>產生訓練資料以及測試資料</li>
<li>建立模型</li>
<li>訓練模型</li>
<li>繪製loss圖以及accuracy圖</li>
<li>顯示訓練後的結果以及圖</li>
</ul>
</li>
</ul>
## 問題
### 問題內容:
設計模型來辨識三種不同的手勢,
可獲得5張在不同照片下從不同人物處捕獲的數據集
拍攝條件。每個數據集中的樣本存儲在9個單獨的目錄中。
目錄0000〜0002、0003〜0005和0006〜0008包含狀態1、2的樣本和3。
每個目錄有20個樣本。每個樣本都是32x32的灰度圖像像素。
## 解決過程
在程式碼中,會需要import以下資料:
```
import cv2
import numpy as np
import os
from keras import layers
from keras import models
from keras.utils import to_categorical
import matplotlib.pyplot as plt
```
### 產生訓練資料以及測試資料:
```
def enumerate_files(dirs, path='All_gray_1_32_32', n_poses=3,n_samples=20):
#從路徑中獲得資料放入filenames,targets中
filenames, targets = [], []
for p in dirs:
for n in range(n_poses):
for j in range(3):
dir_name = path+'/'+p+'/000'+str(n*3+j)+'/'
for s in range(n_samples):
d = dir_name+'%04d/'%s
for f in os.listdir(d):
if f.endswith('jpg'):
filenames += [d+f]
targets.append(n)
return filenames, targets
def read_images(files): #使用cv2將圖片存成灰階的圖案放入img
imgs = []
for f in files:
img = cv2.imread(f, cv2.IMREAD_GRAYSCALE)
imgs.append(img)
return imgs
def read_datasets(datasets): #使用enumerate_files和read_images得到train和test資料
files, labels = enumerate_files(datasets)
list_of_arrays = read_images(files)
return np.array(list_of_arrays),labels #list_of_arrays要使用np.array存成array形式
train_sets = ['Set1', 'Set2', 'Set3'] #set1~set3是訓練資料
test_sets = ['Set4', 'Set5'] #set4~set5是測試資料
trn_array, trn_labels = read_datasets(train_sets) #獲得訓練的array和label
tst_array, tst_labels = read_datasets(test_sets) #獲得測試的array和label
trn_array = trn_array.reshape(540,32,32,1)
#要reshape成四維的(幾張照片,幾乘幾的圖片,每次幾張)
trn_array = trn_array.astype('float32')/255.0 #轉換類型成float
trn_labels = to_categorical(trn_labels) #將label向量轉為二進制
tst_array = tst_array.reshape(360,32,32,1)
#要reshape成四維的(幾張照片,幾乘幾的圖片,每次幾張)
tst_array = tst_array.astype('float32')/255.0 #轉換類型成float
tst_labels = to_categorical(tst_labels) #將label向量轉為二進制
```
透過以上程式碼,
在路徑:'All_gray_1_32_32'中,
可以將測試資料存入trn_array和trn_labels中
以及將訓練資料存入tst_array和tst_labels中
以及將資料都轉變成之後model中能夠使用的型態(包含reshape、astype、to_categorical)
### 建立模型
```
model = models.Sequential() #建立sequential的model
model.add(layers.Conv2D(32, (5, 5), activation='relu', input_shape=(32,32,1),name='layer1')) #建立第一層layer
model.add(layers.MaxPooling2D((2, 2))) #將圖片尺寸減半
model.add(layers.Conv2D(64, (3, 3), activation='tanh')) #建立layer
model.add(layers.MaxPooling2D((2, 2))) #將圖片尺寸減半
model.add(layers.Conv2D(64, (3, 3), activation='relu')) #建立layer
model.add(layers.Conv2D(32, (3, 3), activation='tanh')) #建立layer
model.add(layers.Flatten()) #將輸入的向量扁平化
model.add(layers.Dense(128, activation='tanh')) #使用dense多增加一層
model.add(layers.Dense(3, activation='softmax')) #最後建立一層使用softmax
model.compile(loss='categorical_crossentropy', optimizer='rmsprop',metrics=['accuracy']) #對model進行compile
```
藉由以上程式碼,可以將model建立成功,其中使用了兩次relu、三次tanh、一次softmax。
### 訓練模型
```
train_history = model.fit(trn_array, trn_labels, epochs=50, batch_size=64)
#訓練資料後存入train_history
```
以上程式碼可以將訓練資料帶入model中開始訓練,並且將訓練的內容存入train_history中
並透過以下程式碼來將測試資料對model進行evaluate,得到測試的結果(accuracy):
```
test_loss, test_acc = model.evaluate(tst_array, tst_labels) #對測試資料進行evaluate
print(test_acc)
```
### 繪製loss圖以及accuracy圖
要繪製圖首先要將train_history中的loss值和accuracy值取出,還有作圖所需要的Epochs值,
透過以下程式碼:
```
train_loss = train_history.history['loss'] #取出訓練過程的loss值
train_accuracy = train_history.history['accuracy'] #取出訓練過程的accuracy值
Epoch_data = [] #建立作圖需要用的Epoch_data
for i in range(1,51,1):
Epoch_data.append(i)
```
獲得作圖所需的資料後,就可以藉由下圖開始繪製圖:
```
plt.plot(Epoch_data,train_loss,label='Loss_data',color='blue' ) #做Epoch和loss的圖
plt.xlabel('Epoch_data') #建立X軸標籤
plt.ylabel('Loss_data') #建立Y軸標籤
plt.legend()
plt.show() #印出圖
plt.plot(Epoch_data,train_accuracy,label='accuracy_data',color='blue')#做Epoch和accuracy的圖
plt.xlabel('Epoch_data') #建立X軸標籤
plt.ylabel('Accuracy_data') #建立Y軸標籤
plt.legend()
plt.show() #印出圖
```
### 顯示訓練後的結果以及圖
經過訓練之後的結果如下:



經過測試資料後得到的結果如下:

以下是繪製Loss和accuracy的圖:

