OpenCV实战之实现手势虚拟缩放效果

作者:夏天是冰红茶 时间:2023-04-06 12:51:09 

0、项目介绍

本篇将会以HandTrackingModule为模块,这里的模块与之前的有所不同,请按照本篇为准,前面的HandTrackingModule不足以完成本项目,本篇将会通过手势对本人的博客海报进行缩放,具体效果可以看下面的效果展示。

1、项目展示

OpenCV实战之实现手势虚拟缩放效果

2、项目搭建

首先在一个文件夹下建立HandTrackingModule.py文件以及gesture_zoom.py,以及一张图片,你可以按照你的喜好选择,建议尺寸不要过大。

OpenCV实战之实现手势虚拟缩放效果

在这里用到了食指的索引8,可以完成左右手食指的手势进行缩放。

3、项目的代码与讲解

HandTrackingModule.py:

import cv2
import mediapipe as mp
import math

class handDetector:

def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):
       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 findHands(self, img, draw=True, flipType=True):
       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, pz = int(lm.x * w), int(lm.y * h), int(lm.z * w)
                   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):
       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):
       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][0:2], lmList2[8][0:2], 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()

gesture_zoom.py :

import cv2
import mediapipe as mp
import time
import HandTrackingModule as htm

startDist = None
scale = 0
cx, cy = 500,200
wCam, hCam = 1280,720
pTime = 0

cap = cv2.VideoCapture(0)
cap.set(3, wCam)
cap.set(4, hCam)
cap.set(10,150)

detector = htm.handDetector(detectionCon=0.75)

while 1:
   success, img = cap.read()
   handsimformation,img=detector.findHands(img)

img1 = cv2.imread("1.png")
   # img[0:360, 0:260] = img1
   if len(handsimformation)==2:

# print(detector.fingersUp(handsimformation[0]),detector.fingersUp(handsimformation[1]))
       #detector.fingersUp(handimformation[0]右手
       if detector.fingersUp(handsimformation[0]) == [1, 1, 1, 0, 0] and \
               detector.fingersUp(handsimformation[1]) == [1, 1, 1 ,0, 0]:
           lmList1 = handsimformation[0]['lmList']
           lmList2 = handsimformation[1]['lmList']
           if startDist is None:
               #lmList1[8],lmList2[8]右、左手指尖

# length,info,img=detector.findDistance(lmList1[8],lmList2[8], img)
               length, info, img = detector.findDistance(handsimformation[0]["center"], handsimformation[1]["center"], img)
               startDist=length
           length, info, img = detector.findDistance(handsimformation[0]["center"], handsimformation[1]["center"], img)
           # length, info, img = detector.findDistance(lmList1[8], lmList2[8], img)
           scale=int((length-startDist)//2)
           cx, cy=info[4:]
           print(scale)
   else:
       startDist=None
   try:
       h1, w1, _ = img1.shape
       newH, newW = ((h1 + scale) // 2) * 2, ((w1 + scale) // 2) * 2
       img1 = cv2.resize(img1, (newW, newH))

img[cy-newH//2:cy+ newH//2, cx-newW//2:cx+newW//2] = img1
   except:
       pass
   #################打印帧率#####################
   cTime = time.time()
   fps = 1 / (cTime - pTime)
   pTime = cTime
   cv2.putText(img, f'FPS: {int(fps)}', (40, 50), cv2.FONT_HERSHEY_COMPLEX,
               1, (100, 0, 255), 3)

cv2.imshow("image",img)
   k=cv2.waitKey(1)
   if k==27:
       break

前面的类模块,我不做过多的讲解,它的新添加功能,我会在讲解主文件的时候提到。

1.首先,导入我们需要的模块,第一步先编写打开摄像头的代码,确保摄像头的正常,并调节好窗口的设置&mdash;&mdash;长、宽、亮度,并且用htm(HandTrackingModule的缩写,后面都是此意)handDetector调整置信度,让我们检测到手更准确。

2.其次,用findHands的得到手的landmark,我所设定的手势是左右手的大拇指、食指、中指高于其他四指,也就是这六根手指竖起,我们按照[1, 1, 1, 0, 0],[1, 1, 1, 0, 0]来设定,如果你不能确定,请解除这里的代码;

#print(detector.fingersUp(handsimformation[0]),detector.fingersUp(handsimformation[1]))

3.然后,在这里有两个handsimformation[0]['lmList'],handsimformation[0]["center"],分别代表我要取食指,和手掌中心点,那么展示的时候是用的中心点,可以按照个人的喜好去选择手掌的索引,startDist=None表示为没有检测到的手时的起始长度,而经过每次迭代后,获得的距离length-起始长度,如果我增大手的距离,我就能得到一个较大的scale,由于打印的scale太大,我不希望它变化太快,所以做了二分后取整,如果得到的是一个负值,那么就缩小图片,那么我们没有检测到手时,就要令startDist=None。

4.之后来看,info = (x1, y1, x2, y2, cx, cy),根据索引得到中心值,然后,我们来获取现在海报的大小,然后加上我们scale,实现动态的缩放,但在这里要注意,这里进行了整出2,在乘以2的操作,如果是参数是偶数,我们无需理会,但如果遇到了奇数就会出现少一个像素点的问题,比如,值为9,整除2后得到的为4,4+4=8<9,所以为了确保正确,加了这一步。加入try...except语句是因为图像超出窗口时发出会发出警告,起到超出时此代码将不起作用,回到窗口时,可以继续操作。

5.最后,打印出我们的帧率

来源:https://blog.csdn.net/m0_62919535/article/details/127714724

标签:OpenCV,手势,虚拟,缩放
0
投稿

猜你喜欢

  • PHP autoload使用方法及步骤详解

    2023-08-22 13:05:44
  • 从零开始写jQuery框架

    2008-12-24 13:37:00
  • asp 判断是否为搜索引擎蜘蛛的代码

    2011-03-10 11:03:00
  • ASP下批量删除数据的两种方法

    2011-02-05 11:01:00
  • Python 常用模块threading和Thread模块之线程池

    2022-02-20 05:39:08
  • 9行Python3代码实现批量提取PDF文件的指定内容

    2023-02-12 03:22:41
  • python处理xml文件操作详解

    2021-11-10 10:31:24
  • Python入门之三角函数sin()函数实例详解

    2021-11-09 18:31:21
  • itchat-python搭建微信机器人(附示例)

    2022-05-04 00:00:54
  • Dhtml网页实例教程

    2007-10-09 13:39:00
  • Python破解excel进入密码的过程详解

    2021-06-14 03:06:25
  • Python条件语句与循环语句

    2023-01-03 05:07:21
  • Python类装饰器实现方法详解

    2021-11-15 20:01:05
  • Django实现网页分页功能

    2021-04-05 22:12:18
  • Python机器学习pytorch交叉熵损失函数的深刻理解

    2021-12-11 06:09:40
  • Python中字符编码简介、方法及使用建议

    2021-10-11 21:58:33
  • mysql 控制台程序的提示符 prompt 字符串设置

    2024-01-26 01:42:11
  • 使用python爬取taptap网站游戏截图的步骤

    2021-09-17 07:44:34
  • SQL Server中使用DTS设计器进行数据转移

    2009-01-08 16:15:00
  • Python爬虫文件下载图文教程

    2023-11-18 23:59:03
  • asp之家 网络编程 m.aspxhome.com