1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
import cv2 import mediapipe as mp
class HandDetector: """ 使用mediapipe库查找手。导出地标像素格式。添加了额外的功能。 如查找方式,许多手指向上或两个手指之间的距离。而且提供找到的手的边界框信息。 """ def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon = 0.5): """ :param mode: 在静态模式下,对每个图像进行检测 :param maxHands: 要检测的最大手数 :param detectionCon: 最小检测置信度 :param minTrackCon: 最小跟踪置信度 """ self.mode = mode self.maxHands = maxHands self.modelComplex = False self.detectionCon = detectionCon self.minTrackCon = minTrackCon
self.mpHands = mp.solutions.hands self.hands = self.mpHands.Hands(self.mode, self.maxHands, self.modelComplex, self.detectionCon, 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): """ 从图像(BRG)中找到手部。 :param img: 用于查找手的图像。 :param draw: 在图像上绘制输出的标志。 :return: 带或不带图形的图像 """ imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) self.results = self.hands.process(imgRGB)
if self.results.multi_hand_landmarks: for handLms in self.results.multi_hand_landmarks: if draw: self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS) return img
def findPosition(self, img, handNo=0, draw=True): """ 查找单手的地标并将其放入列表中像素格式。还可以返回手部周围的边界框。 :param img: 要查找的主图像 :param handNo: 如果检测到多只手,则为手部id :param draw: 在图像上绘制输出的标志。(默认绘制矩形框) :return: 像素格式的手部关节位置列表;手部边界框 """
xList = [] yList = [] bbox = [] bboxInfo =[] self.lmList = [] if self.results.multi_hand_landmarks: myHand = self.results.multi_hand_landmarks[handNo] for id, lm in enumerate(myHand.landmark): h, w, c = img.shape px, py = int(lm.x * w), int(lm.y * h) xList.append(px) yList.append(py) self.lmList.append([px, py]) if draw: cv2.circle(img, (px, py), 5, (255, 0, 255), cv2.FILLED) 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) bboxInfo = {"id": id, "bbox": bbox,"center": (cx, cy)}
if draw: cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20), (bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20), (0, 255, 0), 2)
return self.lmList, bboxInfo
def fingersUp(self): """ 查找列表中打开并返回的手指数。会分别考虑左手和右手 :return:竖起手指的列表 """ if self.results.multi_hand_landmarks: myHandType = self.handType() fingers = [] if myHandType == "Right": if self.lmList[self.tipIds[0]][0] > self.lmList[self.tipIds[0] - 1][0]: fingers.append(1) else: fingers.append(0) else: if self.lmList[self.tipIds[0]][0] < self.lmList[self.tipIds[0] - 1][0]: fingers.append(1) else: fingers.append(0) for id in range(1, 5): if self.lmList[self.tipIds[id]][1] < self.lmList[self.tipIds[id] - 2][1]: fingers.append(1) else: fingers.append(0) return fingers
def handType(self): """ 检查传入的手部是左还是右 :return: "Right" 或 "Left" """ if self.results.multi_hand_landmarks: if self.lmList[17][0] < self.lmList[5][0]: return "Right" else: return "Left"
|