Python实现手势识别

 更新时间:2020年10月21日 15:54:11   作者:蛋片鸡  
这篇文章主要介绍了Python如何实现手指指尖的检测,并且可以在windows系统下通过判断手指数目,来模拟键盘操作,感兴趣的朋友可以了解下

  这是借鉴了github上的一个源程序,参考源:https://github.com/lzane/Fingers-Detection-using-OpenCV-and-Python

  自己在这个基础上做了一点修改补充后,可以实现手指指尖的检测,并且可以在windows系统下通过判断手指数目,来模拟键盘操作。下面直接上源程序,并做了详细注释,方便理解。

  环境:python3.6+opencv3.4.0

代码如下:

import cv2
import numpy as np
import copy
import math
import win32api
import win32con

# 参数
cap_region_x_begin = 0.5 # 起点/总宽度
cap_region_y_end = 0.8
threshold = 60 # 二值化阈值
blurValue = 41 # 高斯模糊参数
bgSubThreshold = 50
learningRate = 0

# 变量
isBgCaptured = 0 # 布尔类型, 背景是否被捕获
triggerSwitch = False # 如果正确,键盘模拟器将工作


def printThreshold(thr):
  print("! Changed threshold to " + str(thr))


def removeBG(frame): #移除背景
  fgmask = bgModel.apply(frame, learningRate=learningRate) #计算前景掩膜
  kernel = np.ones((3, 3), np.uint8)
  fgmask = cv2.erode(fgmask, kernel, iterations=1) #使用特定的结构元素来侵蚀图像。
  res = cv2.bitwise_and(frame, frame, mask=fgmask) #使用掩膜移除静态背景
  return res

# 相机/摄像头
camera = cv2.VideoCapture(0)  #打开电脑自带摄像头,如果参数是1会打开外接摄像头
camera.set(10, 200)  #设置视频属性
cv2.namedWindow('trackbar') #设置窗口名字
cv2.resizeWindow("trackbar", 640, 200) #重新设置窗口尺寸
cv2.createTrackbar('threshold', 'trackbar', threshold, 100, printThreshold)
#createTrackbar是Opencv中的API,其可在显示图像的窗口中快速创建一个滑动控件,用于手动调节阈值,具有非常直观的效果。

while camera.isOpened():
  ret, frame = camera.read()
  threshold = cv2.getTrackbarPos('threshold', 'trackbar') #返回滑动条上的位置的值(即实时更新阈值)
  # frame = cv2.cvtColor(frame,cv2.COLOR_RGB2YCrCb)
  frame = cv2.bilateralFilter(frame, 5, 50, 100) # 双边滤波
  frame = cv2.flip(frame, 1) # 翻转 0:沿X轴翻转(垂直翻转)  大于0:沿Y轴翻转(水平翻转)  小于0:先沿X轴翻转,再沿Y轴翻转,等价于旋转180°
  cv2.rectangle(frame, (int(cap_region_x_begin * frame.shape[1]), 0),(frame.shape[1], int(cap_region_y_end * frame.shape[0])), (0, 0, 255), 2)
  #画矩形框 frame.shape[0]表示frame的高度  frame.shape[1]表示frame的宽度  注:opencv的像素是BGR顺序
  cv2.imshow('original', frame)  #经过双边滤波后的初始化窗口

  #主要操作
  if isBgCaptured == 1: # isBgCaptured == 1 表示已经捕获背景
    img = removeBG(frame) #移除背景
    img = img[0:int(cap_region_y_end * frame.shape[0]),int(cap_region_x_begin * frame.shape[1]):frame.shape[1]] # 剪切右上角矩形框区域
    cv2.imshow('mask', img)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #将移除背景后的图像转换为灰度图
    blur = cv2.GaussianBlur(gray, (blurValue, blurValue), 0) #加高斯模糊
    cv2.imshow('blur', blur)
    ret, thresh = cv2.threshold(blur, threshold, 255, cv2.THRESH_BINARY) #二值化处理
    cv2.imshow('binary', thresh)

    # get the coutours
    thresh1 = copy.deepcopy(thresh)
    _, contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    #寻找轮廓  注:这里的'_'用作变量名称,_表示一个变量被指定了名称,但不打算使用。
    length = len(contours)
    maxArea = -1
    if length > 0:
      for i in range(length): # 找到最大的轮廓(根据面积)
        temp = contours[i]
        area = cv2.contourArea(temp) #计算轮廓区域面积
        if area > maxArea:
          maxArea = area
          ci = i

      res = contours[ci] #得出最大的轮廓区域
      hull = cv2.convexHull(res) #得出点集(组成轮廓的点)的凸包
      drawing = np.zeros(img.shape, np.uint8)
      cv2.drawContours(drawing, [res], 0, (0, 255, 0), 2)  #画出最大区域轮廓
      cv2.drawContours(drawing, [hull], 0, (0, 0, 255), 3) #画出凸包轮廓

      moments = cv2.moments(res) # 求最大区域轮廓的各阶矩
      center = (int(moments['m10'] / moments['m00']), int(moments['m01'] / moments['m00']))
      cv2.circle(drawing, center, 8, (0,0,255), -1)  #画出重心

      fingerRes = []  #寻找指尖
      max = 0; count = 0; notice = 0; cnt = 0
      for i in range(len(res)):
        temp = res[i]
        dist = (temp[0][0] -center[0])*(temp[0][0] -center[0]) + (temp[0][1] -center[1])*(temp[0][1] -center[1]) #计算重心到轮廓边缘的距离
        if dist > max:
          max = dist
          notice = i
        if dist != max:
          count = count + 1
          if count > 40:
            count = 0
            max = 0
            flag = False  #布尔值
            if center[1] < res[notice][0][1]:  #低于手心的点不算
              continue
            for j in range(len(fingerRes)): #离得太近的不算
              if abs(res[notice][0][0]-fingerRes[j][0]) < 20 :
                flag = True
                break
            if flag :
              continue
            fingerRes.append(res[notice][0])
            cv2.circle(drawing, tuple(res[notice][0]), 8 , (255, 0, 0), -1) #画出指尖
            cv2.line(drawing, center, tuple(res[notice][0]), (255, 0, 0), 2)
            cnt = cnt + 1

      cv2.imshow('output', drawing)
      print(cnt)
      if triggerSwitch is True:
        if cnt >= 3:
          print(cnt)
          # app('System Events').keystroke(' ') # simulate pressing blank space
          win32api.keybd_event(32, 0, 0, 0) # 空格键位码是32
          win32api.keybd_event(32, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放空格键

  # 输入的键盘值
  k = cv2.waitKey(10)
  if k == 27: # 按下ESC退出
    break
  elif k == ord('b'): # 按下'b'会捕获背景
    bgModel = cv2.createBackgroundSubtractorMOG2(0, bgSubThreshold)
    #Opencv集成了BackgroundSubtractorMOG2用于动态目标检测,用到的是基于自适应混合高斯背景建模的背景减除法。
    isBgCaptured = 1
    print('!!!Background Captured!!!')
  elif k == ord('r'): # 按下'r'会重置背景
    bgModel = None
    triggerSwitch = False
    isBgCaptured = 0
    print('!!!Reset BackGround!!!')
  elif k == ord('n'):
    triggerSwitch = True
    print('!!!Trigger On!!!')

运行程序操作:运行程序后,按下键盘的 b 键就可以捕获背景了

运行结果:

注:模拟点击空格键部分并未展示出来,有兴趣的可以尝试一下(按下n键就可以模拟键盘操作了)

补:该程序受光线影响其实较大,只有在单调背景小效果很好。

-------------------补充----------------------

后期再运行该程序的时候发现有一个错误,如下:

原因:opencv版本的原因,在opencv 4.0.0版本后,findContours的返回值只有contours, hierarchy两个参数,不再有三个参数了!

解决办法:

方法一:

更换opencv的版本 

方法二:

将代码 _,contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  改为 contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  即可!

以上就是Python实现手势识别的详细内容,更多关于Python 手势识别的资料请关注脚本之家其它相关文章!

相关文章

  • Python实现读取Linux系统的CPU以及内存占用

    Python实现读取Linux系统的CPU以及内存占用

    这篇文章主要为大家详细介绍了如何利用Python语言实现Linux系统的CPU以及内存占用,文中的示例代码讲解详细,具有一定的学习价值,需要的可以收藏一下
    2023-05-05
  • python模块和函数帮助文档快速查看方法示例

    python模块和函数帮助文档快速查看方法示例

    这篇文章主要为大家介绍了python模块和函数帮助文档快速查看方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • python实现RSA加密(解密)算法

    python实现RSA加密(解密)算法

    RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准,下面通过本文给大家介绍python实现RSA加密(解密)算法,需要的朋友参考下
    2016-02-02
  • Python字符串对齐和判断方法汇总

    Python字符串对齐和判断方法汇总

    本教程将详细介绍Python中的字符串对齐方法以及字符串判断方法,这些方法在文本处理、格式化输出和字符串匹配中非常实用,无论你是Python初学者还是想要巩固基础知识的程序员,这篇教程都能帮助你全面理解这些操作,需要的朋友可以参考下
    2025-04-04
  • python实现打砖块游戏

    python实现打砖块游戏

    这篇文章主要为大家详细介绍了Python实现打砖块游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • python实现简单多人聊天室

    python实现简单多人聊天室

    这篇文章主要为大家详细介绍了python实现简单多人聊天室功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • Python实现自动化处理每月考勤缺卡数据

    Python实现自动化处理每月考勤缺卡数据

    不管是上学还是上班都会统计考勤,有些学校或公司会对每月缺卡次数过多(比如三次以上)的人员进行处罚。本文提供了Python自动处理考勤和日志缺失的方法,需要的可以参考一下
    2022-06-06
  • python傅里叶变换FFT绘制频谱图

    python傅里叶变换FFT绘制频谱图

    这篇文章主要为大家详细介绍了python傅里叶变换FFT绘制频谱图,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • python如何可视化经纬度信息

    python如何可视化经纬度信息

    在Python中处理经纬度信息,首先通过筛选得到符合条件的停车点,并去除重复数据,利用这些数据点的索引值将原始数据进行分段,并绘制地图,处理重复数据时可以使用set()方法或列表生成式,最后,可以通过DataFrame的join方法合并具有相同索引值的数据
    2024-09-09
  • Tensorflow模型实现预测或识别单张图片

    Tensorflow模型实现预测或识别单张图片

    这篇文章主要为大家详细介绍了Tensorflow模型实现预测或识别单张图片,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07

最新评论