項目環境:opencv==3.4.5 scikit-learn =>=0.20.2. numpy == 1.17.4
參考博客:https://blog.csdn.net/qq_41562704/article/details/88975569
一、收集數據集
1、數據集圖片的大小 300x300
2、獲取上、下、左、右的手勢,進行皮膚檢測,將背景二值化
3、皮膚檢測參考文章(https://blog.csdn.net/weixin_40893939/article/details/84527037)
dataset.py
# -*- coding: utf8 -*-
# @auth
# 獲取數據集
import cv2
import numpy as np
from picture import skinMask
#圖片數據格式爲 300x300
HEIGHT = 300
WIDTH = 300
#獲取手勢框左上角座標
x0 = 100
y0 = 100
#保存圖片計數器
count = 0
if __name__ == '__main__':
cap = cv2.VideoCapture(0) #打開攝像頭
while True:
ret, frame = cap.read() #讀取攝像頭內容
if ret == False:
break #若內容讀取失敗則跳出循環
frame = cv2.flip(frame, 1) #翻轉圖片
cv2.rectangle(frame, (x0-1,y0-1), (x0+WIDTH+1, y0+HEIGHT+1), (0,255,0), 2) #畫出獲取手勢的位置框
roi = frame[y0:y0+HEIGHT, x0:x0+WIDTH] # 獲取手勢框內容
res = skinMask(roi) # 皮膚檢測
frame[y0:y0+HEIGHT, x0:x0+WIDTH] = res # 將肌膚檢測後
cv2.imshow("frame", frame) #展示圖片
key = cv2.waitKey(25) #獲取按鍵,進行判斷下一步操作
if key == 27:
break # 按ESC鍵退出
elif key == ord("w"):
y0 -= 5 # 按w向上移動
elif key == ord("a"):
x0 -= 5 # 按a向左移動
elif key == ord("s"):
y0 += 5 # 按s向下移動
elif key == ord("d"):
x0 += 5 # 按d向右移動
elif key == ord("l"):
# 按l保存手勢
count += 1
cv2.imwrite("./dataset/{:d}.png".format(count), roi) # 保存手勢
cap.release()
cv2.destroyAllWindows()
效果展示:
按鍵:a(左移手勢框), w(上移手勢框), s(下移手勢框), d(右移手勢框), l(保存手勢框中數據)
二、訓練數據集
1、提取數據集的HOG特徵,調用OpenCV自帶函數
2、使用SVM進行訓練,分類
classify.py
# -*- coding: utf-8 -*-
# @auth
# 使用SVM對手勢方向進行訓練, 分類
import cv2
import numpy as np
from os import listdir
from sklearn.svm import SVC
from sklearn.externals import joblib
from sklearn.model_selection import GridSearchCV
train_path = "./feature/"
test_path = "./test_feature/"
model_path = "./model/"
# 將txt文件中的特徵轉化成向量
def txtToVector(filename, N):
returnVec = np.zeros((1,N))
fr = open(filename)
lineStr = fr.readline()
lineStr = lineStr.split(" ")
for i in range(N):
returnVec[0, i] = int(lineStr[i])
return returnVec
# 訓練SVM
def train_SVM(N):
svc = SVC()
parameters = {'kernel':('linear', 'rbf'),
'C':[1, 3, 5, 7, 9, 11, 13, 15, 17, 19],
'gamma':[0.00001, 0.0001, 0.001, 0.1, 1, 10, 100, 1000]}#預設置一些參數值
hwLabels = []#存放類別標籤
trainingFileList = listdir(train_path)
m = len(trainingFileList)
trainingMat = np.zeros((m,N))
for i in range(m):
fileNameStr = trainingFileList[i]
classNumber = int(fileNameStr.split('_')[0])
hwLabels.append(classNumber)
trainingMat[i,:] = txtToVector(train_path+fileNameStr, N)#將訓練集改爲矩陣格式
clf = GridSearchCV(svc, parameters, cv=5, n_jobs=8)#網格搜索法,設置5-折交叉驗證
clf.fit(trainingMat, hwLabels)
print(clf.return_train_score)
print(clf.best_params_) #打印出最好的結果
best_model = clf.best_estimator_
print("SVM Model saved")
save_path = model_path + "svm_train_model.m"
joblib.dump(best_model,save_path)#保存最好的模型
# 測試SVM
def test_SVM(clf,N):
testFileList = listdir(train_path)
errorCount = 0#記錄錯誤個數
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
classNum = int(fileNameStr.split('_')[0])
vectorTest = txtToVector(train_path+fileNameStr,N)
valTest = clf.predict(vectorTest)
#print("分類返回結果爲%d\t真實結果爲%d" % (valTest, classNum))
print("file:", fileNameStr,"classNum:", classNum, "Test:", clf.predict(vectorTest))
if valTest != classNum:
errorCount += 1
print("總共錯了%d個數據\n錯誤率爲%f%%" % (errorCount, errorCount/mTest * 100))
# 載入模型並進行測試
def test_fd(fd_test):
clf = joblib.load(model_path + "svm_train_model.m")
test_svm = clf.predict(fd_test)
return test_svm
if __name__=="__main__":
train_SVM(99)
clf = joblib.load(model_path + "svm_train_model.m")
test_SVM(clf,99)
訓練後,結果測試:
三、完成訓練
運行myGUI.py
效果展示:
小結:
1、訓練樣本共1417張手勢圖片
2、食指超出攝像界面或是手臂出現在攝像界面中錯誤概率較大
3、運行GUI界面可能會出現“延遲卡頓”(鼠標點擊終端會更新識別狀態)