AI手势虚拟拖动方块使用OPENCV

系列文章目录

在使用opencv去拖动AL虚拟的方块的时候我们分为以下的步骤

1.opencv获取视频流

2.在画面上画几个方块

3.通过mediapie获取手指关节关键点坐标

4.判断手指是否在方块上,指尖的坐标都在方块坐标里面

5.如果在方块上,方块跟着手指移动

提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

前言

AI虚拟拖动方块

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。

提示:以下是本篇文章正文内容,下面案例可供参考

一、mediapipe是什么?

示例:mediapipe是用于捕捉在视频中手指关键点的包。MediaPipe感知管道称为Graph。让我们以第一个solution为例,汉兹。我们输入一串图像作为输入,然后在图像上呈现手的landmarks

并且人的手指关键点为21个。

AI手势虚拟拖动方块使用OPENCV

; 二、numpy是什么

示例:numpy是用于一维数组,二维数组,甚至多维数组对象,在计算机眼里的照片都是由数组

组成的一些数字

1.引入库

代码如下(示例):

import cv2  #导入opencv的包
import numpy as np #导入numpy
import math     #后面要用到勾股定理去计算手指之间的距离,所以导入数学的包
#mediapipe的相关参数,在官网上面复制
import mediapipe as mp  #导入mediapipe的包

2.使用opencv都要先导入视频流

代码如下(示例):

cap =cv2.VideoCapture(0)  #定义一个变量来存放导入的视频流

while True:
    #读取每一帧,ret代表的是返回值
    ret,frame =cap.read()
    #对图像进行处理
    #镜像处理,对y轴进行翻转
    frame = cv2.flip(frame,1)

    #退出条件
    if cv2.waitKey(10) & 0xFF == 27: #这边的27代表的是esc键退出
        break
 #显示图像
cv2.imshow('Virtual drag',frame)  #对于第一个参数就是随便取得变量名
cap.release()
cv2.destroyAllWindows()

3.导入mediapipe来获取视频流里的手指关节

#mediapipe的相关参数,在官网上面复制
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
#获取手的21个关节,官网开源
hands = mp_hands.Hands(
    model_complexity=0,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5)

4.对于使用后opencv来画一个方块,用于我们的拖动

#为了更方便看到我们手指之间的距离,我们这边把方块设置为半透明的
 overlay = frame.copy() #给他一个遮罩

cv2.rectangle(frame,(square_x,square_y),(square_x
    +square_width,square_y+square_width),square_color,-1)
#此段代码代表的是在窗口画一个方块,并且对于最后的一个参数就是把设置为-1,代表的是,设置实心的方块
   frame = cv2.addWeighted(overlay,0.5,frame,0.5,0)#做一个半透明

5.当然还需要对方块的位置进行设置

#方块的相关参数
square_x = 100
square_y = 100
square_width = 100
square_color = (255,0,0)

6.对mediapipe颜色的处理

因为由于opencv的颜色处理和mediapipe的颜色处理是不同的。opencv的颜色处理是RGB

而对于mediapipe的颜色处理是BGR。所以我们需要对颜色的进行的调换

 #mediapipe处理颜色,在官网找,fream代表的是帧率的意思,就是变量名
    frame.flags.writeable =False
    frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
    results=hands.process(frame)

    frame.flags.writeable =True
    frame = cv2.cvtColor(frame,cv2.COLOR_RGB2BGR)

7.使用mediapipe来对手的21个关键进行遍历解析,在加入以下的代码就可以在视频上面看到视屏中我们手指的21个关键点。(但是我们的重点是在于对食指和中指的识别,使用这两很手指之间的距离来拖动)

  if results.multi_hand_landmarks: #判断是否有手
    #不断的解析遍历每一双手,并且最大为两双手
    #对于下面对手解析的代码都是开源的,直接到mediapipe的官方网站进行查找即可
      for hand_landmarks in results.multi_hand_landmarks:
          #绘制21个关键点,先对一双手进行解析,然后在对另一双进行解析
        mp_drawing.draw_landmarks(
            frame,
            hand_landmarks,
            mp_hands.HAND_CONNECTIONS,
            mp_drawing_styles.get_default_hand_landmarks_style(),
            mp_drawing_styles.get_default_hand_connections_style()
            )

8.整个项目的核心代码即使上一段代码里的hand_landmarks代表的是

21个关键点的信息,我们打印出来看看hand_landmarks是什么东西

 print(landmark.x)#看看landmark的是什么样子,我只需要食指
 print(hand_landmarks)
  #打印看看21个关键点长什么样子

AI手势虚拟拖动方块使用OPENCV

我们只需要把其中的食指和中指的解析出来就可以了

 #print(landmark.x)#看看landmark的是什么样子,我只需要食指
#这边只使用了landmarks.x代表的是值打印x坐标
但是如果你填写一个landmarks.m的话就回报错,所以只有x,y,z

因为我们是要使用21个数据,所以用python里的列表把这些数据存储起来
用来保存x,y的坐标
 #保存21个x,y的坐标
        x_list = []
        y_list = []
        for landmark in hand_landmarks.landmark:#会循环21次把手的关节弄好
        #添加x坐标
            x_list.append(landmark.x)#append表示添加x坐标
        #添加y坐标
            y_list.append(landmark.y)
        #获取食指指尖,xy坐标
        index_finger_x = int(x_list[8] * width)
        index_finger_y = int(y_list[8] * height)
        #获取中指指尖,用于退出方块
        middle_finger_x = int(x_list[12] * width)
        middle_finger_y = int(y_list[12] * height)

9.在我们使用食指的时候要确保食指的坐标是准确的

#获取画面宽度,高度,因为显示小数的原因是由于,官网原本除以了宽度
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height=int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#由于小数所以要取整

#如何判断手指是获取的坐标是否正确,我们来画一个圆就知道,通过看所画的圆是否在食指手指上面
 #cv2.circle(frame,(index_finger_x,index_finger_y),20,(255,
        #0,255),-1)
        #print(index_finger_x,index_finger_y)

10.判断手指是否在方块上面。在我们确定方块的位置的时候,我们只需要知道方块的对角的那两个点的坐标左上角坐标(x,y),右下角坐标(x+w,y+w)即可确认方块的位置,于是我们把手指看成一个坐标点,如果手指的横坐标点小于右下角的横坐标并且大于左上角的横坐标,手指的纵坐标小于左上角的纵坐标,大于右下角的纵坐标,即可表示出手指在方块上面

      if finger_len < 30:
        #&#x5224;&#x65AD;&#x6307;&#x5C16;&#x662F;&#x5426;&#x5728;&#x65B9;&#x5757;&#x4E0A;&#x9762;
           if (index_finger_x > square_x) and (index_finger_x <
           (square_x+square_width)) and (index_finger_y >
           square_y) and (index_finger_y < (square_y
           +square_width)):
               if on_square ==False:
                    print('&#x5728;&#x65B9;&#x5757;&#x4E0A;')
                    L1=abs(index_finger_x - square_x)#abs&#x4EE3;&#x8868;&#x7EDD;&#x5BF9;&#x503C;
                    L2=abs(index_finger_y - square_y)
                    on_square =True
                    square_color=(255,0,255)
               else:
                  # print('&#x4E0D;&#x5728;&#x65B9;&#x5757;&#x4E0A;')

11.接下来的一步就是当我们的手指在方块上的时候如何使方块的移动,实际上就是当手指在方块的时候,只要不断的改变方块的坐标,并且食指之间的坐标也是在不断的改变即可实现这个功能。算法的图我也给大家整理出

AI手势虚拟拖动方块使用OPENCV

12.最后一步就是当我们的手指在方块上面的时候要激活方块就是用到勾股定理(大家在熟悉不过的345)

 if on_square: #&#x5982;&#x679C;&#x624B;&#x6307;&#x5728;&#x65B9;&#x5757;&#x4E0A;&#x9762;
            square_x = index_finger_x -L1#&#x6839;&#x636E;&#x7B97;&#x6CD5;
            square_y = index_finger_y -L2

13.最后的全部代码

"""
author : The sky
datw:2022-04-29
&#x9879;&#x76EE;1&#x6B65;&#x9AA4;
1.opencv&#x83B7;&#x53D6;&#x89C6;&#x9891;&#x6D41;
2.&#x5728;&#x753B;&#x9762;&#x4E0A;&#x753B;&#x51E0;&#x4E2A;&#x65B9;&#x5757;
3.&#x901A;&#x8FC7;mediapie&#x83B7;&#x53D6;&#x624B;&#x6307;&#x5173;&#x8282;&#x5173;&#x952E;&#x70B9;&#x5750;&#x6807;
4.&#x5224;&#x65AD;&#x624B;&#x6307;&#x662F;&#x5426;&#x5728;&#x65B9;&#x5757;&#x4E0A;,&#x6307;&#x5C16;&#x7684;&#x5750;&#x6807;&#x90FD;&#x5728;&#x65B9;&#x5757;&#x5750;&#x6807;&#x91CC;&#x9762;
5.&#x5982;&#x679C;&#x5728;&#x65B9;&#x5757;&#x4E0A;&#xFF0C;&#x65B9;&#x5757;&#x8DDF;&#x7740;&#x624B;&#x6307;&#x79FB;&#x52A8;
"""
import cv2
import numpy as np
import math
#mediapipe&#x7684;&#x76F8;&#x5173;&#x53C2;&#x6570;&#xFF0C;&#x5728;&#x5B98;&#x7F51;&#x4E0A;&#x9762;&#x590D;&#x5236;
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
#&#x83B7;&#x53D6;&#x624B;&#x7684;21&#x4E2A;&#x5173;&#x8282;&#xFF0C;&#x5B98;&#x7F51;&#x5F00;&#x6E90;
hands = mp_hands.Hands(
    model_complexity=0,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5)
#&#x83B7;&#x53D6;&#x6444;&#x50CF;&#x5934;&#x7684;&#x89C6;&#x9891;&#x6D41;
cap =cv2.VideoCapture(0)

#&#x83B7;&#x53D6;&#x753B;&#x9762;&#x5BBD;&#x5EA6;,&#x9AD8;&#x5EA6;&#xFF0C;&#x56E0;&#x4E3A;&#x663E;&#x793A;&#x5C0F;&#x6570;&#x7684;&#x539F;&#x56E0;&#x662F;&#x7531;&#x4E8E;,&#x5B98;&#x7F51;&#x539F;&#x672C;&#x9664;&#x4EE5;&#x4E86;&#x5BBD;&#x5EA6;
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height=int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#&#x65B9;&#x5757;&#x7684;&#x76F8;&#x5173;&#x53C2;&#x6570;
square_x = 100
square_y = 100
square_width = 100
square_color = (255,0,0)

L1=0
L2=0
on_square = False #&#x7528;&#x4E8E;&#x5224;&#x65AD;&#x662F;&#x5426;&#x5728;&#x65B9;&#x5757;&#x4E0A;&#xFF0C;&#x4E00;&#x5F00;&#x59CB;&#x9ED8;&#x8BA4;&#x4E0D;&#x5728;
while True:
    #&#x8BFB;&#x53D6;&#x6BCF;&#x4E00;&#x5E27;
    ret,frame =cap.read()
    #&#x5BF9;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x5904;&#x7406;
    #&#x955C;&#x50CF;&#x5904;&#x7406;&#xFF0C;&#x5BF9;y&#x8F74;&#x8FDB;&#x884C;&#x7FFB;&#x8F6C;
    frame = cv2.flip(frame,1)

    #mediapipe&#x5904;&#x7406;&#x989C;&#x8272;,&#x5728;&#x5B98;&#x7F51;&#x627E;
    frame.flags.writeable =False
    frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
    results=hands.process(frame)

    frame.flags.writeable =True
    frame = cv2.cvtColor(frame,cv2.COLOR_RGB2BGR)

    if results.multi_hand_landmarks: #&#x5224;&#x65AD;&#x662F;&#x5426;&#x6709;&#x624B;
    #&#x4E0D;&#x65AD;&#x7684;&#x89E3;&#x6790;&#x904D;&#x5386;&#x6BCF;&#x4E00;&#x53CC;&#x624B;&#xFF0C;&#x5E76;&#x4E14;&#x6700;&#x5927;&#x4E3A;&#x4E24;&#x53CC;&#x624B;
      for hand_landmarks in results.multi_hand_landmarks:
          #&#x7ED8;&#x5236;21&#x4E2A;&#x5173;&#x952E;&#x70B9;&#xFF0C;&#x5148;&#x5BF9;&#x4E00;&#x53CC;&#x624B;&#x8FDB;&#x884C;&#x89E3;&#x6790;&#xFF0C;&#x7136;&#x540E;&#x5728;&#x5BF9;&#x53E6;&#x4E00;&#x53CC;&#x8FDB;&#x884C;&#x89E3;&#x6790;
        mp_drawing.draw_landmarks(
            frame,
            hand_landmarks,
            mp_hands.HAND_CONNECTIONS,
            mp_drawing_styles.get_default_hand_landmarks_style(),
            mp_drawing_styles.get_default_hand_connections_style()
            )
        #&#x4FDD;&#x5B58;21&#x4E2A;x,y&#x7684;&#x5750;&#x6807;
        x_list = []
        y_list = []
        for landmark in hand_landmarks.landmark:#&#x4F1A;&#x5FAA;&#x73AF;21&#x6B21;&#x628A;&#x624B;&#x7684;&#x5173;&#x8282;&#x5F04;&#x597D;
        #&#x6DFB;&#x52A0;x&#x5750;&#x6807;
            x_list.append(landmark.x)#append&#x8868;&#x793A;&#x6DFB;&#x52A0;x&#x5750;&#x6807;
        #&#x6DFB;&#x52A0;y&#x5750;&#x6807;
            y_list.append(landmark.y)
        #&#x83B7;&#x53D6;&#x98DF;&#x6307;&#x6307;&#x5C16;,xy&#x5750;&#x6807;
        index_finger_x = int(x_list[8] * width)
        index_finger_y = int(y_list[8] * height)
        #&#x83B7;&#x53D6;&#x4E2D;&#x6307;&#x6307;&#x5C16;&#xFF0C;&#x7528;&#x4E8E;&#x9000;&#x51FA;&#x65B9;&#x5757;
        middle_finger_x = int(x_list[12] * width)
        middle_finger_y = int(y_list[12] * height)
        #&#x8BA1;&#x7B97;&#x98DF;&#x6307;&#x6307;&#x5C16;&#x548C;&#x4E2D;&#x6307;&#x6307;&#x5C16;&#x7684;&#x8DDD;&#x79BB;&#xFF0C;&#x7528;&#x52FE;&#x80A1;&#x5B9A;&#x7406;
        finger_len = math.hypot((index_finger_x-middle_finger_x),
        (index_finger_y-middle_finger_y))
        print(finger_len)
        #&#x753B;&#x4E00;&#x4E2A;&#x5706;&#x6765;&#x9A8C;&#x8BC1;&#x5750;&#x6807;&#x662F;&#x5426;&#x6B63;&#x786E;
        #cv2.circle(frame,(index_finger_x,index_finger_y),20,(255,
        #0,255),-1)
        #print(index_finger_x,index_finger_y)
        # print(landmark.x)#&#x770B;&#x770B;landmark&#x7684;&#x662F;&#x4EC0;&#x4E48;&#x6837;&#x5B50;,&#x6211;&#x53EA;&#x9700;&#x8981;&#x98DF;&#x6307;
        # print(hand_landmarks)
        #&#x6253;&#x5370;&#x770B;&#x770B;21&#x4E2A;&#x5173;&#x952E;&#x70B9;&#x957F;&#x4EC0;&#x4E48;&#x6837;&#x5B50;
        #&#x4E3A;x,y,z&#x4E09;&#x4E2A;&#x624B;&#x6307;&#x7684;&#x53C2;&#x6570;&#x4F4D;&#x7F6E;
        #&#x5982;&#x679C;&#x5C0F;&#x4E8E;30&#x6FC0;&#x6D3B;&#x65B9;&#x5757;&#xFF0C;&#x5426;&#x5219;&#x4E0D;&#x6FC0;&#x6D3B;
        if finger_len < 30:
        #&#x5224;&#x65AD;&#x6307;&#x5C16;&#x662F;&#x5426;&#x5728;&#x65B9;&#x5757;&#x4E0A;&#x9762;
           if (index_finger_x > square_x) and (index_finger_x <
           (square_x+square_width)) and (index_finger_y >
           square_y) and (index_finger_y < (square_y
           +square_width)):
               if on_square ==False:
                    print('&#x5728;&#x65B9;&#x5757;&#x4E0A;')
                    L1=abs(index_finger_x - square_x)#abs&#x4EE3;&#x8868;&#x7EDD;&#x5BF9;&#x503C;
                    L2=abs(index_finger_y - square_y)
                    on_square =True
                    square_color=(255,0,255)
               else:
                  # print('&#x4E0D;&#x5728;&#x65B9;&#x5757;&#x4E0A;')
                  pass
        else:
            on_square =False
            square_color=(255,0,0)

        if on_square: #&#x5982;&#x679C;&#x624B;&#x6307;&#x5728;&#x65B9;&#x5757;&#x4E0A;&#x9762;
            square_x = index_finger_x -L1#&#x6839;&#x636E;&#x7B97;&#x6CD5;
            square_y = index_finger_y -L2
    #&#x753B;&#x4E00;&#x4E2A;&#x65B9;&#x5757;,&#x53EA;&#x9700;&#x8981;&#x5DE6;&#x4E0A;&#x89D2;&#x7684;&#x70B9;&#xFF0C;&#x5176;&#x4ED6;&#x7684;&#x7531;&#x957F;&#x5BBD;&#x9AD8;&#x6765;&#x63A7;&#x5236;
    #cv2.rectangle(frame,(square_x,square_y),(square_x
    #+square_width,square_y+square_width),(255,0,0),-1)
    #&#x8981;&#x4F7F;&#x7528;&#x534A;&#x900F;&#x660E;&#x7684;&#x65B9;&#x5757;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x624B;&#x6307;
    overlay = frame.copy() #&#x7ED9;&#x4ED6;&#x4E00;&#x4E2A;&#x906E;&#x7F69;
    cv2.rectangle(frame,(square_x,square_y),(square_x
    +square_width,square_y+square_width),square_color,-1)
    frame = cv2.addWeighted(overlay,0.5,frame,0.5,0)#&#x505A;&#x4E00;&#x4E2A;&#x534A;&#x900F;&#x660E;

    #&#x663E;&#x793A;&#x56FE;&#x50CF;
    cv2.imshow('Virtual drag',frame)
    #&#x9000;&#x51FA;&#x6761;&#x4EF6;
    if cv2.waitKey(10) & 0xFF == 27:
        break
cap.release()
cv2.destroyAllWindows()

Original: https://blog.csdn.net/weixin_56522854/article/details/124462310
Author: 长坂坡394
Title: AI手势虚拟拖动方块使用OPENCV

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/704182/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球