如何使用计算机视觉、OpenCv和Python创建一个手指计数器

376 阅读6分钟

使用计算机视觉、OpenCv和Python创建一个手指计数器

谈到编码,最好的学习方式是通过从事有趣但具有挑战性的项目。具有挑战性的部分使我们更深入地研究我们正在处理的概念。

有趣的部分使我们在代码出错的时候也能继续工作。在本教程中,我们将做一个有趣但相对有挑战性的项目。我们将研究如何使用计算机视觉、OpenCv和Python创建一个手指计数器。

简介

Python有一些库,可以帮助我们开发项目。我们将需要OpenCvMediaPipe 。我们将在后面讨论为什么以及如何使用这两个库。

我们还需要一个Python IDE。我们将使用pycharm社区版,因为它可以在互联网上免费获得。

本教程将讨论如何在MediaPipe库的帮助下使用python进行手工跟踪。我们还将学习如何使用OpenCv在我们的项目中实现计算机视觉。

最后,我们将学习如何结合MediaPipe、OpenCv和Python来创建一个程序,计算输入图像中的手指数量。使用Windows或Linux的人可以跟进。

前提条件

要理解这篇文章,读者需要。

  • 熟悉Python编程语言。
  • 在他们的计算机上安装了pycharm。

了解手部地标模型

Hand landmark model

上图是一个手部地标模型,显示了MediaPipe如何追踪手部。这篇文章将重点讨论手部的指关节。

该图显示了指关节上显示的从0到20的数字。我们将使用这些指关节的位置来确定一个手指是打开还是关闭。

让我们来看看我们将使用的逻辑。

  • 如果第8个指节在第6个指节之上,那么这个手指是开放的。如果它低于6号指节,那么这个手指是闭合的。
  • 这将适用于除拇指外的所有手指。对于拇指,我们将检查指节号4 ,是否高于指节号2 。如果是这样,那么拇指是打开的,否则,拇指是关闭的。

使用计算机视觉、OpenCv和Python创建一个手指计数器程序

首先,我们需要在Pycharm中准备我们的工作环境。要做到这一点,打开pycharm应用程序,在出现的窗口上点击create a new project

这看起来就像下面的截图一样。

Project

点击create a new project 之后,会出现一个新的窗口。点击create 按钮。现在我们已经准备好了Pycharm,我们需要安装我们的项目所需要的Python库。

安装我们的项目所需的Python库

如下面的截图所示,点击terminal ,然后按照下面的步骤操作。

Terminal

要安装MediaPipe ,使用下面的命令。

pip install mediapipe

这个库是由谷歌开发的。我们将使用它来进行手部追踪和手指追踪。

要安装cv2 ,我们将使用下面的命令。

pip install opencv-python

我们将使用上面的库来通过网络摄像头获取我们的输入。它还将帮助我们把捕捉到的图像处理成RGB 格式。

编码

安装完上述库后,我们现在准备开始编码。我们将在pycharm自动为我们创建的main.py 文件上编写代码。

第1步 - 导入我们需要的库

我们将首先把我们讨论过的库导入我们的项目中。这将使我们能够在我们的代码中使用它们的依赖项。

要做到这一点,请使用下面的代码。

import cv2
import mediapipe as mp

第2步 - 声明 "MediaPipe "对象以及手指和拇指的坐标

然后我们将使用我们的网络摄像头捕捉图像,并声明我们将需要的MediaPipe 对象。我们还将声明手指和拇指的坐标,我们将使用这些坐标来确定一个手指是打开还是关闭。

下面的代码是用来实现这一目的的。

cap = cv2.VideoCapture(0)
mp_Hands = mp.solutions.hands
hands = mp_Hands.Hands()
mpDraw = mp.solutions.drawing_utils
finger_Coord = [(8, 6), (12, 10), (16, 14), (20, 18)]
thumb_Coord = (4,2)

我们将使用mp_Hands 来检测输入图像中的手,hands 来处理检测到的手,mpDraw 来画出手的连接和手中存在的地标。

第3步 - 将输入图像转换为 "RGB "图像

接下来,我们使用下面的代码检查是否有输入图像。如果成功,图像确实存在,我们将首先把它转换为RGB

之后,我们使用hands 模块处理RGB 图像,以定位双手并识别其中存在的所有地标。这显示在下面。

while True:
    success, image = cap.read()
    RGB_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    results = hands.process(RGB_image)
    multiLandMarks = results.multi_hand_landmarks

第4步 - 绘制手部的地标

到目前为止,我们已经确定了手上的地标,但我们还没有画出所确定的地标。下面的代码将有助于确保使用if 语句的手部地标确实存在。

我们将创建一个嵌套的for 循环,使我们能够一次处理一只手,并画出每只手上的手部地标。所创建的空列表将在后面的代码中使用。


    if multiLandMarks:
        handList = []
        for handLms in multiLandMarks:
            mpDraw.draw_landmarks(image, handLms, mp_Hands.HAND_CONNECTIONS)
            for idx, lm in enumerate(handLms.landmark):

第5步--将手部点的坐标改变为图像像素

处理实际的坐标是一个挑战。因此,我们需要将它们改变为像素。

我们使用image.shape 函数来获得图像的高度、宽度和颜色通道。然后我们将以像素的形式得到每个手点的xy 坐标。然后,我们将把这些手点保存在我们之前创建的列表中。

下面的代码将实现这一点。

              h, w, c = image.shape
              cx, cy = int(lm.x * w), int(lm.y * h)
              handList.append((cx, cy))

第6步--圈出手点

现在我们将圈出我们已经确定的每个手点。这是为了确保我们得到正确的手点。

我们使用下面的代码来实现这一点。

        for point in handList:
            cv2.circle(image, point, 10, (255, 255, 0), cv2.FILLED)

第7步--检查一个手指是打开还是关闭的

我们现在将使用我们在这里讨论的逻辑来确定一个手指是打开还是关闭。我们将使用for 循环对每个手指进行迭代。

        upCount = 0
        for coordinate in finger_Coord:
            if handList[coordinate[0]][1] < handList[coordinate[1]][1]:
                upCount += 1
        if handList[thumb_Coord[0]][0] > handList[thumb_Coord[1]][0]:
            upCount += 1

第8步 - 显示我们的输出

最后一步涉及我们显示输出。我们将使用upcount 的值来显示打开的手指的数量。这是因为只有当手指打开时,它才会递增。

我们还将输出一个实时视频,显示用户打开和关闭手指的情况。使用下面的代码来实现这一点。

        cv2.putText(image, str(upCount), (150,150), cv2.FONT_HERSHEY_PLAIN, 12, (0,255,0), 12)

    cv2.imshow("Counting number of fingers", image)
    cv2.waitKey(1)

结果

当我们运行上面的代码完成后,如果没有任何错误,输出结果将如下图所示。

Results

总结

我们终于来到了本教程的结尾。你现在更好地理解了创建手指计数软件所需的概念和技能。现在看着程序识别并显示你通过网络摄像头向它展示的手指数量。