OpenCV實(shí)戰(zhàn)之實(shí)現(xiàn)手勢(shì)虛擬縮放效果
0、項(xiàng)目介紹
本篇將會(huì)以HandTrackingModule為模塊,這里的模塊與之前的有所不同,請(qǐng)按照本篇為準(zhǔn),前面的HandTrackingModule不足以完成本項(xiàng)目,本篇將會(huì)通過(guò)手勢(shì)對(duì)本人的博客海報(bào)進(jìn)行縮放,具體效果可以看下面的效果展示。
1、項(xiàng)目展示
2、項(xiàng)目搭建
首先在一個(gè)文件夾下建立HandTrackingModule.py文件以及gesture_zoom.py,以及一張圖片,你可以按照你的喜好選擇,建議尺寸不要過(guò)大。
在這里用到了食指的索引8,可以完成左右手食指的手勢(shì)進(jìn)行縮放。
3、項(xiàng)目的代碼與講解
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
前面的類模塊,我不做過(guò)多的講解,它的新添加功能,我會(huì)在講解主文件的時(shí)候提到。
1.首先,導(dǎo)入我們需要的模塊,第一步先編寫打開(kāi)攝像頭的代碼,確保攝像頭的正常,并調(diào)節(jié)好窗口的設(shè)置——長(zhǎng)、寬、亮度,并且用htm(HandTrackingModule的縮寫,后面都是此意)handDetector調(diào)整置信度,讓我們檢測(cè)到手更準(zhǔn)確。
2.其次,用findHands的得到手的landmark,我所設(shè)定的手勢(shì)是左右手的大拇指、食指、中指高于其他四指,也就是這六根手指豎起,我們按照[1, 1, 1, 0, 0],[1, 1, 1, 0, 0]來(lái)設(shè)定,如果你不能確定,請(qǐng)解除這里的代碼;
#print(detector.fingersUp(handsimformation[0]),detector.fingersUp(handsimformation[1]))
3.然后,在這里有兩個(gè)handsimformation[0]['lmList'],handsimformation[0]["center"],分別代表我要取食指,和手掌中心點(diǎn),那么展示的時(shí)候是用的中心點(diǎn),可以按照個(gè)人的喜好去選擇手掌的索引,startDist=None表示為沒(méi)有檢測(cè)到的手時(shí)的起始長(zhǎng)度,而經(jīng)過(guò)每次迭代后,獲得的距離length-起始長(zhǎng)度,如果我增大手的距離,我就能得到一個(gè)較大的scale,由于打印的scale太大,我不希望它變化太快,所以做了二分后取整,如果得到的是一個(gè)負(fù)值,那么就縮小圖片,那么我們沒(méi)有檢測(cè)到手時(shí),就要令startDist=None。
4.之后來(lái)看,info = (x1, y1, x2, y2, cx, cy),根據(jù)索引得到中心值,然后,我們來(lái)獲取現(xiàn)在海報(bào)的大小,然后加上我們scale,實(shí)現(xiàn)動(dòng)態(tài)的縮放,但在這里要注意,這里進(jìn)行了整出2,在乘以2的操作,如果是參數(shù)是偶數(shù),我們無(wú)需理會(huì),但如果遇到了奇數(shù)就會(huì)出現(xiàn)少一個(gè)像素點(diǎn)的問(wèn)題,比如,值為9,整除2后得到的為4,4+4=8<9,所以為了確保正確,加了這一步。加入try...except語(yǔ)句是因?yàn)閳D像超出窗口時(shí)發(fā)出會(huì)發(fā)出警告,起到超出時(shí)此代碼將不起作用,回到窗口時(shí),可以繼續(xù)操作。
5.最后,打印出我們的幀率
到此這篇關(guān)于OpenCV實(shí)戰(zhàn)之實(shí)現(xiàn)手勢(shì)虛擬縮放效果的文章就介紹到這了,更多相關(guān)OpenCV手勢(shì)虛擬縮放內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python+pyqt5實(shí)現(xiàn)KFC點(diǎn)餐收銀系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了python+pyqt5實(shí)現(xiàn)KFC點(diǎn)餐收銀系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01python 利用PyAutoGUI快速構(gòu)建自動(dòng)化操作腳本
我們經(jīng)常遇到需要進(jìn)行大量重復(fù)操作的時(shí)候,比如:網(wǎng)頁(yè)上填表,對(duì) web 版本 OA 進(jìn)行操作,自動(dòng)化測(cè)試或者給新系統(tǒng)首次添加數(shù)據(jù)等,今天就利用PyAutoGUI構(gòu)建自動(dòng)化操作腳本完成這些重復(fù)的需求2021-05-05python xml.etree.ElementTree遍歷xml所有節(jié)點(diǎn)實(shí)例詳解
這篇文章主要介紹了python xml.etree.ElementTree遍歷xml所有節(jié)點(diǎn)實(shí)例詳解的相關(guān)資料,這里附有實(shí)例代碼,需要的朋友可以參考下2016-12-12virtualenv實(shí)現(xiàn)多個(gè)版本Python共存
virtualenv用于創(chuàng)建獨(dú)立的Python環(huán)境,多個(gè)Python相互獨(dú)立,互不影響,它能夠:1. 在沒(méi)有權(quán)限的情況下安裝新套件 2. 不同應(yīng)用可以使用不同的套件版本 3. 套件升級(jí)不影響其他應(yīng)用2017-08-08python對(duì)兩個(gè)數(shù)組進(jìn)行合并排列處理的兩種方法
最近遇到數(shù)組合并問(wèn)題,以此記錄解決方法,供大家參考學(xué)習(xí),下面這篇文章主要給大家介紹了關(guān)于python對(duì)兩個(gè)數(shù)組進(jìn)行合并排列處理的兩種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05python連接數(shù)據(jù)庫(kù)后通過(guò)占位符添加數(shù)據(jù)
在pymysql中支持對(duì)占位符的處理,開(kāi)發(fā)者需要在SQL中使用“%”定義占位符,在使用excute()方法執(zhí)行時(shí)對(duì)占位符的數(shù)據(jù)進(jìn)行填充即可,本文給大家介紹python連接數(shù)據(jù)庫(kù)后通過(guò)占位符添加數(shù)據(jù)的方法,需要的朋友參考下吧2021-12-12Python+OpenCV圖片局部區(qū)域像素值處理改進(jìn)版詳解
這篇文章主要為大家詳細(xì)介紹了Python+OpenCV圖片局部區(qū)域像素值處理的改進(jìn)版,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Python asyncio異步編程簡(jiǎn)單實(shí)現(xiàn)示例
本文主要介紹了Python asyncio異步編程簡(jiǎn)單實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01