手势虚拟键盘

2023-11-10

 定义一个HandDetector类

import cv2
import mediapipe as mp
import math


class HandDetector:
    """
    Finds Hands using the mediapipe library. Exports the landmarks
    in pixel format. Adds extra functionalities like finding how
    many fingers are up or the distance between two fingers. Also
    provides bounding box info of the hand found.
    """

    def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):
        """
        :param mode: In static mode, detection is done on each image: slower
        :param maxHands: Maximum number of hands to detect
        :param detectionCon: Minimum Detection Confidence Threshold
        :param minTrackCon: Minimum Tracking Confidence Threshold
        """
        self.mode = mode
        self.maxHands = maxHands
        self.detectionCon = detectionCon
        self.minTrackCon = minTrackCon

        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(static_image_mode=self.mode, max_num_hands=self.maxHands,
                                        min_detection_confidence=self.detectionCon, min_tracking_confidence = self.minTrackCon)
        self.mpDraw = mp.solutions.drawing_utils
        self.tipIds = [4, 8, 12, 16, 20]
        self.fingers = []
        self.lmList = []
        
    def findPosition(self, img, draw=True):
        self.lmList = []
        if self.results.multi_hand_landmarks:
            for handLms in self.results.multi_hand_landmarks:
                for id, lm in enumerate(handLms.landmark):
                    h, w, c = img.shape
                    cx, cy = int(lm.x * w), int(lm.y * h)
                    # print(id, cx, cy)
                    self.lmList.append([id, cx, cy])
                    if draw:
                        cv2.circle(img, (cx, cy), 12, (255, 0, 255), cv2.FILLED)
        return self.lmList

    def findHands(self, img, draw=True, flipType=True):
        """
        Finds hands in a BGR image.
        :param img: Image to find the hands in.
        :param draw: Flag to draw the output on the image.
        :return: Image with or without drawings
        """
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.results = self.hands.process(imgRGB)
        allHands = []
        h, w, c = img.shape
        if  self.results.multi_hand_landmarks:
            for handType,handLms in zip(self.results.multi_handedness,self.results.multi_hand_landmarks):
                myHand={}
                ## lmList
                mylmList = []
                xList = []
                yList = []
                for id, lm in enumerate(handLms.landmark):
                    px, py = int(lm.x * w), int(lm.y * h)
                    mylmList.append([px, py])
                    xList.append(px)
                    yList.append(py)

                ## bbox
                xmin, xmax = min(xList), max(xList)
                ymin, ymax = min(yList), max(yList)
                boxW, boxH = xmax - xmin, ymax - ymin
                bbox = xmin, ymin, boxW, boxH
                cx, cy = bbox[0] + (bbox[2] // 2), \
                         bbox[1] + (bbox[3] // 2)

                myHand["lmList"] = mylmList
                myHand["bbox"] = bbox
                myHand["center"] =  (cx, cy)

                if flipType:
                    if handType.classification[0].label =="Right":
                        myHand["type"] = "Left"
                    else:
                        myHand["type"] = "Right"
                else:myHand["type"] = handType.classification[0].label
                allHands.append(myHand)

                ## draw
                if draw:
                    self.mpDraw.draw_landmarks(img, handLms,
                                               self.mpHands.HAND_CONNECTIONS)
                    cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),
                                  (bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),
                                  (255, 0, 255), 2)
                    cv2.putText(img,myHand["type"],(bbox[0] - 30, bbox[1] - 30),cv2.FONT_HERSHEY_PLAIN,
                                2,(255, 0, 255),2)
        if draw:
            return allHands,img
        else:
            return allHands

    def fingersUp(self,myHand):
        """
        Finds how many fingers are open and returns in a list.
        Considers left and right hands separately
        :return: List of which fingers are up
        """
        myHandType =myHand["type"]
        myLmList = myHand["lmList"]
        if self.results.multi_hand_landmarks:
            fingers = []
            # Thumb
            if myHandType == "Right":
                if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:
                    fingers.append(1)
                else:
                    fingers.append(0)
            else:
                if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:
                    fingers.append(1)
                else:
                    fingers.append(0)

            # 4 Fingers
            for id in range(1, 5):
                if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:
                    fingers.append(1)
                else:
                    fingers.append(0)
        return fingers

    def findDistance(self,p1, p2, img=None):
        """
        Find the distance between two landmarks based on their
        index numbers.
        :param p1: Point1
        :param p2: Point2
        :param img: Image to draw on.
        :param draw: Flag to draw the output on the image.
        :return: Distance between the points
                 Image with output drawn
                 Line information
        """

        x1, y1 = p1
        x2, y2 = p2
        cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
        length = math.hypot(x2 - x1, y2 - y1)
        info = (x1, y1, x2, y2, cx, cy)
        if img is not None:
            cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
            cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
            cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
            cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
            return length,info, img
        else:
            return length, info


        


def main():
    cap = cv2.VideoCapture(0)
    detector = HandDetector(detectionCon=0.8, maxHands=2)
    while True:
        # Get image frame
        success, img = cap.read()
        # Find the hand and its landmarks
        hands, img = detector.findHands(img)  # with draw
        # hands = detector.findHands(img, draw=False)  # without draw

        if hands:
            # Hand 1
            hand1 = hands[0]
            lmList1 = hand1["lmList"]  # List of 21 Landmark points
            bbox1 = hand1["bbox"]  # Bounding box info x,y,w,h
            centerPoint1 = hand1['center']  # center of the hand cx,cy
            handType1 = hand1["type"]  # Handtype Left or Right

            fingers1 = detector.fingersUp(hand1)

            if len(hands) == 2:
                # Hand 2
                hand2 = hands[1]
                lmList2 = hand2["lmList"]  # List of 21 Landmark points
                bbox2 = hand2["bbox"]  # Bounding box info x,y,w,h
                centerPoint2 = hand2['center']  # center of the hand cx,cy
                handType2 = hand2["type"]  # Hand Type "Left" or "Right"

                fingers2 = detector.fingersUp(hand2)

                # Find Distance between two Landmarks. Could be same hand or different hands
                length, info, img = detector.findDistance(lmList1[8], lmList2[8], img)  # with draw
                # length, info = detector.findDistance(lmList1[8], lmList2[8])  # with draw
        # Display
        cv2.imshow("Image", img)
        cv2.waitKey(1)


if __name__ == "__main__":
    main()

虚拟输入

import cv2
from cvzone.HandTrackingModule import HandDetector
from time import sleep
import pyautogui
import cvzone
from pynput.keyboard import Key,Controller
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

# 识别手势
detector = HandDetector(detectionCon=0.8)
keyboard = Controller()

# 键盘关键字
keys = [['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
        ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';'],
        ['Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/']]



class Button():
    def __init__(self, pos, text, size = [50, 50]):
        self.pos = pos
        self.text = text
        self.size = size
   
   
buttonList = []
finalText = ''
for j in range(len(keys)):
    for x, key in enumerate(keys[j]):
        # 循环创建buttonList对象列表
        buttonList.append(Button([60*x+20,100+j*60],key))


def drawAll(img,buttonList):
    for button in buttonList:
        x, y = button.pos
        w, h = button.size
        cvzone.cornerRect(img, (x, y, w, h),20,rt = 0)
        cv2.rectangle(img, button.pos, (x + w, y + h), (255, 0, 255), cv2.FILLED)
        cv2.putText(img, button.text, (x + 10, y + 40),
                    cv2.FONT_HERSHEY_PLAIN, 3, (255, 255, 255), 2)
    return img


while True:
    success, img = cap.read()
    # 识别手势
    hand = detector.findHands(img)
    lmList = detector.findPosition(img, True)

    # img = mybutton.draw(img)
    img = drawAll(img,buttonList )
    if lmList:
        for button in buttonList:
            x,y = button.pos
            w,h = button.size
            if x<lmList[8][1]<x+w and y<lmList[8][2]<y+h:
                cv2.rectangle(img, (x-5,y-5), (x + w + 5, y + h + 5), (175, 0, 175), cv2.FILLED)
                cv2.putText(img, button.text, (x + 10, y + 40),
                            cv2.FONT_HERSHEY_PLAIN, 3, (255, 255, 255), 2)

                l,_,_ = detector.findDistance(lmList[8][1:],lmList[12][1:],img)
                print('中指(12)和食指(8)之间的距离:',l)
                if l < 120:
                    keyboard.press(button.text)
                    pyautogui.typewrite(f"{button.text}", 0.5)
                    cv2.rectangle(img, button.pos, (x + w, y + h), (0, 255, 0), cv2.FILLED)
                    cv2.putText(img, button.text, (x + 10, y + 40),
                                cv2.FONT_HERSHEY_PLAIN, 3, (255, 255, 255), 2)
                    finalText += button.text
                    print('当前选中的是:', button.text)
                    sleep(0.2)
    cv2.rectangle(img, (20,350), (600, 400), (175, 0, 175), cv2.FILLED)
    cv2.putText(img, finalText, (20, 390),
                cv2.FONT_HERSHEY_PLAIN, 3, (255, 255, 255), 4)
    cv2.imshow("Image",img)
    cv2.waitKey(1)

 

 最后:代码我完全开源可用,需要安装必要的python包。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手势虚拟键盘 的相关文章

  • 没有名为 crypto.cipher 的模块

    我现在正在尝试加密一段时间 我最近得到了这个基于 python 的密码器 名为PythonCrypter https github com jbertman PythonCrypter 我对 Python 相当陌生 当我尝试通过终端打开 C
  • Python 中的 Lanczos 插值与 2D 图像

    我尝试重新缩放 2D 图像 灰度 图像大小为 256x256 所需输出为 224x224 像素值范围从 0 到 1300 我尝试了两种使用 Lanczos 插值来重新调整它们的方法 首先使用PIL图像 import numpy as np
  • Python 的键盘中断不会中止 Rust 函数 (PyO3)

    我有一个使用 PyO3 用 Rust 编写的 Python 库 它涉及一些昂贵的计算 单个函数调用最多需要 10 分钟 从 Python 调用时如何中止执行 Ctrl C 好像只有执行结束后才会处理 所以本质上没什么用 最小可重现示例 Ca
  • 将 saxon 与 python 结合使用

    我需要使用 python 处理 XSLT 目前我正在使用仅支持 XSLT 1 的 lxml 现在我需要处理 XSLT 2 有没有办法将 saxon XSLT 处理器与 python 一起使用 有两种可能的方法 设置一个 HTTP 服务 接受
  • 为 Anaconda Python 安装 psycopg2

    我有 Anaconda Python 3 4 但是每当我运行旧代码时 我都会通过输入 source activate python2 切换到 Anaconda Python 2 7 我的问题是我为 Anaconda Python 3 4 安
  • 如何在 Python 中检索 for 循环中的剩余项目?

    我有一个简单的 for 循环迭代项目列表 在某些时候 我知道它会破裂 我该如何退回剩余的物品 for i in a b c d e f g try some func i except return remaining items if s
  • 使用 on_bad_lines 将 pandas.read_csv 中的无效行写入文件

    我有一个 CSV 文件 我正在使用 Python 来解析该文件 我发现文件中的某些行具有不同的列数 001 Snow Jon 19801201 002 Crom Jake 19920103 003 Wise Frank 19880303 l
  • 如何替换 pandas 数据框列中的重音符号

    我有一个数据框dataSwiss其中包含瑞士城市的信息 我想用普通字母替换带有重音符号的字母 这就是我正在做的 dataSwiss Municipality dataSwiss Municipality str encode utf 8 d
  • 是否可以忽略一行的pyright检查?

    我需要忽略一行的pyright 检查 有什么特别的评论吗 def create slog group SLogGroup data Optional dict None SLog insert one SLog group group da
  • Flask如何获取请求的HTTP_ORIGIN

    我想用我自己设置的 Access Control Allow Origin 标头做出响应 而弄清楚请求中的 HTTP ORIGIN 参数在哪里似乎很混乱 我在用着烧瓶 0 10 1 以及HTTP ORIGIN似乎是这个的特点之一object
  • Python 的“zip”内置函数的 Ruby 等价物是什么?

    Ruby 是否有与 Python 内置函数等效的东西zip功能 如果不是 做同样事情的简洁方法是什么 一些背景信息 当我试图找到一种干净的方法来进行涉及两个数组的检查时 出现了这个问题 如果我有zip 我可以写这样的东西 zip a b a
  • Pygame:有没有简单的方法可以找到按下的任何字母数字的字母/数字?

    我目前正在开发的游戏需要让人们以自己的名义在高分板上计时 我对如何处理按键有点熟悉 但我只处理过寻找特定的按键 有没有一种简单的方法可以按下任意键的字母 而不必执行以下操作 for event in pygame event get if
  • IO 密集型任务中的 Python 多线程

    建议仅在 IO 密集型任务中使用 Python 多线程 因为 Python 有一个全局解释器锁 GIL 只允许一个线程持有 Python 解释器的控制权 然而 多线程对于 IO 密集型操作有意义吗 https stackoverflow c
  • 使用 \r 并打印一些文本后如何清除控制台中的一行?

    对于我当前的项目 有一些代码很慢并且我无法使其更快 为了获得一些关于已完成 必须完成多少的反馈 我创建了一个进度片段 您可以在下面看到 当你看到最后一行时 sys stdout write r100 80 n I use 80覆盖最终剩余的
  • 向 Altair 图表添加背景实心填充

    I like Altair a lot for making graphs in Python As a tribute I wanted to regenerate the Economist graph s in Mistakes we
  • 解释 Python 中的数字范围

    在 Pylons Web 应用程序中 我需要获取一个字符串 例如 关于如何做到这一点有什么建议吗 我是 Python 新手 我还没有找到任何可以帮助解决此类问题的东西 该列表将是 1 2 3 45 46 48 49 50 51 77 使用
  • 在 Qt 中自动调整标签文本大小 - 奇怪的行为

    在 Qt 中 我有一个复合小部件 它由排列在 QBoxLayouts 内的多个 QLabels 组成 当小部件调整大小时 我希望标签文本缩放以填充标签区域 并且我已经在 resizeEvent 中实现了文本大小的调整 这可行 但似乎发生了某
  • Python 类继承 - 诡异的动作

    我观察到类继承有一个奇怪的效果 对于我正在处理的项目 我正在创建一个类来充当另一个模块的类的包装器 我正在使用第 3 方 aeidon 模块 用于操作字幕文件 但问题可能不太具体 以下是您通常如何使用该模块 project aeidon P
  • 如何使用 Pycharm 安装 tkinter? [复制]

    这个问题在这里已经有答案了 I used sudo apt get install python3 6 tk而且效果很好 如果我在终端中打开 python Tkinter 就可以工作 但我无法将其安装在我的 Pycharm 项目上 pip
  • Statsmodels.formula.api OLS不显示截距的统计值

    我正在运行以下源代码 import statsmodels formula api as sm Add one column of ones for the intercept term X np append arr np ones 50

随机推荐

  • java知识结构

    基础 1 java概述 2 搭建运行环境 3 java基本语法 常变量 数据类型 运算符 标识符与关键字 4 流程控制 5 eclipse开发工具 6 面向对象编程 类和对象 包 继承 this super关键字 多态 重载 重写 抽象类f
  • systemverilog中的bind

    最早接触 bind 关键字是在assertion 当中 将assertion 与 dut 进行绑定连接 如下例子 bind cpu fpu props fpu rules 1 a b c cpu 是module 名字 fpu props 是
  • ElementUI表格的动态渲染

    在ElementUI官方文档中 描述的动态渲染只是单纯的将已知字段名称的JSON数据通过prop属性填充到页面中 下为官方文档内容
  • 轮播图背景图铺满整个div

    slider width 1224px height 458px background image url image school 1 png background size cover background repeat round p
  • Biogeochemical record of ancient humans (古人类生物地理化学记录)

    一 摘要 该文为一篇综述 全文主要介绍了如何利用生物化学记录 同位素 研究古人类饮食 营养和活动 二 作者简介 Marilyn Fogel born September 19 1952 is an American geo ecologis
  • Java程序中对Service进行Mock

    Java程序中对Service进行Mock 背景 Servie Test Service 背景 在项目中往往需要对service逻辑进行单元测试验证 这里采用mockito对dao数据进行模拟 验证service逻辑 Servie pack
  • 算法训练 大小写转换

    http lx lanqiao org problem page gpid T216 算法训练 大小写转换 时间限制 1 0s 内存限制 512 0MB 问题描述 编写一个程序 输入一个字符串 长度不超过20 然后把这个字符串内的每一个字符
  • 快速获得CNVD证书

    首先要明确什么样的通用漏洞可以发证书 收录标准 这里的收录标准是能获得证书的标准 事件型 事件型漏洞必须是三大运营商 移动 联通 电信 的中高危漏洞 或者党政机关 重要行业单位 科研院所 重要企事业单位 如 中央国有大型企业 部委直属事业单
  • maven子工程application文件失效

    按照如下进行操作
  • ubuntu下载goalng-1.9

    一 安装 这里以安装golang1 9为例 1 首先通过命令行直接安装 sudo apt get install golang 1 9 2 下载好之后 查看go的版本 catik catik Aspire V3 471 go version
  • 2023杭电暑假多校6 题解 1 2 6 10

    文章目录 1 Count 2 Pair Sum and Perfect Square https vjudge csgrandeur cn problem HDU 7337 6 Perfect square number https vju
  • C++中的拷贝构造函数

    1 拷贝构造函数 拷贝构造函数是一种特殊的构造函数 它在创建对象时 是使用同一类中之前创建的对象来初始化新创建的对象 拷贝构造函数通常用于 a 当用类的一个对象去初始化该类的另一个对象 或引用 时系统自动调用拷贝构造函数实现拷贝赋值 b 若
  • 微信小程序开发(二)微信小程序的调试和发布

    调试 编译和预览 预览 点击预览 可以使用微信扫描二维码 在手机上安装测试版小程序 或者点击自动预览 可以连接手机微信或者直接在电脑端打开小程序预览 发布 上传代码 发布项目 工具 上传 确定 编辑版本号和描述 点击上传 上传成功 点击下载
  • mysql错误代码1045的原因及解决方案、Mysql服务没找到?

    mysql错误代码1045的原因及解决方案 Mysql服务没找到 再一次接触数据库时 想要用工具连接数据库的时候 出现了错误 Acess denied for localhost 忘了 应该是服务器的问题 就去重启了一下服务器 net st
  • 【Ant Design of Vue】Tree 树形控件双击树节点禁止取消选中(两种方法)

    一 需求 Ant Design of Vue官网中 第一次点击树节点会选中 再一次点击该树节点会取消选中 如图所示 现有如下需求 根据左侧选中树节点 去请求接口获取右侧表格数据 第一次点击树节点则选中 再一次点击该树节点不会取消选中 不会取
  • 通过js date对象获取各种开始结束日期的示例

    有时候做一些任务计划的功能时候 需要提供一个开始时间或者结束时间 比如本周结束 本月结束 今天结束等等 因此 我参考网上的资料把相关的实现为一个项目 gitee https gitee com dhclly icedog date edge
  • 深度学习------tensorflow卷积神经网络:cifar数据集

    1 cifar10数据集介绍 CIFAR 10数据集由10个类的60000个32x32彩色图像组成 每个类有6000个图像 有50000个训练图像和10000个测试图像 数据集分为五个训练批次和一个测试批次 每个批次有10000个图像 测试
  • Dofbot机械臂从零部署笔记(4)——ROS之Moveit下实现实机逆向运动学规划

    文章目录 编译代码 逆向运动学规划例子 代码和运行效果 关于老是规划失败 逆向运动学Moveit编程步骤 代码修正 本节接上节 实现逆向运动学规划 本节源代码位于 home jetson dofbot ws src dofbot movei
  • linux重置电池阀值,Thinkpad在linux(ubuntu)下修改电池充电阈值,成功解决Thinkpad在Linux下的电池充电问题...

    安装tp smapi aptitude install tp smapi dkms modprobe tp smapi 更改充电阈值 设置开始充电阈值 如从 60 开始充电 echo 60 gt sys devices platform s
  • 手势虚拟键盘

    定义一个HandDetector类 import cv2 import mediapipe as mp import math class HandDetector Finds Hands using the mediapipe libra