使用Mediapipe
參考資料21 hand landmarks
水平鏡像處理
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己電腦的攝像頭
cap.set(3, 1280) # 寬
cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=2)
# 處理每一幀影像
while True:
success, img = cap.read()
# 翻轉影像,使自身和攝像頭中的自己呈鏡像關系
img = cv2.flip(img, 1) # 將手水平翻轉
hands, img = detector.findHands(img)
cv2.imshow("Image", img)
cv2.waitKey(1)
修改代碼
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己電腦的攝像頭
cap.set(3, 1280) # 寬
cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)
# 處理每一幀影像
while True:
success, img = cap.read()
# 翻轉影像,使自身和攝像頭中的自己呈鏡像關系
img = cv2.flip(img, 1) # 將手水平翻轉
hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正確
cv2.imshow("Image", img)
cv2.waitKey(1)
問題修復完畢
觀察手的資訊
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己電腦的攝像頭
cap.set(3, 1280) # 寬
cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)
# 處理每一幀影像
while True:
success, img = cap.read()
# 翻轉影像,使自身和攝像頭中的自己呈鏡像關系
img = cv2.flip(img, 1) # 將手水平翻轉
hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正確
print(hands)
cv2.imshow("Image", img)
cv2.waitKey(1)
輸出結果
[{‘lmList’: [[1088, 633, 0], [1012, 655, -24], [940, 629, -32], [894, 596, -35], [875, 562, -36], [949, 504, -17], [891, 441, -16], [862, 419, -16], [838, 403, -16], [995, 480, -3], [943, 418, 8], [924, 426, 17], [920, 440, 22], [1044, 480, 8], [998, 455, 17], [987, 489, 21], [993, 513, 23], [1085, 492, 19], [1048, 477, 27], [1036, 505, 35], [1041, 528, 40]], ‘bbox’: (838, 403, 250, 252), ‘center’: (963, 529), ‘type’: ‘Left’}]
做個小蛇
import math
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己電腦的攝像頭
cap.set(3, 1280) # 寬
cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)
class SnakeGameClass:
def __init__(self): # 構造方法
self.points = [] # 蛇身上所有的點
self.lengths = [] # 每個點之間的長度
self.currentLength = 0 # 蛇的總長
self.allowedLength = 150 # 蛇允許的總長度
self.previousHead = 0, 0 # 第二個頭結點
def update(self, imgMain, currentHead): # 實體方法
px, py = self.previousHead
cx, cy = currentHead
self.points.append([cx, cy]) # 添加蛇的點串列節點
distance = math.hypot(cx - px, cy - py) # 兩點之間的距離
self.lengths.append(distance) # 添加蛇的距離串列內容
self.currentLength += distance
self.previousHead = cx, cy
# Draw Snake
for i, point in enumerate(self.points):
if i != 0:
cv2.line(imgMain, self.points[i - 1], self.points[i], (0, 0, 255), 20)
# 對串列最后一個點也就是蛇頭畫為紫色點
cv2.circle(imgMain, self.points[-1], 20, (200, 0, 200), cv2.FILLED)
return imgMain
game = SnakeGameClass()
# 處理每一幀影像
while True: # 不斷迭代更新
success, img = cap.read()
# 翻轉影像,使自身和攝像頭中的自己呈鏡像關系
img = cv2.flip(img, 1) # 將手水平翻轉
hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正確
if hands:
lmList = hands[0]['lmList'] # hands是由N個字典組成的串列
pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐標
img = game.update(img, pointIndex)
cv2.imshow("Image", img)
cv2.waitKey(1)
添加甜甜圈
import math
import random
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己電腦的攝像頭
cap.set(3, 1280) # 寬
cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)
class SnakeGameClass:
def __init__(self, pathFood): # 構造方法
self.points = [] # 蛇身上所有的點
self.lengths = [] # 每個點之間的長度
self.currentLength = 0 # 蛇的總長
self.allowedLength = 150 # 蛇允許的總長度
self.previousHead = 0, 0 # 第二個頭結點
self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED)
self.hFood, self.wFood, _ = self.imgFood.shape
self.foodPoint = 0, 0
self.randomFoodLocation()
def randomFoodLocation(self):
self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
def update(self, imgMain, currentHead): # 實體方法
px, py = self.previousHead
cx, cy = currentHead
self.points.append([cx, cy]) # 添加蛇的點串列節點
distance = math.hypot(cx - px, cy - py) # 兩點之間的距離
self.lengths.append(distance) # 添加蛇的距離串列內容
self.currentLength += distance
self.previousHead = cx, cy
# Length Reduction
if self.currentLength > self.allowedLength:
for i, length in enumerate(self.lengths):
self.currentLength -= length
self.lengths.pop(i)
self.points.pop(i)
if self.currentLength < self.allowedLength:
break
# Draw Snake
if self.points:
for i, point in enumerate(self.points):
if i != 0:
cv2.line(imgMain, self.points[i - 1], self.points[i], (0, 0, 255), 20)
# 對串列最后一個點也就是蛇頭畫為紫色點
cv2.circle(imgMain, self.points[-1], 20, (200, 0, 200), cv2.FILLED)
# Draw Food
rx, ry = self.foodPoint
imgMain = cvzone.overlayPNG(imgMain, self.imgFood,
(rx - self.wFood // 2, ry - self.hFood // 2))
return imgMain
game = SnakeGameClass("donut.png")
# 處理每一幀影像
while True: # 不斷迭代更新
success, img = cap.read()
# 翻轉影像,使自身和攝像頭中的自己呈鏡像關系
img = cv2.flip(img, 1) # 將手水平翻轉
hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正確
if hands:
lmList = hands[0]['lmList'] # hands是由N個字典組成的串列
pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐標
img = game.update(img, pointIndex)
cv2.imshow("Image", img)
cv2.waitKey(1)
donut.png
部分代碼解釋說明
imgMain = cvzone.overlayPNG(imgMain, self.imgFood,
(rx - self.wFood // 2, ry - self.hFood // 2))
為什么不是
imgMain = cvzone.overlayPNG(imgMain, self.imgFood, (rx , ry))
那是因為,隨機生成一個點后,有坐標(x,y)
增加分數機制
import math
import random
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己電腦的攝像頭
cap.set(3, 1280) # 寬
cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)
class SnakeGameClass:
def __init__(self, pathFood): # 構造方法
self.points = [] # 蛇身上所有的點
self.lengths = [] # 每個點之間的長度
self.currentLength = 0 # 蛇的總長
self.allowedLength = 150 # 蛇允許的總長度
self.previousHead = 0, 0 # 第二個頭結點
self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED)
self.hFood, self.wFood, _ = self.imgFood.shape
self.foodPoint = 0, 0
self.randomFoodLocation()
self.score = 0
def randomFoodLocation(self):
self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
def update(self, imgMain, currentHead): # 實體方法
px, py = self.previousHead
cx, cy = currentHead
self.points.append([cx, cy]) # 添加蛇的點串列節點
distance = math.hypot(cx - px, cy - py) # 兩點之間的距離
self.lengths.append(distance) # 添加蛇的距離串列內容
self.currentLength += distance
self.previousHead = cx, cy
# Length Reduction
if self.currentLength > self.allowedLength:
for i, length in enumerate(self.lengths):
self.currentLength -= length
self.lengths.pop(i)
self.points.pop(i)
if self.currentLength < self.allowedLength:
break
# Check if snake ate the food
rx, ry = self.foodPoint
if rx - self.wFood // 2 < cx < rx + self.wFood // 2 and \
ry - self.hFood // 2 < cy < ry + self.hFood // 2:
self.randomFoodLocation()
self.allowedLength += 50
self.score += 1
print(self.score)
# Draw Snake
if self.points:
for i, point in enumerate(self.points):
if i != 0:
cv2.line(imgMain, self.points[i - 1], self.points[i], (0, 0, 255), 20)
# 對串列最后一個點也就是蛇頭畫為紫色點
cv2.circle(imgMain, self.points[-1], 20, (200, 0, 200), cv2.FILLED)
# Draw Food
imgMain = cvzone.overlayPNG(imgMain, self.imgFood,
(rx - self.wFood // 2, ry - self.hFood // 2))
return imgMain
game = SnakeGameClass("donut.png")
# 處理每一幀影像
while True: # 不斷迭代更新
success, img = cap.read()
# 翻轉影像,使自身和攝像頭中的自己呈鏡像關系
img = cv2.flip(img, 1) # 將手水平翻轉
hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正確
if hands:
lmList = hands[0]['lmList'] # hands是由N個字典組成的串列
pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐標
img = game.update(img, pointIndex)
cv2.imshow("Image", img)
cv2.waitKey(1)
完整代碼(后期需要不斷優化完善,持續更新中)
import math
import random
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己電腦的攝像頭
cap.set(3, 1280) # 寬
cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)
class SnakeGameClass:
def __init__(self, pathFood): # 構造方法
self.points = [] # 蛇身上所有的點
self.lengths = [] # 每個點之間的長度
self.currentLength = 0 # 蛇的總長
self.allowedLength = 150 # 蛇允許的總長度
self.previousHead = 0, 0 # 第二個頭結點
self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED)
self.hFood, self.wFood, _ = self.imgFood.shape
self.foodPoint = 0, 0
self.randomFoodLocation()
self.score = 0
self.gameOver = False
def randomFoodLocation(self):
self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
def update(self, imgMain, currentHead): # 實體方法
if self.gameOver:
cvzone.putTextRect(imgMain, "Game Over", [300, 400],
scale=7, thickness=5, offset=20)
cvzone.putTextRect(imgMain, f'Your Score:{self.score}', [300, 550],
scale=7, thickness=5, offset=20)
else:
px, py = self.previousHead
cx, cy = currentHead
self.points.append([cx, cy]) # 添加蛇的點串列節點
distance = math.hypot(cx - px, cy - py) # 兩點之間的距離
self.lengths.append(distance) # 添加蛇的距離串列內容
self.currentLength += distance
self.previousHead = cx, cy
# Length Reduction
if self.currentLength > self.allowedLength:
for i, length in enumerate(self.lengths):
self.currentLength -= length
self.lengths.pop(i)
self.points.pop(i)
if self.currentLength < self.allowedLength:
break
# Check if snake ate the food
rx, ry = self.foodPoint
if rx - self.wFood // 2 < cx < rx + self.wFood // 2 and \
ry - self.hFood // 2 < cy < ry + self.hFood // 2:
self.randomFoodLocation()
self.allowedLength += 50
self.score += 1
print(self.score)
# Draw Snake
if self.points:
for i, point in enumerate(self.points):
if i != 0:
cv2.line(imgMain, self.points[i - 1], self.points[i], (0, 0, 255), 20)
# 對串列最后一個點也就是蛇頭畫為紫色點
cv2.circle(imgMain, self.points[-1], 20, (200, 0, 200), cv2.FILLED)
# Draw Food
imgMain = cvzone.overlayPNG(imgMain, self.imgFood,
(rx - self.wFood // 2, ry - self.hFood // 2))
cvzone.putTextRect(imgMain, f'Your Score:{self.score}', [50, 80],
scale=3, thickness=5, offset=10)
# Check for Collision
pts = np.array(self.points[:-2], np.int32)
pts = pts.reshape((-1, 1, 2)) # 重塑為一個行數未知但只有一列且每個元素有2個子元素的矩陣
cv2.polylines(imgMain, [pts], False, (0, 200, 0), 3)
# 第三個引數是False,我們得到的是不閉合的線
minDist = cv2.pointPolygonTest(pts, (cx, cy), True)
# 引數True表示輸出該像素點到輪廓最近距離
if -1 <= minDist <= 1:
print("Hit")
self.gameOver = True
self.points = [] # 蛇身上所有的點
self.lengths = [] # 每個點之間的長度
self.currentLength = 0 # 蛇的總長
self.allowedLength = 150 # 蛇允許的總長度
self.previousHead = 0, 0 # 第二個頭結點
self.randomFoodLocation()
return imgMain
game = SnakeGameClass("donut.png")
# 處理每一幀影像
while True: # 不斷迭代更新
success, img = cap.read()
# 翻轉影像,使自身和攝像頭中的自己呈鏡像關系
img = cv2.flip(img, 1) # 將手水平翻轉
hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正確
if hands:
lmList = hands[0]['lmList'] # hands是由N個字典組成的串列
pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐標
img = game.update(img, pointIndex)
cv2.imshow("Image", img)
key = cv2.waitKey(1)
if key == ord('r'):
game.gameOver = False
之后我會持續更新,如果喜歡我的文章,請記得一鍵三連哦,點贊關注收藏,你的每一個贊每一份關注每一次收藏都將是我前進路上的無限動力 !!!↖(▔▽▔)↗感謝支持!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/438658.html
標籤:AI