python手勢識別上下左右(SVM+HOG特徵)

項目環境: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界面可能會出現“延遲卡頓”(鼠標點擊終端會更新識別狀態)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章