---
# System prepended metadata

title: <h1>Hand Posture Recognition with CNN</h1>
tags: [大三, Python, 深度學習]

---

# <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()                     #印出圖
```

### 顯示訓練後的結果以及圖

經過訓練之後的結果如下：
![](https://i.imgur.com/OWBZcVW.png)
![](https://i.imgur.com/5qV87Eb.png)
![](https://i.imgur.com/OpEPM0N.png)

經過測試資料後得到的結果如下：
![](https://i.imgur.com/XDOwtnq.png)

以下是繪製Loss和accuracy的圖：
![](https://i.imgur.com/7CwpcVI.png)
![](https://i.imgur.com/HoJbK26.png)






