各位同学好,今天和大家分享一下如何使用opencv+mediapipe完成远程手势调节图片尺寸的案例。先放张图看效果。当拇指和食指竖起时,根据食指间的连线的长度自由缩放图片尺寸。图片的中点始终位于指尖连线的中点。16代表FPS值

这里需要用到mediapipe中的手部关键点检测方法,并且需要判断哪根手指是弯下的,哪根手指是翘起来的。手部关键点检测方法有不明白的可以看我之前的一篇文章:【MediaPipe】(1) AI视觉,手部关键点实时跟踪,附python完整代码_立同学的博客-CSDN博客,判断哪个手指朝上的方法在后面的章节会介绍。


1. 导入工具包

# 安装工具包
pip install opencv-contrib-python  # 安装opencv
pip install mediapipe  # 安装mediapipe
# pip install mediapipe --user  #有user报错的话试试这个
pip install cvzone  # 安装cvzone# 导入工具包
import cv2
from cvzone.HandTrackingModule import HandDetector  # 手部追踪方法
import mediapipe as mp
import time

21个手部关键点信息如下,本节我们主要研究食指指尖"8"的坐标信息。


2. 手部关键点检测

(1) cvzone.HandTrackingModule.HandDetector()  是手部关键点检测方法

参数:

mode: 默认为 False,将输入图像视为视频流。它将尝试在第一个输入图像中检测手,并在成功检测后进一步定位手的坐标。在随后的图像中,一旦检测到所有 maxHands 手并定位了相应的手的坐标,它就会跟踪这些坐标,而不会调用另一个检测,直到它失去对任何一只手的跟踪。这减少了延迟,非常适合处理视频帧。如果设置为 True,则在每个输入图像上运行手部检测,用于处理一批静态的、可能不相关的图像。

maxHands: 最多检测几只手,默认为 2

detectionCon: 手部检测模型的最小置信值(0-1之间),超过阈值则检测成功。默认为 0.5

minTrackingCon: 坐标跟踪模型的最小置信值 (0-1之间),用于将手部坐标视为成功跟踪,不成功则在下一个输入图像上自动调用手部检测。将其设置为更高的值可以提高解决方案的稳健性,但代价是更高的延迟。如果 mode 为 True,则忽略这个参数,手部检测将在每个图像上运行。默认为 0.5

它的参数和返回值类似于官方函数 mediapipe.solutions.hands.Hands()

(2)cvzone.HandTrackingModule.HandDetector.findHands()    找到手部关键点并绘图

参数:

img: 需要检测关键点的帧图像,格式为BGR

draw: 是否需要在原图像上绘制关键点及识别框

flipType: 图像是否需要翻转,当视频图像和我们自己不是镜像关系时,设为True就可以了

返回值:

hands: 检测到的手部信息,包含:21个关键点坐标,检测框坐标及宽高,检测框中心坐标,检测出是哪一只手。

img: 返回绘制了关键点及连线后的图像

代码如下

# 远程手势缩放物体尺寸
import cv2
from cvzone.HandTrackingModule import HandDetector  # 手部追踪方法
import time#(1)获取摄像头信息
cap = cv2.VideoCapture(0)  # 0代表电脑自带的摄像头
cap.set(3, 1280)  # 设置显示框的宽
cap.set(4, 720)   # 设置显示框的高pTime = 0  # 处理第一帧图像的起始时间#(2)获取手部检测方法,传入参数,手部最小检测置信度0.8,最多检测2只手
detector = HandDetector(detectionCon=0.8, maxHands=2)#(3)处理每一帧图像
while True:# 返回是否读取成功,已经读取的帧图像success, img = cap.read()#(4)检测手部信息# 返回每只手的检测框信息hands,以及绘制后的手部图像hands, img = detector.findHands(img, draw=True, flipType=True) # fliptype代表是否翻转图像,上面以及翻转过了# 打印检测到的是左手还是右手,以及关键点的像素坐标print(hands)#(5)展示视频图像# 计算fpscTime = time.time()  # 处理每一帧图像所需的时间fps = 1/(cTime-pTime)pTime = cTime  # 更新处理下一帧图像的起始时间# 把fps值显示在图像上,img画板,显示字符串,显示的坐标位置,字体,字体大小,颜色,线条粗细cv2.putText(img, str(int(fps)), (30,50), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 显示图像,输入窗口名及图像数据# cv2.namedWindow("img", 0)  # 窗口大小可手动调整cv2.imshow('img', img)    if cv2.waitKey(20) & 0xFF==27:  #每帧滞留20毫秒后消失,ESC键退出break# 释放视频资源
cap.release()
cv2.destroyAllWindows()

打印某一帧中检测到的手部信息,lmList 代表每只手的21个手部关键点坐标bbox 代表检测框的左上角坐标,以及检测框的宽和高;center 代表检测框的中心坐标;type 代表检测出是哪一只手。

----------------------------------------------------
[{'lmList': [[1214, 809], [1111, 806], [1024, 769], [983, 732], [939, 727], [972, 576], [896, 461], [851, 392], [810, 331], [1052, 528], [985, 393], [943, 310], [905, 237], [1145, 514], [1109, 376], [1081, 289], [1052, 214], [1247, 525], [1256, 407], [1254, 332], [1245, 262]],
'bbox': (810, 214, 446, 595),
'center': (1033, 511),
'type': 'Right'},
{'lmList': [[174, 753], [329, 742], [469, 707], [589, 687], [695, 674], [451, 519], [539, 414], [596, 358], [653, 311], [394, 480], [488, 365], [558, 299], [628, 249], [321, 459], [409, 347], [481, 286], [555, 243], [232, 450], [293, 350], [348, 291], [411, 242]],
'bbox': (174, 242, 521, 511),
'center': (434, 497),
'type': 'Left'}]
----------------------------------------------------

显示结果如图:


3. 确定缩放方法

首先,我们通过 cv2.imread() 导入需要缩放的图像,img[0:180, 0:320] = img1,先把图像显示在视频帧图像的固定位置。

确定缩放方法的思路是,如果检测到两只手,并且这两只手是拇指和食指朝上,那么检测到的第一帧时的两只手的食指尖之间的距离,作为初始距离 startDist = length,接下去图片在这个初始距离的基础上进行缩放如果检测的手消失,那么就重置初始距离 startDist = None,将下一次检测到的指尖距离作为初始值。

通过 detector.findHands() 方法来检测哪个手指朝上,传入参数是每只手的所有关键点坐标。返回值是由0和1组成的长度为5的列表,0代表该手指弯曲,1代表该手指朝上。我们需要得到的是[1,1,0,0,0],即拇指和食指朝上,其他手指弯曲

通过 detector.findDistance() 方法来检测某两个关键点之间的距离。length, info, img  = distance = detector.findDistance(lmList1[8], lmList2[8], img), 返回值: length 代表两个关键点之间的距离,info 是一个6个元素组成的列表,包含关键点之间连线的起点、终点、中点坐标img 是绘制连线后的图像。

因此,我们在上述代码中补充。

# 远程手势缩放物体尺寸
import cv2
from cvzone.HandTrackingModule import HandDetector  # 手部追踪方法
import time#(1)获取摄像头信息
cap = cv2.VideoCapture(0)  # 0代表电脑自带的摄像头
cap.set(3, 1280)  # 设置显示框的宽
cap.set(4, 720)   # 设置显示框的高pTime = 0  # 处理第一帧图像的起始时间#(2)获取手部检测方法,传入参数,手部最小检测置信度0.8,最多检测2只手
detector = HandDetector(detectionCon=0.8, maxHands=2)startDist = None  # 设置一个初始距离#(3)处理每一帧图像
while True:# 返回是否读取成功,已经读取的帧图像success, img = cap.read()    #(4)检测手部信息# 返回每只手的检测框信息hands,以及绘制后的手部图像hands, img = detector.findHands(img, draw=True, flipType=True) # fliptype代表是否翻转图像#(5)导入需要调节的图片,图像的(w,h)为[1280,720]  img1 = cv2.imread('C:\\GameDownload\\Deep Learning\\TF2.jpg')# 由于我导入的图像太大了,这里把它缩小一下img1 = cv2.resize(img1, (320,180))# 把这张图片放在屏幕的固定位置,先指定h再指定w, 即img[h,w]img[0:180, 0:320] = img1# 放大和缩小步骤:当两只手的拇指和食指竖起,其他指弯下,那么就执行放大和缩小#(6)如果检测到有两只手,进行放大缩小的操作if len(hands) == 2:# 检测手指是否朝上的,hands[0]代表第一只手,hands[1]代表第二只手print('which up:', detector.fingersUp(hands[0]), detector.fingersUp(hands[1]))# 返回值是[1,1,0,0,0]代表一只手中拇指和食指竖起,其他指都没有竖起if detector.fingersUp(hands[0]) == [1,1,0,0,0] and detector.fingersUp(hands[1]) == [1,1,0,0,0]:# 通过两只手食指的关键点之间的距离来缩放图片lmList1 = hands[0]['lmList']  # 第一只手的关键点坐标信息,hands是一个字典lmList2 = hands[1]['lmList']  # 第二只手的关键点坐标信息# 第一次检测到食指间的距离if startDist is None:# 计算食指间的距离并绘图;食指的关键点索引是8;返回值:连线长度,连线的信息(起点、终点、中点坐标),绘制后的图像length, info, img  = distance = detector.findDistance(lmList1[8], lmList2[8], img)# print('length',length,'info',info)# 检测到的第一帧的食指间的距离作为初始距离,接下来超过这个长度就放大,小于这个长度就缩小startDist = length# 第一帧检测到距离之后,接下来变动的距离就是用于缩放图片大小length, info, img  = distance = detector.findDistance(lmList1[8], lmList2[8], img)# 计算变化量,正数代表放大,负数代表缩小scale = length - startDistprint('scale:',scale)# 如果两只手中至少有一只消失了,重置初始距离else:startDist = None#(7)展示视频图像# 计算fpscTime = time.time()  # 处理每一帧图像所需的时间fps = 1/(cTime-pTime)pTime = cTime  # 更新处理下一帧图像的起始时间# 把fps值显示在图像上,img画板,显示字符串,显示的坐标位置,字体,字体大小,颜色,线条粗细cv2.putText(img, str(int(fps)), (30,50), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 显示图像,输入窗口名及图像数据# cv2.namedWindow("img", 0)  # 窗口大小可手动调整cv2.imshow('img', img)    if cv2.waitKey(20) & 0xFF==27:  #每帧滞留20毫秒后消失,ESC键退出break# 释放视频资源
cap.release()
cv2.destroyAllWindows()

打印某几帧的结果,数字1代表该指时朝上的,0代表该指是弯着的。scale代表食指间的距离。

----------------------------------------------
which up: [1, 1, 0, 0, 0] [1, 1, 0, 0, 0]
scale: 225.00591450309486
which up: [1, 1, 0, 0, 0] [1, 1, 0, 0, 0]
scale: 18.837911081298728
which up: [1, 1, 0, 0, 0] [1, 1, 0, 0, 0]
scale: -30.173165115569134
which up: [1, 1, 0, 0, 0] [1, 1, 0, 0, 0]
scale: -28.422575826465106
-----------------------------------------------

显示结果如图,需要改变尺寸的图片暂时位于左上方,当拇指和食指朝上时绘制指尖连线,并计算连线长度。


4. 按比例缩放图片

info中存放指尖连线的起点、终点、中点坐标,其中 cx, cy = info[4:] 代表连线中点的坐标。现在让图片的中点落在指尖连线的中点上,使图片的位置随手指位置而实时发生变化

在计算中点时用到 newH//2newW//2 ,这时候需要保证新的宽和高能被2整除。否则在执行 img[cy - newH//2:cy + newH//2, cx - newW//2:cx + newW//2] = img1 时,屏幕上划分给图片的shape和图片自身的shape不一致,从而导致程序报错。因此在执行之前,通过int(((h1+scale)//2)*2)int(((w1+scale)//2)*2)  ,提前使宽高能被整除。如果是奇数除以2,也只是忽略了一个像素,不会有影响。

当我们把图片放的过大,或图像坐标出现负数时,程序会抛出异常不能执行,因此使用 try,except 方法,当遇到异常就执行except中的内容,这里是pass,直接跳过;没发出异常就正常运行try中的内容

因此,在上述代码中补充。

# 远程手势缩放物体尺寸
import cv2
from cvzone.HandTrackingModule import HandDetector  # 手部追踪方法
import time#(1)获取摄像头信息
cap = cv2.VideoCapture(0)  # 0代表电脑自带的摄像头
cap.set(3, 1280)  # 设置显示框的宽
cap.set(4, 720)   # 设置显示框的高pTime = 0  # 处理第一帧图像的起始时间#(2)获取手部检测方法,传入参数,手部最小检测置信度0.8,最多检测2只手
detector = HandDetector(detectionCon=0.8, maxHands=2)startDist = None  # 设置一个初始距离scale = 0  # 设置一个初始的需要缩放的大小cx, cy = 200, 200  # 确定初始的图像中心点在屏幕上的显示位置#(3)处理每一帧图像
while True:# 返回是否读取成功,已经读取的帧图像success, img = cap.read()    # 翻转图像,保证摄像机画面和人的动作是镜像# img = cv2.flip(img, flipCode=1)  #0竖直翻转,1水平翻转#(4)检测手部信息# 返回每只手的检测框信息hands,以及绘制后的手部图像hands, img = detector.findHands(img, draw=True, flipType=True) # fliptype代表是否翻转图像#(5)导入需要调节的图片,图像的(w,h)为[1280,720]  img1 = cv2.imread('C:\\GameDownload\\Deep Learning\\TF2.jpg')# 由于我导入的图像太大了,这里把它缩小一下img1 = cv2.resize(img1, (320,180))# 把这张图片放在屏幕的固定位置,先指定h再指定w, 即img[h,w]# img[0:180, 0:320] = img1# 放大和缩小步骤:当两只手的拇指和食指竖起,其他指弯下,那么就执行放大和缩小#(6)如果检测到有两只手,进行放大缩小的操作if len(hands) == 2:# 检测手指是否朝上的,hands[0]代表第一只手,hands[1]代表第二只手# print('which up:', detector.fingersUp(hands[0]), detector.fingersUp(hands[1]))# 返回值是[1,1,0,0,0]代表一只手中拇指和食指竖起,其他指都没有竖起if detector.fingersUp(hands[0]) == [1,1,0,0,0] and detector.fingersUp(hands[1]) == [1,1,0,0,0]:# 通过两只手食指的关键点之间的距离来缩放图片lmList1 = hands[0]['lmList']  # 第一只手的关键点坐标信息,hands是一个字典lmList2 = hands[1]['lmList']  # 第二只手的关键点坐标信息# 第一次检测到食指间的距离if startDist is None:# 计算食指间的距离并绘图;食指的关键点索引是8;返回值:连线长度,连线的信息(起点、终点、中点坐标),绘制后的图像length, info, img  = distance = detector.findDistance(lmList1[8], lmList2[8], img)# print('length',length,'info',info)# 检测到的第一帧的食指间的距离作为初始距离,接下来超过这个长度就放大,小于这个长度就缩小startDist = length# 第一帧检测到距离之后,接下来变动的距离就是用于缩放图片大小length, info, img  = distance = detector.findDistance(lmList1[8], lmList2[8], img)# 计算变化量,正数代表放大,负数代表缩小。scale的变化范围过大,除以2使它变化缓慢一些scale = (length - startDist) // 2#(7)按比例缩放图像# 获取食指连线的中心点坐标,用于实时改变图像的位置cx, cy = info[4:]  # info是一个列表索引4和5存放中心点坐标# 如果两只手中至少有一只消失了,重置初始距离else:startDist = Nonetry:  # 用于处理异常,因为一旦缩放的区间变成负数,就会报错# 确定需要缩放的图像的宽高h1, w1, _ = img1.shape  # 获取原始图像的宽高# 如果scale是奇数,那么计算结果不能被2整除,使得img中的空出的位置的shape和img1的shape不一样# newH, newW = h1+scale, w1+scale  newH, newW = int(((h1+scale)//2)*2), int(((w1+scale)//2)*2)  # 改变原图像的shape,先指定宽,后指定高img1 = cv2.resize(img1, (newW, newH))# 实时改变图像的位置,使图像中心点随着食指间的连线的中点的位置变化# 确保newH和newW可以被2整除,不然重组后的img中的shape和img1的shape不同img[cy - newH//2:cy + newH//2, cx - newW//2:cx + newW//2] = img1  # 先指定高,再指定宽except:  # 如果报错了的话上面try的内容不起作用pass#(7)展示视频图像# 计算fpscTime = time.time()  # 处理每一帧图像所需的时间fps = 1/(cTime-pTime)pTime = cTime  # 更新处理下一帧图像的起始时间# 把fps值显示在图像上,img画板,显示字符串,显示的坐标位置,字体,字体大小,颜色,线条粗细cv2.putText(img, str(int(fps)), (30,50), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 显示图像,输入窗口名及图像数据# cv2.namedWindow("img", 0)  # 窗口大小可手动调整cv2.imshow('img', img)    if cv2.waitKey(1) & 0xFF==27:  #每帧滞留1毫秒后消失,ESC键退出break# 释放视频资源
cap.release()
cv2.destroyAllWindows()

显示结果如下:

【机器视觉案例】(5) AI视觉,手势调节物体尺寸,附python完整代码相关推荐

  1. 【MediaPipe】(3) AI视觉,人脸识别,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe完成人脸实时跟踪检测,先放张图看效果,FPS值为14,右侧的输出为:每帧图像是人脸的概率,检测框的左上角坐标及框的宽高. 有需要的可以使用 cv ...

  2. 【机器视觉案例】(10) AI视觉搭积木,手势移动虚拟物体,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv+mediapipe 完成手势移动虚拟物体,可自定义各种形状的物体,通过手势搭积木.先放张图看效果. 规则:当食指在某个物体内部,并且中指指尖和食指 ...

  3. 【机器视觉案例】(9) AI视觉,手势控制电脑键盘,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv+mediapipe 完成远程手势控制电脑键盘.感兴趣的可以看一下我前面一篇手势控制电脑鼠标:https://blog.csdn.net/dgvv4 ...

  4. 【机器视觉案例】(5) AI视觉,远程手势控制虚拟计算器,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe+Opencv完成虚拟计算器,先放张图看效果.FPS值为29,食指和中指距离小于规定阈值则认为点击按键,为避免重复数字出现,规定每20帧可点击一 ...

  5. 【MediaPipe】(4) AI视觉,远程手势调节电脑音量,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe完成手势调节电脑音量,先放张图看效果. 注意!! 本节需要用到手部关键点的实时跟踪,我已经在之前的文章中详细写过了,本节会直接使用,有疑问的同学 ...

  6. 【机器视觉案例】(6) AI视觉,距离测量,自制AI小游戏,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv + mediapipe 创建一个AI视觉小游戏,先放图看效果. 游戏规则,用手按下屏幕上的圆形按钮,每按一次后松开,按钮就随机出现在屏幕上的一个位 ...

  7. 【机器视觉案例】(8) AI视觉,手势控制电脑鼠标,附python完整代码

    各位同学好,今天和大家分享一下如何使用 MediaPipe+Opencv 通过手势识别来控制电脑鼠标的移动和点击,如果有兴趣的话,可以代替鼠标去打游戏.先放图看效果.用画图板来测试 黄框代表电脑屏幕的 ...

  8. 【机器视觉案例】(12) 自制AI视觉小游戏--贪吃蛇,附python完整代码

    各位同学好,今天和大家分享一下如何使用 mediapipe+opencv 自制贪吃蛇小游戏.先放张图看效果. 规则:食指指尖控制蛇头,指尖每接触到黄色方块,计数加一,蛇身变长,方块随机切换位置.如果指 ...

  9. 【机器视觉案例】(16) 自制视觉小游戏--桌上冰球,附python完整代码

    大家好,今天和各位分享一下如何使用 mediapipe+opencv 制作桌上冰球的交互式小游戏.先放张图看效果. 规则如下:左手控制白色球拍:右手控制紫色球拍:球拍只能上下移动:红色圆形就是冰球:球 ...

最新文章

  1. 在Asp.Net MVC中实现RequiredIf标签对Model中的属性进行验证
  2. python软件是免费的吗-python语言是免费还是收费的?
  3. matlab FAQ
  4. 【重难点】【事务 03】分布式事务
  5. JMETER分布式部署注意事项
  6. Bailian4133 垃圾炸弹【枚举】
  7. Linux下安装PHP扩展 pdo_sqlsrv
  8. 光猫修改html灰色选项,电信光猫怎么设置(修改)wifi密码?
  9. 力天创见客流统计标书制作
  10. 关于A卡和N卡对opengl驱动问题
  11. Siebel学习笔记
  12. html div 自动滚动到底部,javascript让DIV的滚动自动滚动到最底部-4种方法
  13. 后代选择器和子代选择器
  14. css鼠标点在文字上背景透明,CSS实现文字半透明显示在图片上方法(示例代码)
  15. leetcode 题解 904.水果成篮(Typescript)
  16. vue使用vue-dplayer播放m3u8视频
  17. TCP/IP协议及常见状态码说明(SYN,FIN,ACK,PSH,RST)
  18. GQM 概述:构建研发效能度量体系的根本方法
  19. 计算机408王道考研资料、笔记分享 ~ ~
  20. sap模块介绍_SAP会计科目之 自动记账

热门文章

  1. Installation failed with message Invalid File:(Application Installatino Failed)
  2. 漫谈五种IO模型(主讲IO多路复用)
  3. 闰年流程图(18网三袁昳)
  4. 如何参与贡献Dubbo社区
  5. spring boot 文件上传工具类(bug 已修改)
  6. 模拟文件上传(一):手动文件上传
  7. C++ 笔记(22)— STL string 类(字符串赋值、访问、拼接、查找、翻转、大小写转换)
  8. 如何找到自己的优势并坚定信念执行下去
  9. 计算机启动和操作系统加载小话
  10. C#实现网页截图功能