【开发日记】石头剪刀布之最终功能实现

在之前一篇文章——石头剪刀布之卷积神经网络,我已经定义了网络模型,当时在每类200张图片的情况下可以达到89%左右的精度。在本项目中,获取数据的成本并不是很高,利用摄像头就可以获得足够多的数据。因此,我又收集了一些数据,使得每类的图片大概是3000张左右。按照之前的训练方法,验证精度可以达到98.9%,识别一张图片的时间在25ms左右。这样的网络模型就可以满足要求。

有了训练好的模型(相当于一个大脑),有了摄像头(相当于眼睛),有了舵机(相当于手)。就可以把这些集成,来完成“石头剪刀布”这个游戏了。

以下是整个系统的连接图:


摄像头正对着背景板,放的位置和角度要尽可能和获取数据时的位置一样,这样识别精度更高。舵机和指针用来输出树莓派的计算结果。石头剪刀布的图片可以从网上下载,打印出来,粘贴上去。

通过在树莓派上运行以下代码,就可以实现石头剪刀布的功能了(rps.py)。

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf
import  numpy as np
import PIL.Image as Image
from pylab import *
import time
import cv2
import RPi.GPIO as GPIO
import signal
import atexit
# 舵机旋转的角度
def rotate(p, angle):
    p.ChangeDutyCycle(7.5+10*angle/180)
    time.sleep(1)
    p.ChangeDutyCycle(0)
# 石头剪刀布主程序
def rps(model_dir, classes, p):
    
    clicked = False  
    def onMouse(event, x, y, flags, param):  
        global clicked  
        if event == cv2.EVENT_LBUTTONUP:  
            clicked = True  
      
    cameraCapture = cv2.VideoCapture(0)
    cameraCapture.set(3, 100) # 帧宽度
    cameraCapture.set(4, 100) # 帧高度
    cv2.namedWindow('MyWindow')  
    cv2.setMouseCallback('MyWindow', onMouse)  
      
    print('showing camera feed. Click window or press and key to stop.')  
    success, frame = cameraCapture.read()  
    print(success)  
    count = 0
    flag = 0

    saver = tf.train.import_meta_graph(model_dir+".meta")
    with tf.Session() as sess:
        saver.restore(sess, model_dir)
        x = tf.get_default_graph().get_tensor_by_name("images:0")
        keep_prob = tf.get_default_graph().get_tensor_by_name("keep_prob:0")
        y = tf.get_default_graph().get_tensor_by_name("fc2/output:0")
        count=0
        while success and cv2.waitKey(1)==-1 and not clicked:
            time1 = time.time()
            cv2.imshow('MyWindow', frame)  
            success, frame = cameraCapture.read()
            img = Image.fromarray(frame)
            # 将图片转化成灰度并缩小尺寸
            img = array(img.convert('L').resize((28, 28)),dtype=float32)
            
            img = img.reshape((1,28*28))
            img = img/255.0 # 图像前处理
            prediction = sess.run(y, feed_dict={x:img,keep_prob: 1.0})
            
            index = np.argmax(prediction)
            probability = prediction[0][index]
            # 设置probability为0.8是为了提高识别稳定性
            if index==1 and flag!=1 and probability>0.8:
                  rotate(p, 30)
                  flag=1
            elif index==2 and flag!=2 and probability>0.8: 
                  rotate(p, 0)
                  flag = 2
            elif index==3 and flag!=3 and probability>0.8:
                  rotate(p, -30)
                  flag = 3
            time2 = time.time()
            if count%30==0:
              print(classes[index])
              
              print('using time: ', time2-time1)
           
              print('probability: %.3g' % probability)
            count+=1
          
        cv2.destroyWindow('MyWindow')  
        cameraCapture.release() 


if __name__=="__main__":
  classes = ['others','paper','rock','scissors']
  model_dir="model/model.ckpt"

  atexit.register(GPIO.cleanup)    
      
  servopin = 21

  GPIO.setmode(GPIO.BCM)  
  GPIO.setup(servopin, GPIO.OUT, initial=False)  
  p = GPIO.PWM(servopin,50) #50HZ  
  p.start(0)  
  time.sleep(2)

  rps(model_dir, classes, p)
  

运行以上代码,效果如下动画所示:


从效果上看,还是不错的。几乎看不到有延迟的现象,而且识别得很稳定。

终于从头到尾完成一个项目了,还是蛮有成就感的。春节过后,把这些整理成一个单一的文章。


版权声明:本文为Lauyeed原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。