OpenCV實戰(zhàn)之實現(xiàn)手勢虛擬縮放效果
0、項目介紹
本篇將會以HandTrackingModule為模塊,這里的模塊與之前的有所不同,請按照本篇為準,前面的HandTrackingModule不足以完成本項目,本篇將會通過手勢對本人的博客海報進行縮放,具體效果可以看下面的效果展示。
1、項目展示

2、項目搭建
首先在一個文件夾下建立HandTrackingModule.py文件以及gesture_zoom.py,以及一張圖片,你可以按照你的喜好選擇,建議尺寸不要過大。

在這里用到了食指的索引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.首先,導入我們需要的模塊,第一步先編寫打開攝像頭的代碼,確保攝像頭的正常,并調(diào)節(jié)好窗口的設(shè)置——長、寬、亮度,并且用htm(HandTrackingModule的縮寫,后面都是此意)handDetector調(diào)整置信度,讓我們檢測到手更準確。
2.其次,用findHands的得到手的landmark,我所設(shè)定的手勢是左右手的大拇指、食指、中指高于其他四指,也就是這六根手指豎起,我們按照[1, 1, 1, 0, 0],[1, 1, 1, 0, 0]來設(shè)定,如果你不能確定,請解除這里的代碼;
#print(detector.fingersUp(handsimformation[0]),detector.fingersUp(handsimformation[1]))
3.然后,在這里有兩個handsimformation[0]['lmList'],handsimformation[0]["center"],分別代表我要取食指,和手掌中心點,那么展示的時候是用的中心點,可以按照個人的喜好去選擇手掌的索引,startDist=None表示為沒有檢測到的手時的起始長度,而經(jīng)過每次迭代后,獲得的距離length-起始長度,如果我增大手的距離,我就能得到一個較大的scale,由于打印的scale太大,我不希望它變化太快,所以做了二分后取整,如果得到的是一個負值,那么就縮小圖片,那么我們沒有檢測到手時,就要令startDist=None。
4.之后來看,info = (x1, y1, x2, y2, cx, cy),根據(jù)索引得到中心值,然后,我們來獲取現(xiàn)在海報的大小,然后加上我們scale,實現(xiàn)動態(tài)的縮放,但在這里要注意,這里進行了整出2,在乘以2的操作,如果是參數(shù)是偶數(shù),我們無需理會,但如果遇到了奇數(shù)就會出現(xiàn)少一個像素點的問題,比如,值為9,整除2后得到的為4,4+4=8<9,所以為了確保正確,加了這一步。加入try...except語句是因為圖像超出窗口時發(fā)出會發(fā)出警告,起到超出時此代碼將不起作用,回到窗口時,可以繼續(xù)操作。
5.最后,打印出我們的幀率
到此這篇關(guān)于OpenCV實戰(zhàn)之實現(xiàn)手勢虛擬縮放效果的文章就介紹到這了,更多相關(guān)OpenCV手勢虛擬縮放內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python抓取聚劃算商品分析頁面獲取商品信息并以XML格式保存到本地
這篇文章主要為大家詳細介紹了Python抓取聚劃算商品分析頁面獲取商品信息,并以XML格式保存到本地的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02
selenium+python 去除啟動的黑色cmd窗口方法
今天小編就為大家分享一篇selenium+python 去除啟動的黑色cmd窗口方法。具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
django創(chuàng)建最簡單HTML頁面跳轉(zhuǎn)方法
今天小編就為大家分享一篇django創(chuàng)建最簡單HTML頁面跳轉(zhuǎn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08
python射線法判斷一個點在圖形區(qū)域內(nèi)外
這篇文章主要為大家詳細介紹了python射線法判斷一個點在圖形區(qū)域內(nèi)外,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-06-06
django實現(xiàn)HttpResponse返回json數(shù)據(jù)為中文
這篇文章主要介紹了django實現(xiàn)HttpResponse返回json數(shù)據(jù)為中文,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Python?eval()和exec()函數(shù)使用詳解
exec函數(shù)執(zhí)行的是python語句,沒有返回值,eval函數(shù)執(zhí)行的是python表達式,有返回值,exec函數(shù)和eval函數(shù)都可以傳入命名空間作為參數(shù),本文給大家介紹下Python?eval()和exec()函數(shù),感興趣的朋友跟隨小編一起看看吧2022-11-11

