手势识别首先想到两种方法, opencv计算hu, 神经网络图片分类
一. opencv计算hu
1. HU是什么?
一 原理
几何矩是由Hu(Visual pattern recognition by moment invariants)在1962年提出的,具有平移、旋转和尺度不变性。 定义如下:
① (p+q)阶不变矩定义:
② 对于数字图像,离散化,定义为:
③ 归一化中心矩定义:
④Hu矩定义
要点:
1. pq代表的是维度
2. 矩具有平移不变性(显然)
3. 均一化矩(与零维矩的比值)具有平移,旋转,缩放不变性
所以回到代码实现
首先提取手部信息,两种方法, 一是利用手的颜色提取,二是用手的轮廓提取. 手的颜色在相机中不稳定, 且容易提取到别的东西. 老方法: 二值化+图像形态学操作
frame = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
cv.threshold(frame, 120, 255, cv.THRESH_TOZERO, dst=frame)
# cv.threshold(frame, 100, 255, cv.THRESH_BINARY, dst=frame)
kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
cv.morphologyEx(frame, cv.MORPH_OPEN, kernal, dst=frame)
findContour,然后利用contour的面积进一步排除,最后调用矩对比函数(先前存好了参考图像)
contours, hierarchy = cv.findContours(frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
real_contours = []
contours_hu = []
for contour in contours:
contour_area = cv.contourArea(contour)
if contour_area < 13000 or contour_area > 45000:
pass
else:
real_contours.append(contour)
# print(contour_area)
for real_contour in real_contours:
s = cv.matchShapes(SCISSORS, real_contour, 1, 0.0)
r = cv.matchShapes(ROCK, real_contour, 1, 0.0)
p = cv.matchShapes(PAPER, real_contour, 1, 0.0)
if s < r and s < p:
print("SCISSORS")
if r < s and r < p:
print("ROCK")
if p < r and p < s:
print("PAPER")
矩在opencv中还有其他函数,但是原理大同小异.
矩对比, 模板匹配都可以实现图像分类的功能, 矩经过改造后也可以实现模板匹配的全部功能,可以说矩是一种高级的,抽象化,降维的模板匹配.
二. 神经网络
*从这里开始一堆破事开始出现了
- 首先想到的是tensorflow官方给出的基础教程
https://tensorflow.google.cn/tutorials/keras/classification
其中很简单的,用keras,设计了一个单层的全联通网络,在MNIST上效果很好.所以下意识的(偷懒),打算直接弄过来. 先是利用 glob模块, 和群里发布的数据集开始进行数据清理.
def getPictures():
paths = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\paper\\*")
paths1 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\rock\\*")
paths2 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\scissors\\*")
list_images = []
for path in paths:
# print(path)
src_image = cv.imread(path, -1)
list_images.append([1, src_image])
for path in paths1:
# print(path)
src_image = cv.imread(path, -1)
list_images.append([2, src_image])
for path in paths2:
# print(path)
src_image = cv.imread(path, -1)
list_images.append([3, src_image])
np.random.shuffle(list_images)
return list_images
文件的读取很顺利. 但是由于给的训练图像是绿幕图, 所以要进行一个抠图. 也没有怎么百度啥的, 简单的就像根据图像去扣, 效果惨不忍睹,另外一个就是findcontours里面的contour是顺着手内部的,这个问题我在另外一个车道检测的项目中也遇到过,需要设定roi区域, 但是没有找到能根治的方法, 深度学习这一部分问题太多了,还是先等有空了再去学一下把.
def aaaaaa():
image = src_image
image = src_image[:, :, 0] + src_image[:, :, 2]
cv.threshold(image, 170, 255, cv.THRESH_BINARY, dst=image)
kernel = cv.getStructuringElement(cv.MORPH_RECT, (57, 57))
cv.morphologyEx(image, cv.MORPH_DILATE, kernel, image)
kernel = cv.getStructuringElement(cv.MORPH_RECT, (37, 37))
cv.morphologyEx(image, cv.MORPH_ERODE, kernel, image)
low_hand_color = np.array([0, 0, 0])
high_hand_color = np.array([255, 150, 255])
mask = cv.inRange(image, low_hand_color, high_hand_color)
image = cv.bitwise_and(image, image, mask=mask)
contours, hierarchy = cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(src_image, contours, -1, [255, 0, 0], 3)
cv.imshow("process_frame", image)
cv.waitKey(0)
real_contours = []
contours_hu = []
for contour in contours:
contour_area = cv.contourArea(contour)
if contour_area < 13000 or contour_area > 45000:
pass
else:
real_contours.append(contour)
# print(contour_area)
self.contours = real_contours
(未完待续)
全部代码:
Opencv:
import cv2 as cv
import numpy as np
import sys
def Scissors_Rock_Paper():
scissors_frame = cv.imread("01.jpg")
scissors_frame = cv.cvtColor(scissors_frame, cv.COLOR_BGR2GRAY)
cv.threshold(scissors_frame, 100, 255, cv.THRESH_BINARY, dst=scissors_frame)
kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
cv.morphologyEx(scissors_frame, cv.MORPH_OPEN, kernal, dst=scissors_frame)
scissors_contours, his = cv.findContours(scissors_frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
SCISSORS = np.zeros(scissors_frame.shape)
cv.drawContours(SCISSORS, scissors_contours, -1, [255], 3)
# cv.imshow("SCISSORS", SCISSORS)
rock_frame = cv.imread("02.jpg")
rock_frame = cv.cvtColor(rock_frame, cv.COLOR_BGR2GRAY)
cv.threshold(rock_frame, 100, 255, cv.THRESH_BINARY, dst=rock_frame)
kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
cv.morphologyEx(rock_frame, cv.MORPH_OPEN, kernal, dst=rock_frame)
rock_contours, hir = cv.findContours(rock_frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
ROCK = np.zeros(rock_frame.shape)
cv.drawContours(ROCK, rock_contours, -1, [255], 3)
# cv.imshow("ROCK", ROCK)
paper_frame = cv.imread("03.jpg")
paper_frame = cv.cvtColor(paper_frame, cv.COLOR_BGR2GRAY)
cv.threshold(paper_frame, 100, 255, cv.THRESH_BINARY, dst=paper_frame)
kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
cv.morphologyEx(paper_frame, cv.MORPH_OPEN, kernal, dst=paper_frame)
paper_contours, hi = cv.findContours(paper_frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
PAPER = np.zeros(paper_frame.shape)
cv.drawContours(PAPER, paper_contours, -1, [255], 3)
# cv.imshow("PAPER", PAPER)
return scissors_contours[0], rock_contours[0], paper_contours[0]
SCISSORS, ROCK, PAPER = Scissors_Rock_Paper()
class Frame:
def __init__(self, path):
self.cap = cv.VideoCapture(path, cv.CAP_DSHOW)
def __call__(self, **kwargs):
self.ret, self.frame = self.cap.read()
if not self.ret:
raise Exception
else:
return self.frame
class Process:
def __call__(self, frame, **kwargs):
self.frame = np.copy(frame)
cv.GaussianBlur(frame, (3, 3), 0, dst=frame)
self.frame = frame
return self.frame
def draw_self_contours(self, frame):
cv.drawContours(frame, self.contours, -1, [255, 0, 0], 3)
return frame
# 相机曝光是自动的,同时环境曝光也是自动的,无法有效提取肉色,放弃
def get_hand_by_color(self):
frame = self.frame
low_hand_color = np.array([149, 136, 128])
high_hand_color = np.array([249, 236, 218])
mask = cv.inRange(frame, low_hand_color, high_hand_color)
self.frame = cv.bitwise_and(frame, frame, mask=mask)
return self.frame
def get_hand_by_findcontours(self):
frame = self.frame
frame = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
cv.threshold(frame, 120, 255, cv.THRESH_TOZERO, dst=frame)
# cv.threshold(frame, 100, 255, cv.THRESH_BINARY, dst=frame)
kernal = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
cv.morphologyEx(frame, cv.MORPH_OPEN, kernal, dst=frame)
contours, hierarchy = cv.findContours(frame, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
real_contours = []
contours_hu = []
for contour in contours:
contour_area = cv.contourArea(contour)
if contour_area < 13000 or contour_area > 45000:
pass
else:
real_contours.append(contour)
# print(contour_area)
for real_contour in real_contours:
s = cv.matchShapes(SCISSORS, real_contour, 1, 0.0)
r = cv.matchShapes(ROCK, real_contour, 1, 0.0)
p = cv.matchShapes(PAPER, real_contour, 1, 0.0)
if s < r and s < p:
print("SCISSORS")
if r < s and r < p:
print("ROCK")
if p < r and p < s:
print("PAPER")
self.contours = real_contours
return frame
# def decide_hand_meaning(self):
class_frame = Frame(0)
class_process = Process()
while True:
process_frame = class_frame()
class_process(process_frame)
cv.imshow("processing frame", class_process.get_hand_by_findcontours())
cv.imshow("input_frame", class_process.draw_self_contours(process_frame))
cv.waitKey(27)
tensorflow:
import tensorflow as tf
import keras
import cv2 as cv
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import glob
def get_picture(path, kind):
pictures_paths = glob.iglob(path)
pictures = []
for pictures_path in pictures_paths:
picture = cv.imread(pictures_path)
pictures.append([kind, picture])
return pictures
def getPictures():
paths = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\paper\\*")
paths1 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\rock\\*")
paths2 = glob.glob("E:\\03-project\\02-basketball\\01-handreconization\\pictures\\scissors\\*")
list_images = []
for path in paths:
# print(path)
src_image = cv.imread(path, -1)
list_images.append([1, src_image])
# image = src_image
#
# image = src_image[:, :, 0] + src_image[:, :, 2]
# cv.threshold(image, 170, 255, cv.THRESH_BINARY, dst=image)
#
# kernel = cv.getStructuringElement(cv.MORPH_RECT, (57, 57))
# cv.morphologyEx(image, cv.MORPH_DILATE, kernel, image)
# kernel = cv.getStructuringElement(cv.MORPH_RECT, (37, 37))
# cv.morphologyEx(image, cv.MORPH_ERODE, kernel, image)
# low_hand_color = np.array([0, 0, 0])
# high_hand_color = np.array([255, 150, 255])
# mask = cv.inRange(image, low_hand_color, high_hand_color)
# image = cv.bitwise_and(image, image, mask=mask)
#
# contours, hierarchy = cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# cv.drawContours(src_image, contours, -1, [255, 0, 0], 3)
#
# cv.imshow("process_frame", image)
# cv.waitKey(0)
# real_contours = []
# contours_hu = []
# for contour in contours:
# contour_area = cv.contourArea(contour)
# if contour_area < 13000 or contour_area > 45000:
# pass
# else:
# real_contours.append(contour)
# # print(contour_area)
#
# for real_contour in real_contours:
# s = cv.matchShapes(SCISSORS, real_contour, 1, 0.0)
# r = cv.matchShapes(ROCK, real_contour, 1, 0.0)
# p = cv.matchShapes(PAPER, real_contour, 1, 0.0)
# if s < r and s < p:
# print("SCISSORS")
# if r < s and r < p:
# print("ROCK")
# if p < r and p < s:
# print("PAPER")
#
# self.contours = real_contours
for path in paths1:
# print(path)
src_image = cv.imread(path, -1)
list_images.append([2, src_image])
for path in paths2:
# print(path)
src_image = cv.imread(path, -1)
list_images.append([3, src_image])
np.random.shuffle(list_images)
return list_images
TRAIN_DATA = getPictures()
train_images = []
train_index = []
for data in TRAIN_DATA:
train_images.append(data[1])
train_index.append(data[0])
# cv.imshow("data", data[1])
# print(data[0])
# cv.waitKey(0)
model = keras.Sequential([
keras.layers.Flatten(input_shape=(300, 200)),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dense(10)
])
model.compile(optimizer='adam',
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(train_images, train_index, epochs=30)
test_loss, test_acc = model.evaluate(train_images, train_index, verbose=2)
print("TEST accuracy:", test_acc)
SCISSOR_PICTURES = get_picture("", 0)
ROCK_PICTURES = get_picture("", 1)
PAPER_PICTURES = get_picture("", 2)