使用 python3+OpenCV+TensorFlow 做手势识別

Posted illusioned

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 python3+OpenCV+TensorFlow 做手势识別相关的知识,希望对你有一定的参考价值。

本文很大程度的参考了知乎大大的文章:

<使用 python3+OpenCV+TensorFlow 做手势识別> 

原文链接:https://zhuanlan.zhihu.com/p/56699632

 

说明:

由于原文章是一年前的内容,有些内容已经不适用,存在比较多坑点,在此重新做下注解和补充;

该文章觉得非常适合初学小白入门,用来练手实践,体验人工“智障”的乐趣;

所以在此花了几天时间特意整理了内容,希望能给看博客的你,种又白嫖了的快感~

 

一、环境配置

1、Anaconda3 下载

Windows 用户,强烈建议使用 Anaconda3  的Python 虚拟环境来安装tensorflow;

出问题或者啥不顺心或突然暴躁的,完完全全可以直接干掉环境重新再来;谁还不是个宝宝呢~(`へ´*)ノ~

官网:https://www.anaconda.com/distribution/

Anaconda3 都支持3.7 了,直接安装最新版本,下载 Python 3.7 version;

 

2、Anaconda3

 建议安装在D盘,D:\\Anaconda3 下,下面就可以开启 CTRL+C 、CTRL+V无脑模式;

 

3、环境变量配置;例如:安装在D盘目录下;

D:\\Anaconda3\\Scripts
D:\\Anaconda3\\Library\\bin
D:\\Anaconda3\\Scripts
D:\\Anaconda3\\

4、 win+R 打开cmd,检查安装结果;

① 检测anaconda环境是否安装成功:conda --version

② 检测目前安装了哪些环境变量:conda info --envs

③ 查看当前有哪些可以使用的tensorflow版本:conda search --full --name tensorflow、

④ 查看tensorflow包信息及依赖关系:conda info tensorflow

如图demo:

 

二、tensorflow安装与模块导入

1、安装Git

官网下载安装:https://gitforwindows.org/

默认安装,安装完成后配置环境变量;

 

2、下载模块 (注:此处要与对应发tensorflow 版本一致,此次demo主要以tensorflow1.12.0版本演示)

git clone -b r1.12.0 https://github.com/tensorflow/models.git   D:/tensorflow/models

---大概600Mb 左右,漫长的等待……

##注意,使用其他tensorflow 版本的同学,记得下载的模块版本分支要与tensorflow版本一致;否则会出现很多奇奇怪怪的问题;

##例如:代码v1、v2 啥1.x 和2.x 不兼容问题,concat函数啥啥啥写法不兼容问题;

 

3、Python虚拟环境的搭建

进入windows命令模式,创建TensorFlow env环境;

由于该教程演示是用tensorflow1.12 做的,在此,直接把虚拟环境名称命名为tensorflow1.12

安装python3.6: conda  create  --name  tensorflow1.12  python=3.6

删除python3.6: conda  remove  --name tensorflow1.12  --all

 

激活tensorflow1.12环境: activate tensorflow1.12   

退出tensorflow1.12环境: deactivate

 

4、安装tensorflow与opencv包

① tensorflow包的安装

1)激活tensflow的tfenv环境:

activate tensorflow1.12

2)安装tensorflow1.12 :

pip install --upgrade --ignore-installed tensorflow==1.12.0

3)验证功能正常:python 进入代码环境

import tensorflow as tf
hello = tf.constant(\'hello,tf\')
sess = tf.Session()
print(sess.run(hello))
常见报错问题总结:
A、tensorflow import 失败报错问题 温馨提示:如果你的conda和tensorflow环境都是安装成功的,但是一用测试代码进行跑的时候就出问题了,那么注意,这个原因你由于你在安装tensorflow的时候,是直接在cmd下,而不是在你用conda激活的一个环境,所以导致,tensorflow并没有直接嵌入到conda环境,所以,就导致无法导入模块的一个错误; 解决方法: (1)只需要在activate tensorflow1.12 (2)然后再使用 pip install --upgrade --ignore-installed tensorflow==1.12.0命令安装就可以了 B、FutureWarning: Passing (type, 1) 报错问题 使用TensorFlow时报错FutureWarning: Passing (type, 1) or \'1type\' as a synonym of type is deprecated; in a future version of numpy....... 报错原因:numpy1-17-0版本过高,使用numpy-1.16-0版本即可 解决方法:重新安装numpy-1.16-0 pip install numpy==1.16.0 C、 CPU 指令集报错问题 使用TensorFlow模块时,弹出错误Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2 有两种解决办法: 1.忽略这个警告,不看它! import os os.environ["TF_CPP_MIN_LOG_LEVEL"]=\'1\' # 这是默认的显示等级,显示所有信息 os.environ["TF_CPP_MIN_LOG_LEVEL"]=\'2\' # 只显示 warning 和 Error os.environ["TF_CPP_MIN_LOG_LEVEL"]=\'3\' # 只显示 Error 我们用第二个就可以了。 2.彻底解决,换成支持cpu用AVX2编译的TensorFlow版本。 首先,卸载原来版本的TensorFlow EG:pip install tensorflow-1.6.0-cp36-cp36m-win_amd64.whl 参考:https://github.com/fo40225/tensorflow-windows-wheel

  

 5、模块安装

首先把需要使用的模块安装好

python -m pip install opencv-python
python -m pip install Cython
python -m pip install contextlib2
python -m pip install pillow
python -m pip install lxml
python -m pip install jupyter
python -m pip install matplotlib

 

6、tensorflow object detection API 框架搭建

① protoc 下载

链接:https://pan.baidu.com/s/19xzP6_x5Ru5y_qra3wtakA

提取码:nf6n

 

② 使用protoc生成python文件

然后win+R→cmd→

C:\\>cd /d D:\\tensorflow\\models\\research

D:\\tensorflow\\models\\research>D:/tensorflow/protoc-3.4.0-win32/bin/protoc object_detection/protos/*.proto --python_out=.

 

③ API测试准备

找到python的安装路径,我的虚拟环境路径:D:\\Anaconda3\\envs\\tensorflow1.12\\Lib\\site-packages;

在该文件夹下新建一个txt文件,打开该txt文件,输入以下三条路径

D:\\tensorflow\\models\\research
D:\\tensorflow\\models\\research\\slim
D:\\tensorflow\\models\\research\\object_detection

将该文件命名为tensorflow_model.pth储存即可。

 

④ API测试

回到cmd,输入

cd  /d  D:\\tensorflow\\models\\research

python object_detection/builders/model_builder_test.py

##得到ok,测试成功!此时tensorflow object detection API 框架搭建完成。

 

三、手势数据的收集与标注
1、数据收集
① 提前工作
     在D盘tensorflow目录下,创建一个文件夹,命名为hand_data;在hand_data里创建一个文件夹,命名为VOC2012(注意:该名称必须为VOC2012);在VOC2012文件夹下创建3个文件夹,分别命名为Annotations,ImageSets,JPEGImages(注意:该名称必须为Annotations,ImageSets,JPEGImages); 在ImageSets文件夹内创建Main文件夹。

回到cmd,输入

md  d:\\tensorflow\\hand_data\\VOC2012\\Annotations
md  d:\\tensorflow\\hand_data\\VOC2012\\ImageSets
md  d:\\tensorflow\\hand_data\\VOC2012\\JPEGImages\\Main

 

② 使用摄像头+opencv收集数据

以下代码设定的为每5帧保存一次,可以修改,保存地址为VOC2012文件夹下的JPEGImages文件夹内,每种手势收集1000张图片最佳。

import cv2 as cv
import numpy as np

capture = cv.VideoCapture(0)
index = 1
while True:
    ret, frame = capture.read()
    if ret is True:
        cv.imshow("frame", frame)
        index += 1
        if index % 5 == 0:
            cv.imwrite("D:/tensorflow/hand_data/VOC2012/JPEGImages/" + str(index) + ".jpg", frame)
        c = cv.waitKey(50)
        if c == 27: # 退出命令键盘 Esc
            break
    else:
        break

cv.destroyAllWindows()

首先删除不清晰的图片,因为收集到的图片的序号不是按照顺序排的,因此需要排好序再标注。在JPEGImages文件夹内新建一个txt文件,把以下代码copy进去,命名为.bat文件,保存好,再运行一下,图片名就会按照顺序排列好了。

@echo off
set a=0
setlocal EnableDelayedExpansion
dir /b .\\*.jpg | find /c /v "" >> .\\tmp.txt
set /p c=<.\\tmp.txt
del /a /f /q .\\tmp.txt 
 
for %%i in (*.jpg) do (
set /a a+=1
if !a! gtr %c% (goto aa)
echo !a!
echo %%i 
ren "%%i" "!a!.jpg"
)
:aa
pause

 

2、数据标注
①  labelImg下载
百度云盘链接:https://pan.baidu.com/s/1Ros4T5c-m401urzt_NdVNw   提取码:xdiz

 

② 添加标签

下载解压完成后打开

 

本文对三个手势进行标注,在该txt文件中添加了三个标签

把储存照片的JPEGImages文件夹路径设置好:

 

 路径都设置好以后,再按下W即可对图片标注。

 标注好位置后,点击save进行保存。(快捷方式为两次空格键)(也可以按一次空格键,全部标注完以后,检查时再按一次空格键方便检查,会有绿色和白色的背景色提醒,白色为最终确认的颜色)

然后点击Next Image 对下一张图片进行数据标注。(快捷方式为D)

想返回上一张查看的话,可以点击Prev Image。(快捷方式为A)

重复上述工作至全部标注完成即可。数据标注工作枯燥无味,如果一次未能全部标注完,关闭后下一次可以继续标注。

 

③ xml文件的修改

之前标注好的数据会保存在.xml文件中,但是格式并不完全正确。下面红色方框内的内容必须要改成如下形式即可。

上千个.xml文件,手动改是不可能手动改的。用下面的python代码可以遍历全部文件进行更改,并且在Main文件夹内保存对应的txt文件。

import cv2 as cv
import os
from xml.dom import minidom
import xml.etree.ElementTree as ET

root_dir = "D:/tensorflow/hand_data/VOC2012/JPEGImages/"

def xml_modification():
    ann_dir = "D:/tensorflow/hand_data/VOC2012/Annotations/"
    files = os.listdir(ann_dir)
    for xml_file in files:
        if os.path.isfile(os.path.join(ann_dir, xml_file)):
            xml_path = os.path.join(ann_dir, xml_file)
            tree = ET.parse(xml_path)
            root = tree.getroot()
# changing a field text for elem in root.iter(\'folder\'): elem.text = \'voc2012\' for elem in root.iter(\'name\'): name = elem.text elem.text = name.replace(" ", "") tree.write(xml_path) print("processed xml : %s" % (xml_path)) def generate_classes_text(): print("start to generate classes text...") ann_dir = "D:/tensorflow/hand_data/VOC2012/Annotations/" okay_train = open("D:/tensorflow/hand_data/VOC2012/ImageSets/Main/Okay_train.txt", \'w\') okay_val = open("D:/tensorflow/hand_data/VOC2012/ImageSets/Main/Okay_val.txt", \'w\') good_train = open("D:/tensorflow/hand_data/VOC2012/ImageSets/Main/Good_train.txt", \'w\') good_val = open("D:/tensorflow/hand_data/VOC2012/ImageSets/Main/Good_val.txt", \'w\') v_train = open("D:/tensorflow/hand_data/VOC2012/ImageSets/Main/V_train.txt", \'w\') v_val = open("D:/tensorflow/hand_data/VOC2012/ImageSets/Main/V_val.txt", \'w\') files = os.listdir(ann_dir) for xml_file in files: if os.path.isfile(os.path.join(ann_dir, xml_file)): xml_path = os.path.join(ann_dir, xml_file) tree = ET.parse(xml_path) root = tree.getroot() for elem in root.iter(\'filename\'): filename = elem.text for elem in root.iter(\'name\'): name = elem.text if name == "Okay": okay_train.write(filename.replace(".jpg", " ") + str(1) + "\\n") okay_val.write(filename.replace(".jpg", " ") + str(1) + "\\n") good_train.write(filename.replace(".jpg", " ") + str(-1) + "\\n") good_val.write(filename.replace(".jpg", " ") + str(-1) + "\\n") v_train.write(filename.replace(".jpg", " ") + str(-1) + "\\n") v_val.write(filename.replace(".jpg", " ") + str(-1) + "\\n") if name == "V": okay_train.write(filename.replace(".jpg", " ") + str(-1) + "\\n") okay_val.write(filename.replace(".jpg", " ") + str(-1) + "\\n") good_train.write(filename.replace(".jpg", " ") + str(-1) + "\\n") good_val.write(filename.replace(".jpg", " ") + str(-1) + "\\n") v_train.write(filename.replace(".jpg", " ") + str(1) + "\\n") v_val.write(filename.replace(".jpg", " ") + str(1) + "\\n") if name == "Good": okay_train.write(filename.replace(".jpg", " ") + str(-1) + "\\n") okay_val.write(filename.replace(".jpg", " ") + str(-1) + "\\n") good_train.write(filename.replace(".jpg", " ") + str(1) + "\\n") good_val.write(filename.replace(".jpg", " ") + str(1) + "\\n") v_train.write(filename.replace(".jpg", " ") + str(-1) + "\\n") v_val.write(filename.replace(".jpg", " ") + str(-1) + "\\n") okay_train.close() okay_val.close() v_train.close() v_val.close() good_train.close() good_val.close() xml_modification() #generate_classes_text()

成功运行上面python代码后,得到以下txt文件。

 对得到的txt文件进行说明:第一列为图片的名称,第二列为图片的结果,-1代表不是,1代表是。

 

 至此,VOC2012数据集制作完成。

 

④ tf.record数据的生成
在tensorflow文件夹下新建一个文件夹,命名为hand_set,在hand_set文件夹下新建三个文件夹,分别命名为data,export,model。

md  d:\\tensorflow\\hand_set\\data
md  d:\\tensorflow\\hand_set\\export
md  d:\\tensorflow\\hand_set\\model

在model文件夹下新建eval和train文件夹。

md  d:\\tensorflow\\hand_set\\model\\eval
md  d:\\tensorflow\\hand_set\\model\\train

在hand_data文件夹里新建一个txt文件,命名为hand_label_map.pbtxt,

 在D:\\tensorflow\\models\\research\\object_detection\\data中找打一个叫pet_label_map.pbtxt的文件打开,

 复制全部内容后,粘贴到hand_label_map.pbtxt中,并把name: \' \' 内的内容修改为需要修改的内容,

保存好,.pbtxt文件制作完成。

在D:\\tensorflow\\models\\research\\object_detection\\dataset_tools中找到create_pascal_tf_record.py文件并打开,在165行更改成如下形式,和D:\\tensorflow\\hand_data\\VOC2012\\ImageSets\\Main中的一个txt文件保持一致即可。

 

 

接下来,win+R→cmd→

C:\\>cd /d D:\\tensorflow\\models\\research

D:\\tensorflow\\models\\research>python object_detection/dataset_tools/create_pascal_tf_record.py --label_map_path=D:/tensorflow/hand_data/hand_label_map.pbtxt --data_dir=D:\\tensorflow\\hand_data --year=VOC2012 --set=train --output_path=D:\\tensorflow\\hand_set\\data\\pascal_train.record

注意:期间可能会遇到个报错 TypeError:can’t pickle dict_values objects.

解决办法:https://blog.csdn.net/sy20173081277/article/details/84311730

 运行生成record文件,并把之前做好的hand_label_map.pbtxt文件一并放到该文件夹下。

 

⑤ 预训练模型的选择

打开https://github.com/tensorflow/models/tree/master/research/object_detection

找到model zoo,在这里面有各种各样的模型。

我们选择下面这个模型,从Speed中可以看到模型的速度。有兴趣的也可以尝试其他的模型。点击下载到D:\\tensorflow。

config文件的配置
在D:\\tensorflow\\models\\research\\object_detection\\samples\\configs中找到ssd_mobilenet_v1_pets.config文件。复制粘贴到D:\\tensorflow\\handset\\model中。

打开ssd_mobilenet_v1_pets.config,把第9行的数字修改为需要分类的类别数

 

路径修改(注意反斜杠和斜杆的问题):

fine_tune_checkpoint 后的路径改为 ssd_mobilenet_v1_pets.config 的路径;

train_input_reader下的 input_path 后的路径改为 pascal_train.record 的路径,label_map_path后的路径改为 hand_label_map.pbtxt 的路径;

eval_input_reader下的路径同上。

 

 模型训练
首先在cmd中执行下面的命令

pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI

##注:该命令时间稍长,建议等待;自己下载git文件,编译会出现vc2014 等待系列依赖问题;我之前就是在这里栽了,各种恶心抓狂的开端;

然后在cmd中执行

C:\\>cd /d D:\\tensorflow\\models\\research

D:\\tensorflow\\models\\research>python object_detection/model_main.py --pipeline_config_path=D:/tensorflow/hand_set/model/ssd_mobilenet_v1_pets.config --model_dir=D:\\tensorflow\\hand_set\\model\\train --num_train_steps=200 --num_eval_steps=5 --alsologtostderr
即可开始训练,因为tensorflow是CPU版本的,所以训练时间比较长。至少五到六个小时;

 

⑥ 训练过程查看

C:\\>cd\\
C:\\>tensorboard --logdir=D:\\tensorflow\\handset\\model\\train --host=127.0.0.1

得到http://127.0.0.1:6006,在浏览器中打开,即可看到过程参数,识别图像等,都可以自己尝试点击看看。

 

⑦ 数据模型导出

在cmd中输入

C:\\>cd /d D:\\tensorflow\\models\\research

D:\\tensorflow\\models\\research>python object_detection/export_inference_graph.py --input_type=image_tensor --pipeline_config_path=D:\\tensorflow\\hand_set\\model\\ssd_mobilenet_v1_pets.config --trained_checkpoint_prefix=D:\\tensorflow\\hand_set\\model\\train\\model.ckpt-200 --output_directory=D:\\tensorflow\\hand_set\\export
即可导出数据,在D:\\tensorflow\\handset\\export中可以看到导出的模型。

⑧ 实时手势识别

# -*- coding: utf-8 -*-
"""
Created on Mon Mar 16 09:23:06 2020

@author: illusioned.zhy
"""

import os
import sys
import tarfile

import cv2 as cv
import numpy as np
import tensorflow as tf

from utils import label_map_util
from utils import visualization_utils as vis_util


# Path to frozen detection graph. This is the actual model that is used for the object detection.
PATH_TO_FROZEN_GRAPH = \'D:/tensorflow/hand_set/export/frozen_inference_graph.pb\'

# List of the strings that is used to add correct label for each box.
PATH_TO_LABELS = os.path.join(\'D:/tensorflow/hand_set/data\', \'hand_label_map.pbtxt\')

NUM_CLASSES = 3
detection_graph = tf.Graph()
capture = cv.VideoCapture(0)
with detection_graph.as_default():
    od_graph_def = tf.GraphDef()
    with tf.gfile.GFile(PATH_TO_FROZEN_GRAPH, \'rb\') as fid:
        serialized_graph = fid.read()
        od_graph_def.ParseFromString(serialized_graph)
        tf.import_graph_def(od_graph_def, name=\'\')

label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categorys = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categorys)


with detection_graph.as_default():
    with tf.Session(graph=detection_graph) as sess:
        while  True:
            ret, image = capture.read()
            if ret is True:
                image_np_expanded = np.expand_dims(image, axis=0)
                image_tensor = detection_graph.get_tensor_by_name(\'image_tensor:0\')
                boxes = detection_graph.get_tensor_by_name(\'detection_boxes:0\')
                scores = detection_graph.get_tensor_by_name(\'detection_scores:0\')
                classes = detection_graph.get_tensor_by_name(\'detection_classes:0\')
                num_detections = detection_graph.get_tensor_by_name(\'num_detections:0\')

                (boxes,scores,classes,num_detections)=sess.run([boxes, scores, classes, num_detections],
                                                                feed_dict={image_tensor: image_np_expanded})
                vis_util.visualize_boxes_and_labels_on_image_array(
                    image,
                    np.squeeze(boxes),
                    np.squeeze(classes).astype(np.int32),
                    np.squeeze(scores),
                    category_index,
                    min_score_thresh=0.5, #置信度,默认为0.5
                    use_normalized_coordinates=True,
                    line_thickness=4
                )
                c = cv.waitKey(5)
                if c == 27:  # ESC
                    break
                cv.imshow("Hand Gesture Demo", image)
            else:
                break
        cv.waitKey(0)
        cv.destoryAllWindows()

注意要把路径写对。

大功告成!

后面描述不清楚的地方,可以参考回原文 https://zhuanlan.zhihu.com/p/56699632

最后,附一张用20张图片标注生成的图片:

2020 疫情期间,带着口罩上班;=_=!! 明明是V,这准确度和人工"智障"!!!自己把自己笑死~~~

 

以上是关于使用 python3+OpenCV+TensorFlow 做手势识別的主要内容,如果未能解决你的问题,请参考以下文章

使用 python3+OpenCV+TensorFlow 做手势识別

Anaconda默认Python3.8版本创建Python3.6版本环境并安装opencv3.4.1.15,使用pycharm作为IDE

我使用 python3.5 和 OpenCV 3.1.0,OpenCV 函数 cv2.countNonZero(img) 我得到一个错误 [重复]

在python3下使用OpenCV 抓取摄像头图像并实时显示3色直方图

python3.6怎么使用opencv

Python3 识别验证码(opencv-python)