精华内容
下载资源
问答
  • 基于树莓派的深度学习网络手势识别系统.pdf
  • 文章目录 目录 一、材料 二、环境配置 ...1.树莓派(我用的是树莓派4b) 2.摄像头(我用的是csi摄像头,因为csi摄像头比普通usb摄像头占用cpu资源少) 3.THB6128步进电机驱动 步进电机驱动说明

    文章目录

    目录

    一、材料

    二、环境配置

    1.树莓派烧录系统

    2.安装相关库

    三、申请百度AI开放平台的id和密钥

    1.创建应用

    2.获取自己的ID以及密钥

    四、接线

    1.步进电机与步进电机驱动接线以及电机供电

    2.树莓派GPIO口与步进电机驱动接线

    五、树莓派python代码


    一、材料

    1.树莓派(我用的是树莓派4b)

    2.摄像头(我用的是csi摄像头,因为csi摄像头比普通usb摄像头占用cpu资源少)

    3.THB6128步进电机驱动

    步进电机驱动说明

    4.两相四线步进电机



    二、环境配置



    1.树莓派烧录系统

    这里建议烧录NOOBS或Raspbian等官方推荐的系统,而不是Ubuntu、Windows等。我之前就是烧录了Ubuntu的系统,然后就一堆bug,大多数是系统引起的,因为树莓派官方系统里面有很多适用于树莓派的库和一些硬件驱动。

    2.安装相关库

    树莓派官方推荐的系统是自带python环境的,如果没有可以自己再下载。

    然后安装百度api的库

    pip install baidu-aip这里我们用的是百度AI开放平台,进行在线手势识别
    

    三、申请百度AI开放平台的id和密钥

    1.创建应用

    2.获取自己的ID以及密钥

    用自己的APP_ID、KEY替换代码里的。

    百度AI开放平台每个月会有免费调用的次数便于开发者开发(足够开发使用),我这里就不分享我的APP_ID了哈。

    """ 你的 APPID AK SK """
    APP_ID = '*********'
    API_KEY = '*************'
    SECRET_KEY = '*******************'
    ''' 调用'''

    四、接线

    1.步进电机与步进电机驱动接线以及电机供电

    可以参考我的另一篇博客--》》步进电机与步进电机驱动接线https://blog.csdn.net/qq_48535429/article/details/120198962?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163127332516780357245667%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163127332516780357245667&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-5-120198962.pc_v2_rank_blog_default&utm_term=openmv%E6%AD%A5%E8%BF%9B%E7%94%B5%E6%9C%BA&spm=1018.2226.3001.4450https://blog.csdn.net/qq_48535429/article/details/120198962?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163127332516780357245667%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163127332516780357245667&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-5-120198962.pc_v2_rank_blog_default&utm_term=openmv%E6%AD%A5%E8%BF%9B%E7%94%B5%E6%9C%BA&spm=1018.2226.3001.4450

    2.树莓派GPIO口与步进电机驱动接线

    和上篇博客差不多,只不过这里我把openmv换成了树莓派,这里我将CP+-分别连接树莓派的pin16(GPIO23)、pin18(GPIO24),DIR+-分别接pin13(GPIO27)、pin15(GPIO22)。

    五、树莓派python代码

    最后上代码啦。

    import os
    import cv2
    from aip import AipBodyAnalysis
    from aip import AipSpeech
    from threading import Thread
    import time
    from playsound import playsound
    
    import serial
    import RPi.GPIO as GPIO
    
    
    
    """ 你的 APPID AK SK """
    APP_ID = '23*****2'
    API_KEY = 'mdSOHU1Vq******0zDsiuUMY'
    SECRET_KEY = 'yeKL9o3TPWNrrl******qPuhLZ116Hwc'
    ''' 调用'''
    
    IN1=18
    IN2=16
    IN3=15
    IN4=13
    
    hand = {'One': '数字1', 'Five': '数字5', 'Fist': '拳头', 'Ok': 'OK',
            'Prayer': '祈祷', 'Congratulation': '作揖', 'Honour': '作别',
            'Heart_single': '比心心', 'Thumb_up': '点赞', 'Thumb_down': 'Diss',
            'ILY': '我爱你', 'Palm_up': '掌心向上', 'Heart_1': '双手比心1',
            'Heart_2': '双手比心2', 'Heart_3': '双手比心3', 'Two': '数字2',
            'Three': '数字3', 'Four': '数字4', 'Six': '数字6', 'Seven': '数字7',
            'Eight': '数字8', 'Nine': '数字9', 'Rock': 'Rock', 'Insult': '竖中指', 'Face': '脸'}
    
    # 语音合成
    client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
    
    # 手势识别
    gesture_client = AipBodyAnalysis(APP_ID, API_KEY, SECRET_KEY)
    
    capture = cv2.VideoCapture(0)  # 0为默认摄像头
    
    
    def camera():
        while True:
            # 获得图片
            ret, frame = capture.read()
            # cv2.imshow(窗口名称, 窗口显示的图像)
            # 显示图片
            frame=cv2.flip(frame,1)
            cv2.imshow('frame', frame)
            if cv2.waitKey(1) == ord('q'):
                break
    
    
    Thread(target=camera).start()  # 引入线程防止在识别的时候卡死
    
    
    def gesture_recognition():
        # 第一个参数ret 为True 或者False,代表有没有读取到图片
    
        # 第二个参数frame表示截取到一帧的图片
        floor=0
        while True:
            try:
                ret, frame = capture.read()
    
                # 图片格式转换
                image = cv2.imencode('.jpeg', frame)[1]
    
                gesture = gesture_client.gesture(image)  # AipBodyAnalysis内部函数
                words = gesture['result'][0]['classname']
    
                voice(hand[words])
                print(hand[words])
                print(words)
                print(floor)
                if words=='One'and floor==0:
                    forward(0.0001,1000)
                    floor=1
                    print("first floor")
                if words=='Two'and floor==0:
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    floor=2
                if words=='Three'and floor==0:
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    floor=3
                if words=='Four'and floor==0:
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    floor=4
                if words=='Two'and floor==1:
                    forward(0.0001,1000)
                    floor=2
                if words=='Three'and floor==1:
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    floor=3 
                if words=='Four'and floor==1:
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    floor=4
                if words=='One'and floor==2:
                    backward(0.0001,1000)
                    floor=1
                if words=='Three'and floor==2:
                    forward(0.0001,1000)
                    floor=3
                if words=='Four'and floor==2:
                    forward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    forward(0.0001,1000)
                    floor=4
                if words=='One'and floor==3:
                    backward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    backward(0.0001,1000)
                    floor=1
                if words=='Two'and floor==3:
                    backward(0.0001,1000)
                    floor=2
                if words=='Four'and floor==3:
                    forward(0.0001,1000)
                    floor=4
                if words=='One'and floor==4:
                    backward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    backward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    backward(0.0001,1000)
                    floor=1
                if words=='Two'and floor==4:
                    backward(0.0001,1000)
                    stop()
                    time.sleep(3)
                    backward(0.0001,1000)
                    floor=2
                if words=='Three'and floor==4:
                    backward(0.0001,1000)
                    floor=3
    
    
    
            except:
                voice('识别失败')
            if cv2.waitKey(1) == ord('q'):
                break
    
    
    def voice(words):
        # 语音函数
        result = client.synthesis(words, 'zh', 1, {
            'vol': 5,
        })
        if not isinstance(result, dict):
            with open('./res.mp3', 'wb') as f:
                f.write(result)
                f.close()
            playsound('./res.mp3')
    
    def setStep(W1,W2,W3,W4):
        GPIO.output(IN1,W1)
        GPIO.output(IN2,W2)
        GPIO.output(IN3,W3)
        GPIO.output(IN4,W4)
        
    def stop():
        setStep(0,0,0,0)
        
    def forward (delay,steps):
        for i in range (0,steps):
            setStep(1,0,1,0)
            time.sleep(delay)
            setStep(0,1,1,0)
            time.sleep(delay)
            setStep(0,1,0,1)
            time.sleep(delay)
            setStep(1,0,0,1)
            time.sleep(delay)
    
    
    def backward (delay,steps):
        for i in range (0,steps):
            setStep(1,0,0,1)
            time.sleep(delay)
            setStep(0,1,0,1)
            time.sleep(delay)
            setStep(0,1,1,0)
            time.sleep(delay)
            setStep(1,0,1,0)
            time.sleep(delay)
            
    def setup():
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(IN1,GPIO.OUT)
        GPIO.setup(IN2,GPIO.OUT)
        GPIO.setup(IN3,GPIO.OUT)
        GPIO.setup(IN4,GPIO.OUT)
     
    def destory():
        GPIO.cleanup()
    
    
    
    
    if __name__=='__main__':
        
        setup()
        try:
           gesture_recognition()
        except KeyboardInterrupt:
            destroy()
    
    



    总结

    为了方便观察现象,我采用了电机分段转动的形式,即0楼去四楼电机正向转动四次,四楼去1楼电机反向转动三次。(每次转动角度一样)

    展开全文
  • 文章目录前言一、树莓派引脚介绍1.1引脚设置二、代码书写2.1引入库2.2示例代码点亮led 响蜂鸣器三完整代码 图片 前言 材料:树莓派 摄像头 SG90舵机两个 PCA9685拓展板 led小灯 蜂鸣器模块 一、树莓派引脚介绍 ...


    前言

    材料:树莓派 摄像头 SG90舵机两个 PCA9685拓展板 led小灯 蜂鸣器模块


    一、树莓派引脚介绍

    树莓派引脚对照表
    在这里插入图片描述
    可以看到一共有三种定义方式 分别是Wiring Pi编码,BCM编码和BOARD物理引脚编码。

    1.1引脚设置

    在最开始终端输入

    sudo raspi-config
    

    进入设置 后找到

    Interfacing Options
    

    进入 找到

    Remote GPIO
    

    开启GPIO

    二、代码书写

    2.1引入库

    在最开始导入库

    import RPi.GPIO as GPIO #1导入引脚库
    
    GPIO.setmode(GPIO.BOARD) # 2定义引脚方式 此处为BOARD编码
    GPIO.setup(channel, GPIO.OUT) # 3建立通道 该函数需要两个参数 第一个为引脚编号 第二个为模式定义
    #此处为输出
    GPIO.output(7, True)#4 驱动通道 
    GPIO.cleanup()#5清除 释放资源 
    
    

    2.2示例代码点亮led 响蜂鸣器

    #导入gpio模块 调用引脚
    import RPi.GPIO as GPIO
    
    #初始化引脚模式为BOARD 屏蔽警告
    GPIO.setmode(GPIO.BOARD)
    GPIO.setwarnings(False)
    
    #引脚定义 蜂鸣器接的35引脚 led接的37引脚
    beep=35
    led=37
    GPIO.setup(beep,GPIO.OUT)#设置gpio模式为输出
    GPIO.setup(led,GPIO.OUT)
    
     GPIO.output(led,GPIO.HIGH)#开灯
     GPIO.output(led,GPIO.LOW)#关灯
      GPIO.output(beep,GPIO.HIGH)#蜂鸣器响
      GPIO.output(beep,GPIO.LOW)#蜂鸣器关
    

    三完整代码 图片

    #!/usr/bin/env python2
    # -*- coding: utf-8 -*-
    """
    * @par Copyright (C): 2010-2020, hunan CLB Tech
    * @file         50_Hand_gestures.py
    * @version      V2.0
    * @details
    * @par History
    
    @author: zhulin
    """
    import cv2
    import numpy as np
    import math
    import time
    
    import sys
    import Adafruit_PCA9685#导入PCA9685模块
    
    #设置编码为utf-8
    import importlib
    importlib.reload(sys)
    #sys.setdefaultencoding('utf8')
    
    #导入gpio模块 调用引脚
    import RPi.GPIO as GPIO
    
    #初始化引脚模式为BOARD 屏蔽警告
    GPIO.setmode(GPIO.BOARD)
    GPIO.setwarnings(False)
    
    #引脚定义 蜂鸣器接的35引脚 led接的37引脚
    beep=35
    led=37
    GPIO.setup(beep,GPIO.OUT)#设置gpio模式为输出
    GPIO.setup(led,GPIO.OUT)
    
    
    
    #初始化PCA9685和舵机
    servo_pwm = Adafruit_PCA9685.PCA9685()  # 实例话舵机云台
    
    # 设置舵机初始值,可以根据自己的要求调试
    servo_pwm.set_pwm_freq(60)  # 设置频率为60HZ
    servo_pwm.set_pwm(5,0,325)  # 底座舵机
    servo_pwm.set_pwm(4,0,325)  # 倾斜舵机
    time.sleep(1)
    
    #初始化摄像头并设置阙值
    cap = cv2.VideoCapture(0)
    
    cap.set(3,120)
    cap.set(4,160)
    
    while(1):
    
        try:  #an error comes if it does not find anything in window as it cannot find contour of max area
              #therefore this try error statement
    
            ret, frame = cap.read()
            frame=cv2.flip(frame,1)
            kernel = np.ones((3,3),np.uint8)
    
            #define region of interest
            roi=frame[0:300, 0:300]
    
    
            cv2.rectangle(frame,(0,0),(300,300),(0,255,0),0)
            hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
    
    
    
        # define range of skin color in HSV
            lower_skin = np.array([0,20,70], dtype=np.uint8)
            upper_skin = np.array([20,255,255], dtype=np.uint8)
    
         #extract skin colur imagw
            mask = cv2.inRange(hsv, lower_skin, upper_skin)
    
    
    
        #extrapolate the hand to fill dark spots within
            mask = cv2.dilate(mask,kernel,iterations = 4)
    
        #blur the image
            mask = cv2.GaussianBlur(mask,(5,5),100)
    
    
    
        #find contours
            _,contours,hierarchy= cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    
       #find contour of max area(hand)
            cnt = max(contours, key = lambda x: cv2.contourArea(x))
    
        #approx the contour a little
            epsilon = 0.0005*cv2.arcLength(cnt,True)
            approx= cv2.approxPolyDP(cnt,epsilon,True)
    
    
        #make convex hull around hand
            hull = cv2.convexHull(cnt)
    
         #define area of hull and area of hand
            areahull = cv2.contourArea(hull)
            areacnt = cv2.contourArea(cnt)
    
        #find the percentage of area not covered by hand in convex hull
            arearatio=((areahull-areacnt)/areacnt)*100
    
         #find the defects in convex hull with respect to hand
            hull = cv2.convexHull(approx, returnPoints=False)
            defects = cv2.convexityDefects(approx, hull)
    
        # l = no. of defects
            l=0
    
        #code for finding no. of defects due to fingers
            for i in range(defects.shape[0]):
                s,e,f,d = defects[i,0]
                start = tuple(approx[s][0])
                end = tuple(approx[e][0])
                far = tuple(approx[f][0])
                pt= (100,180)
    
    
                # find length of all sides of triangle
                a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
                b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)
                c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2)
                s = (a+b+c)/2
                ar = math.sqrt(s*(s-a)*(s-b)*(s-c))
    
                #distance between point and convex hull
                d=(2*ar)/a
    
                # apply cosine rule here
                angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57
    
    
                # ignore angles > 90 and ignore points very close to convex hull(they generally come due to noise)
                if angle <= 90 and d>30:
                    l += 1
                    cv2.circle(roi, far, 3, [255,0,0], -1)
    
                #draw lines around hand
                cv2.line(roi,start, end, [0,255,0], 2)
    
    
            l+=1
    
            #print corresponding gestures which are in their ranges
            font = cv2.FONT_HERSHEY_SIMPLEX
            if l==1:
                if areacnt<2000:
                    cv2.putText(frame,'Put hand in the box',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                else:
                    if arearatio<12:
                        cv2.putText(frame,'0',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                    elif arearatio<17.5:
                        cv2.putText(frame,'Best of luck',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
    
                    else:
                        cv2.putText(frame,'1',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                        GPIO.output(led,GPIO.HIGH)#开灯
    
            elif l==2:
                cv2.putText(frame,'2',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                GPIO.output(led,GPIO.LOW)#关灯
    
            elif l==3:
    
                  if arearatio<27:
                        cv2.putText(frame,'3',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                        GPIO.output(beep,GPIO.HIGH)#蜂鸣器响
                  else:
                      pass#屏蔽ok手势
                        #cv2.putText(frame,'ok',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
    
            elif l==4:
                cv2.putText(frame,'4',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                GPIO.output(beep,GPIO.LOW)#蜂鸣器关
    
            elif l==5:
                cv2.putText(frame,'5',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                GPIO.output(led,GPIO.HIGH)#开灯
                time.sleep(0.5)
                GPIO.output(beep,GPIO.HIGH)#蜂鸣器响
                time.sleep(0.5)
                GPIO.output(beep,GPIO.LOW)#蜂鸣器关
                time.sleep(0.5)
                GPIO.output(led,GPIO.LOW)#关灯
                time.sleep(0.5)
    
            elif l==6:
                cv2.putText(frame,'reposition',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
    
            else :
                cv2.putText(frame,'reposition',(10,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
    
            #show the windows
            cv2.imshow('mask',mask)
            cv2.imshow('frame',frame)
        except:
            pass
    
    
        k = cv2.waitKey(5) & 0xFF
        if k == 27:
            break
    
    cv2.destroyAllWindows()
    cap.release()
    

    实现功能 :
    识别手势1 伸一个指头 点亮LED 灯
    识别手势2 伸两个指头 关闭LED 灯
    识别手势3 伸三个指头 响蜂鸣器
    识别手势4 伸四个指头 蜂鸣器关
    识别手势5 伸5个指头 声光警报

    成品展示:
    成品展示

    展开全文
  • 【python】树莓派相机实现手势识别,调百度API

    千次阅读 多人点赞 2019-08-11 19:41:39
    之前一直在玩百度的IOT天工物联网,一次偶然看到了人工智能标签下的人体分析功能,进去看了文档和API,发现有个手势识别很好玩,而且居然50000次/天免费 正巧,手边有一个带摄像头的树莓派3B,说干就干,开始。 2. ...

    1. 做这个的想法

    之前一直在玩百度的IOT天工物联网,一次偶然看到了人工智能标签下的人体分析功能,进去看了文档和API,发现有个手势识别很好玩,而且居然50000次/天免费

    正巧,手边有一个带摄像头的树莓派3B,说干就干,开始。

    2. 资料和准备

    百度的API https://cloud.baidu.com/doc/BODY/s/ajwvxyyn0/

    可以看到,能够识别24类手势,还挺好玩的,树莓派支持python,手势识别正好有python的API

    首先远程连接树莓派,enable摄像头(raspi-config)

    pip安装百度的aip库(sudo pip3 install baidu-aip)

    python2今年就停止支持了,所以直接上python3

    3.编写代码

    代码主要分为3部分

    • 拍照
    • 人体识别
    • 文字转语音

    全部代码如下(AK和SK隐藏了,需要的时候换成你自己的就行,反正是免费的):

    # 使用python3运行
    # 作者:xuehu96
    # 编写时间 2019年8月11日
    from picamera import PiCamera,Color
    import time
    import demjson
    from pygame import mixer 
    from aip import AipBodyAnalysis
    from aip import AipSpeech
    
    hand={'One':'数字1','Five':'数字5','Fist':'拳头','Ok':'OK',
          'Prayer':'祈祷','Congratulation':'作揖','Honour':'作别',
          'Heart_single':'比心心','Thumb_up':'点赞','Thumb_down':'Diss',
          'ILY':'我爱你','Palm_up':'掌心向上','Heart_1':'双手比心1',
          'Heart_2':'双手比心2','Heart_3':'双手比心3','Two':'数字2',
          'Three':'数字3','Four':'数字4','Six':'数字6','Seven':'数字7',
          'Eight':'数字8','Nine':'数字9','Rock':'Rock','Insult':'竖中指','Face':'脸'}
    
    
    # 下面的key要换成自己的 
    """ 人体分析 APPID AK SK """
    APP_ID = '*******'
    API_KEY = '*******************'
    SECRET_KEY = '*******************'
    """ 语音技术 APPID AK SK """
    SpeechAPP_ID = '*******'
    SpeechAPI_KEY ='*******************'
    SpeechSECRET_KEY = '*******************'
    
    camera = PiCamera()
    client = AipBodyAnalysis(APP_ID, API_KEY, SECRET_KEY)
    Speechclient = AipSpeech(SpeechAPP_ID, SpeechAPI_KEY, SpeechSECRET_KEY)
    
    '''cam config'''
    camera.resolution = (1280, 720)
    camera.annotate_text = "xuehu96 !" #图片上加水印
    #camera.annotate_background = Color('blue')
    camera.annotate_text_size = 20
    camera.annotate_foreground = Color('white')
    camera.brightness = 55
    
    """ 读取图片 """
    def get_file_content(filePath):
        with open(filePath, 'rb') as fp:
            return fp.read()
    mixer.init()
    while True:
        """1.拍照 """
        camera.start_preview()
        time.sleep(2)
        mixer.music.stop()
        camera.capture('./image.jpg')
        camera.stop_preview()
    
        image = get_file_content('./image.jpg')
    
        """ 2.调用手势识别 """
        raw = str(client.gesture(image))
        text = demjson.decode(raw)
        try:
            res = text['result'][0]['classname']
        except:
            print('识别结果:什么也没识别到哦~' )
        else:
            print('识别结果:' + hand[res])
    
            """ 3.调用文字转语音"""
            content = hand[res]
            result = Speechclient.synthesis(content, 'zh', 1, {'spd': 2, 'vol': 6, 'per': 1})
            #print(result)
            if not isinstance(result, dict):
                with open('./res.mp3', 'wb') as f:
                    f.write(result)
                
                mixer.music.load('./res.mp3')
                mixer.music.play()
    #            time.sleep(3)
    #            
    

    4. 运行与测试

    编写一个body.py, 然后 python3 body.py就可以运行了,如果缺少什么库 就sudo pip3 install xxx就行了

    图片和测试结果贴在文章的最后。

    可以看到,百度在ai方面还是挺强的,识别率很高。识别出后,通过文字转语音,再用pygame模块播报出来,再给树莓派接上USB小音箱,就能听到识别的结果了

    5. 最后

    可以看到 python语言确实非常简单方便,短短几十行代码,就完成了这样一个小功能,这样的小作品用做本科的普通毕业设计都绰绰有余,而且可以在此基础上加更多的功能,比如和智能家居联动(手势打开窗帘,手势开灯等等),就更好玩了。不过我只是想起来就做了这个小想法,没准备做更多的功能,上面你的代码完整并且完全开源,填上key就能运行,大家有兴趣了可以在我代码基础上添加更多创意。

    6.运行图片

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    展开全文
  • 最近采购了一块新的树莓派,迫不及待的想要在树莓派上实现一个实时的手势识别。从算法的角度讲,并不是太难;但是从工程的角度来说,主要有两个难点,一是手势数据的采集。大家都知道,深度学习的高精度离不开大量的...

    目录结构

    1、背景介绍

    2、数据采集

    3、网络设计

    4、网络训练

    5、网络部署

    6、总结

     

    1、背景介绍

    最近采购了一块新的树莓派,迫不及待的想要在树莓派上实现一个实时的手势识别。从算法的角度讲,并不是太难;但是从工程的角度来说,主要有两个难点,一是手势数据的采集。大家都知道,深度学习的高精度离不开大量的训练数据,网络设计的再好,没有足够的数据是不行的。因此要想实现一个好的手势识别,采集数据就成了一个比较重要的难点;另外一个难点是如何在树莓派上实现实时的识别。树莓派实际上是一个使用arm作为处理器的linux系统,但是由于芯片的性能不是很强,比我们使用的手机要弱很多,并且树莓派目前对vulkan的支持并不好,无法使用vulkan加速,因此对网络的优化也是一个难点。要保证网络优化后的精度不能下降太多,但计算量必须要下降很多。 这次就从这两个角度出发,实现一套实时的手势识别。关注公众号"DL工程实践",后台回复“手势识别”四个字,就会自动获取所有源码的下载地址。由于手势的类型非常多,有识别数字的,识别字母的,识别动作的,这里为了抛砖引玉,设计一个相对简单的识别"剪刀,石头,布"的手势识别系统,后续可以用来制作一个剪刀石头布的对战机器人。想要实现其他类型的手势识别,也完全可以按照这个流程来做。

     

    2、数据采集

    对于数据采集,首先看看有没有开源的手势识别数据集。很遗憾,除了收费的手势识别数据集,基本上都是一些不太完整的手势识别数据集。因此我们需要自己采集。工欲善其事必先利其器,自己采集就得有一些比较好的数据采集工具。这里我设计了一款数据采集工具(关注公众号"DL工程实践",后台回复“手势识别”四个字,可获取)。大家也可以根据自己的需要开发自己的数据采集工具。其实本质上并不难,使用pyqt+opencv很容易就能开发一个顺手的数据采集工具。由于基于python开发,所以移植性非常好,既可以在windows下使用,也可以在linux,树莓派上使用。我设计的这个界面非常简洁,如下图所示:

     

    opencv会调用camera开始预览,然后设置一下保存路径,保存标签,点击保存图片,就可以按照设置的保存间隔进行采集数据。例如默认的保存间隔为30,即30帧保存一张图片,相当于1秒钟保存一张,如果想要频率快一些,就将保存间隔设置的小一点。下面的视频展示了数据采集工具的采集过程,为了展示效果,我把保存间隔设置为了60帧,大约2秒保存一张图片。

    视频插不进来,有兴趣的关注“DL工程实践”查看。

    我把剪刀的标签设置为0,石头的标签设置为1,布的标签设置为2,最终通过该数据收集工具就收集到了三个文件夹:

    接下来需要为训练数据创建标签文本。这里我将所有图片的80%作为训练数据数据集,剩余的20%作为验证数据集。使用python脚本很容易实现自动创建标签文件的脚本,代码如下:

    import os
    import random
    ​
    MAX_LABEL=3 #类别的种类数目
    ​
    label_list=[]
    for label in range(0,MAX_LABEL+1):
        for file in os.listdir(str(label)):
            label_list.append(str(label)+'/' + str(file) + ' ' + str(label))        
    random.shuffle(label_list) #对列表进行shuffle操作
    count = len(label_list)
    train_count = int(count * 0.8) # 80%作为训练数据集
    train_list = label_list[0:train_count]
    test_list = label_list[train_count:]
    print('total count=%d train_count=%d test_count=%d'%(count, train_count, count-train_count))
    # 写入train.txt标签文件
    with open('train.txt', 'w') as f:
        for line in train_list:
            f.write(line + '\r')
    # 写入test.txt标签文件
    with open('test.txt', 'w') as f:
        for line in test_list:
            f.write(line + '\r')

     

    3、网络设计

    完成了数据收集,那么就可以开始为手势识别系统设计一个网络了。由于需要在树莓派这样的低性能硬件上面运行CNN,那么可以考虑从轻量级网络中选择一个来进行优化。例如google的mobilenet系列,efficient lite系列,旷世的shufflenet系列,华为的ghostnet等。那这些模型如何选择呢?我之前有一篇关于这些轻量级的模型的评测,有兴趣的可以去看看,《谁才是轻量级CNN的王者?7个维度全面评测mobilenet/shufflenet/ghostnet》,通过之前的评测,我发现shufflenetv2在精度和推理延时上面有一个很好的平衡,因此我选择了shufflenetv2作为手势识别系统的基础网络。直接使用shufflenetv2虽然能够在树莓派上较为流畅的运行,但是还达不到实时的效果,因此需要对shufflentv2进行一些优化,主要是为了降低计算量,并且能够尽量保持精度。降低计算量可以从如下几个方面考虑:

    降低shufflenet的通道系数

    shufflenetv1/v2在设计之初,本身就考虑了应用在不同的资源设备上,因此设置了一个通道系数,直接调整该通道系数,就可以获得更小计算量的模型。然而通过实际测试,直接将通道系数从1.0x降低为0.5x,在降低计算量的同时,也会对精度损失较大。因此不采用该方案。

    降低输入分辨率

    shufflenet的原始输入分辨率为224*224,如果将分辨率降低x,那么计算量将降低x^2,因此收益很大。但是通过测试发现,直接将分辨率降低,对精度的影响也会很大。所以也不采用降低分辨率的方案。

    裁剪shufflenetv2不重要的1*1卷积

    通过观察shufflenet的block,可以分为两种结构,一种是每个stage的第一个block,该block由于需要降采样,升维度,所以对输入直接复制成两份,经过branch1,和branch2之后再concat到一起,通道翻倍,如下图中的降采样block所示。另外一种普通的block将输入split成两部分,一部分经过branch2的卷积提取特征后直接与branch1的部分进行concat。如下图中的普通block所示:

    一般在DW卷积(depthwise卷积)的前或后使用1*1的卷积处于两种目的,一种是融合通道间的信息,弥补dw卷积对通道间信息融合功能的缺失。另一种是为了降维升维,例如mobilenet v2中的inverted reddual模块。而shufflenet中的block,在branch2中用了2个1*1卷积,实际上有一些多余,因为此处不需要进行升维降维的需求,那么只是为了融合dw卷积的通道间信息。实际上有一个1*1卷积就够了。因此将上述红色虚线框中的1*1卷积核删除。经过测试,精度几乎不降低,计算量却下降了30%。因此裁剪1*1的卷积核将是一个不错的方法。

    加入CSP模块

    csp在大型网络上取得了很大的成功。它在每个stage,将输入split成两部分,一部分经过原来的路径,另一部分直接shortcut到stage的尾部,然后concat到一起。这既降低了计算量,又丰富了梯度信息,减少了梯度的重用,是一个非常不错的trip。在yolov4,yolov5的目标检测中,也引入了csp机制,使用了csp_darknet。此处将csp引入到shufflenet中。并且对csp做了一定的精简,最终使用csp stage精简版本作为最终的网络结构。

    经过测试,网络虽然能大幅降低计算量,但是精度降低的也很明显。分析原因,主要有两个,一是shufflenetv2本身已经使用了在输入通道split,然后concat的blcok流程,与csp其实是一样的,只是csp是基于一个stage,shufflenetv2是基于一个block,另外csp本来就是在densenet这种密集连接的网络上使用有比较好的效果,在轻量级网络上不见得效果会好。

    因此最终将网络设计为基于shufflenetv2 1.0x,并精简了多余的1*1卷积的版本,命名为:shufflenetv2_liteconv版本。(关注公众号"DL工程实践",后台回复“手势识别”四个字,可获取)

     

    4、网络训练

    收集好了数据,并且也设计好了网络,那么接下来就是训练了。基于pytroch,大家可以很方便的编写出一个简单的训练流程。这里我选择从0开始训练,没有使用shufflenet v2 1.0x的预训练模型,因为我们对shufflenet做了优化,删除了很多1*1的conv,直接使用预训练模型会不匹配,因此从0开始训练。学习率可以适当的放大一些,epoch数目可以适当大一些。我把我的训练超参贴出来,大家可以参考使用:

    训练epoch:60

    初始学习率:0.01

    学习率策略:multistep(35,40)

    优化器:moment sgd

    weight decay:0.0001

    最终在训练完50个epoch之后,loss大约为0.1,测试集上面的精度为0.98。

     

    5、网络部署

    网络部署可以采用很多开源的推理库。例如mnn,ncnn,tnn等。这里我选择使用ncnn,因为ncnn开源的早,使用的人多,网络支持,硬件支持都还不错,关键是很多问题都能搜索到别人的经验,可以少走很多弯路。但是遗憾的是ncnn并不支持直接将pytorch模型导入,需要先转换成onnx格式,然后再将onnx格式导入到ncnn中。另外注意一点,将pytroch的模型到onnx之后有许多胶水op,这在ncnn中是不支持的,需要使用另外一个开源工具:onnx-simplifier对onnx模型进行剪裁,然后再导入到ncnn中。因此整个过程还有些许繁琐,为了简单,我编写了从"pytorch模型->onnx模型->onnx模型精简->ncnn模型"的转换脚本,方便大家一键转换,减少中间过程出错。我把主要流程的代码贴出来(详细的代码请关注公众号"DL工程实践",后台回复“手势识别”四个字,可获取)

    # 1、pytroch模型导出到onnx模型
    torch.onnx.export(net,input,onnx_file,verbose=DETAIL_LOG)
    # 2、调用onnx-simplifier工具对onnx模型进行精简
    cmd = 'python -m onnxsim ' + str(onnx_file) + ' ' + str(onnx_sim_file)
    ret = os.system(str(cmd))
    # 3、调用ncnn的onnx2ncnn工具,将onnx模型准换为ncnn模型
    cmd = onnx2ncnn_path + ' ' + str(new_onnx_file) + ' ' + str(ncnn_param_file) + ' ' + str(ncnn_bin_file)
    ret = os.system(str(cmd))
    # 4、对ncnn模型加密(可选步骤)
    cmd = ncnn2mem_path + ' ' + str(ncnn_param_file) + ' ' + str(ncnn_bin_file) + ' ' + str(ncnn_id_file) + ' ' + str(ncnn_mem_file)
    ret = os.system(str(cmd))

    导出到ncnn模型之后,就可以在ncnn模型上运行训练好的手势识别库。ncnn是基于C++开发的,因此编写上层应用的时候使用C++是效率最高的。我为了简单,使用python来调用ncnn的C++库也是可以的,不过会损失一丢丢的性能,但这是值得的,人生苦短,我用python。下面这个视频是最终部署好的手势识别程序(PS:为了增加乐趣,我实现了一个剪刀石头布对战的功能,也开源了,还是老方法获取:关注公众号"DL工程实践",后台回复“手势识别”四个字)

    视频插不进来,有兴趣的关注“DL工程实践”查看。

     

    6、总结

    本次实践完成了基于树莓派的实时手势识别,算法上并不复杂,主要是工程实践上的一些问题,例如数据的采集,网络的优化,以及后期的推理转换等。实际上还有一些工作可以优化,例如对模型的量化,对数据的增强。通过模型量化,可以进一步提升运算效率,通过数据增强可以弥补我们自己采集的数据分布单一,过拟合的风险,这些问题就留给读者朋友们自己去思考了。

    展开全文
  • 近日Seeed发布了一款专为树莓派(Raspberry Pi)设计,售价仅为12.90美元的“3D手势识别和跟踪板”。该跟踪板采用了Microchip的电近场感应技术,可在高达10cm的距离内实现触摸板输入和3D手势跟踪。Seeed基于Microchip...
  • OPENCV手势动作识别-石头剪刀布,OpenCV3.0版本,VS2012完美运行。
  • 调整屏幕亮度会改变结果。尽量将手完全放在盒子里,避免手臂或手腕进入盒子(因为它会改变面积比)。使用范围值完成,因此可能适用于不同的人的不同颜色范围。import cv2import numpy as npimport mathcap = cv2....
  • 本实验使用Arduino+树莓派进行简单的手势识别,实现对小车状态的控制材料准备:Arduino开发板一块树莓派3B杜邦线若干L298N小车底盘HC-05蓝牙模块MMA7361传感器实现原理:树莓派通过蓝牙串口与Arduino连接(实验室没有...
  • OpenCV——手势识别

    2020-12-05 16:51:30
    #include "header.h" intmain() {const int sample_num =... } } cout[index] 识别率:" (((max - min) * 100) > 100 ? 100 : ((max - min) * 100)) (3); cout[computer] * ̄▽ ̄*" ("pause"); waitKey(100);return 0; }
  • 本实验使用Arduino+树莓派进行简单的手势识别,实现对小车状态的控制 材料准备: Arduino开发板一块 树莓派3B 杜邦线若干 L298N 小车底盘 HC-05蓝牙模块 MMA7361传感器 ###实现原理: 树莓派通过蓝牙串口与Arduino...
  • 之后,我们将GPIO引脚模式设置为遵循板号以便于识别,将引脚7设置为来自手势传感器的输入,并将引脚8、10、12和16设置为4个LED的输出。 状态1-4最初设置为false,以指示LED最初将处于关闭状态。 打印字典 这部分是...
  • 调用手势识别 """ raw = str(client.gesture(image)) text = demjson.decode(raw) try: res = text['result'][0]['classname'] except: print('识别结果:什么也没识别到哦~' ) else: print('识别结果:' + hand[res...
  • 童话树莓派第十一集-进入AI世界-人脸识别(防疫检测)【人脸识别+口罩检测】小朋友们,很快又见面了今天我们继续进入AI人工智能世界,探寻人脸识别的奥秘你看起来多少岁呢?你看起来是男的还是女的呢?你带口罩了吗?....
  • Tensorflow+树莓派,自制“猜拳神器”

    千次阅读 热门讨论 2018-02-24 20:42:40
    该教程使用弯曲传感器和Tensorflow来识别猜拳手势,然后选择相应的选项:石头、剪刀、布。该项目还上了大名鼎鼎的谷歌大脑负责人Jeff Dean关于谷歌大脑在2017年的进展回顾里[2]。 图1 我想既然已经使用了...
  • 1:下载若干依赖项:  更新软件源:sudo apt-get update/upgrade;  依次安装一下依赖项:  sudo apt-get install build-essential  sudo apt-get install cmake ... sudo apt-get i
  • 本人大二,在大一下学期做了一个简单的树莓派摄像头手势识别的程序。当初选择opencv这个库是因为感觉它较skimage对新手比较友好,现在在学图像识别之前想把手势识别再看一遍,且思且记,以便日后复习。 好了废话不...
  • 基于树莓派和OpenCV的人脸识别

    千次阅读 2020-07-13 00:44:06
    树莓派(Raspberry Pi)一个 安装好系统(Raspbian) 树莓派摄像头模块(PiCam) 树莓派和摄像头安装好长这样 安装OpenCV 树莓派(Raspbian Buster)下的opencv、opencv_contrib的源码安装 下载相关程序 在树莓派终端中 ...
  • 基于树莓派的人工智能自动驾驶小车 # 整体流程 电机控制 摄像头调试 道路数据采集 搭建深度学习模型,参数调试 自动驾驶真实道路模拟 参数最终调试 使用方法: 1. 先将树莓派小车硬件组装好 2. 使用zth_car...
  • OPENCV手势动作识别-石头剪刀布

    万次阅读 多人点赞 2018-04-22 17:25:41
    作为一个OpenCV初学者,为了锻炼能力,决定自己写个手势识别程序,结果比网上找的程序效果还好一些,所以分享出来~~ 为了得到更好的效果,我利用了背景减法。取摄像头的第一帧为背景,后面所有帧减去第一帧,这样...
  • 使用树莓派控制手势传感器PAJ7620

    千次阅读 2019-09-18 20:08:46
    PAJ7620传感器是原相科技(Pixart)的一款内部集成光学阵列式传感器,以使复杂的手势和光标模式输出,内部集成了九种手势识别:上、下、左、右、向前、向后、顺时针、逆时针以及挥动的手势动作识别、模块以i2c通信,...
  • 使用TensorFlow进行手势识别

    千次阅读 2020-08-10 22:12:13
    A TensorFlow gesture detector (waving, fist pumping, running, random motion) for the Atltvhead ... 用于Atltvhead项目的TensorFlow手势检测器(挥手,拳头抽气,跑步,随机运动)和数据科学探索。 While ...
  • TensorFlow遇见Android Studio之手势识别

    千次阅读 2018-12-17 17:39:35
    在一个人工智能课上被要求做一个利用手机加速度传感器进行手势识别的项目。几经辗转,竟然收获了不错的效果。 1.首先寻找数据集,是没有找到的,这使得我们开始下定决心自己造数据。但是数据要求有一定的真实性,不...
  • 上一篇讲的是人脸检测,也是人脸识别的基础,接下来这篇我们讲人脸识别 一、人脸数据采集 我们这个项目的第一步是创建一个简单的数据集,该数据集将储存每张人脸的 ID 和一组用于人脸检测的灰度图。 在树莓派终端...
  • 公众号ID|ComputerVisionGzq 学习群|扫码在主页获取加入方式 关注并星标 从此不迷路 计算机视觉研究院 1 背景 最近采购了一块新的树莓派,迫不及待的想要在树莓派上实现一个实时的手势识别。从算法的角度讲,并不...
  • 在视频中,机器每次都可以识别出人出的是“石头”还是其他的,然后几乎同时做出反应。看视频根本区分不出机器“慢”出手。 以下为新智元关于Jeff Dean博客的报道,有兴趣的可以在这篇文章里面看到视频: 【谷歌...
  • #!/usr/bin/python# -*- coding:utf-8 -*-import timeimport smbus#i2c addressPAJ7620U2_I2C_ADDRESS = 0x73#Register Bank selectPAJ_BANK_SELECT= 0xf0#Bank0== 0x00,Bank1== 0x01#Register Bank 0PAJ_SUSPEND=.....
  • 目前,在网上大部分实现手势识别的算法,都是基于肤色检测和凸包检测。此算法虽然运算速度较快,但最大的弊端就是对手势背景要求较高(也就是说只要背景有跟皮肤类似的颜色出现,就很难将手势分割出来),抗干扰能力...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 339
精华内容 135
关键字:

树莓派手势识别