Machine Learning/Tip

[Mediapipe] Hands

WakaraNai 2021. 6. 25. 00:53
728x90
반응형

기초 코드

import cv2
import mediapipe as mp
import time


cap = cv2.VideoCapture(0)
# 카메라의 번호를 정확히 넣었는지 확인하기

mpHands = mp.solutions.hands
hands = mpHands.Hands()  # 기본 객체 생성을 위해 입력값 empty
# 생성자에서 입력값을 확인해보면,
# static_image_mode : select track or detect
# 각각 min_confidence로 비율을 설정할 수 있음

mpDraw = mp.solutions.drawing_utils
pTime = 0
cTime = 0

while True:
    success, img = cap.read()
    # rgb 이미지를 hand 객체로 보내기
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    results = hands.process(imgRGB)  # 이미지의 rgb 정보 추출하기


	# ### FPS 출력하기
    cTime = time.time()  # current time
    fps = 1/(cTime-pTime)
    pTime = cTime  # previous time

    # img ,text, 문자열 위치(왼쪽아래), font, fontSize, font color
    cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
                (255, 0, 255), 3)

    cv2.imshow("image", img)
    cv2.waitKey(1)

 

 

프로그램 종료

cmd에서 ctrl+c를 눌러서 강제 종료 시키는 방법이 간단하다

 

Landmark

results.multi_hand_landmarks 를 출력해보면,

다음과 같이 손이 화면에 잡힐 때마다 그 위치 값이 출력된다   

import cv2
import mediapipe as mp
import time


cap = cv2.VideoCapture(0)
# 카메라의 번호를 정확히 넣었는지 확인하기

mpHands = mp.solutions.hands
hands = mpHands.Hands()  # 기본 객체 생성을 위해 입력값 empty
# 생성자에서 입력값을 확인해보면,
# static_image_mode : select track or detect
# 각각 min_confidence로 비율을 설정할 수 있음

mpDraw = mp.solutions.drawing_utils
pTime = 0
cTime = 0

while True:
    success, img = cap.read()
    # rgb 이미지를 hand 객체로 보내기
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    results = hands.process(imgRGB)  # 이미지의 rgb 정보 추출하기

    # 감지 여부 확인하기
    print(results.multi_hand_landmarks)
  

    cTime = time.time()  # current time
    fps = 1/(cTime-pTime)
    pTime = cTime  # previous time

    # img ,text, 문자열 위치(왼쪽아래), font, fontSize, font color
    cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
                (255, 0, 255), 3)

    cv2.imshow("image", img)
    cv2.waitKey(1)

 

 

landmark {
      x: 0.5121928453445435
      y: 0.6661974787712097
      z: 0.032212890684604645
    }
    ]
    None
    None
    None
    None

 

 

 

Landmark Points

 

각각의 id에 따라 원하는 점을 크게 보이게 하는 방법

id = 0 에서 다른 색의 커다란 원을 그리니 다음과 같은 결과물이 나온다

 

# https://www.youtube.com/watch?v=01sAkU_NvOY

# py -3.6 -m pip install opencv-python
# py -3.6 -m pip install mediapipe
import cv2
import mediapipe as mp
import time


cap = cv2.VideoCapture(0)
# 카메라의 번호를 정확히 넣었는지 확인하기

mpHands = mp.solutions.hands
hands = mpHands.Hands()  # 기본 객체 생성을 위해 입력값 empty
# 생성자에서 입력값을 확인해보면,
# static_image_mode : select track or detect
# 각각 min_confidence로 비율을 설정할 수 있음

mpDraw = mp.solutions.drawing_utils
pTime = 0
cTime = 0

while True:
    success, img = cap.read()
    # rgb 이미지를 hand 객체로 보내기
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    results = hands.process(imgRGB)  # 이미지의 rgb 정보 추출하기

    # handLms == 손 하나
    # mediapipe로 손의 관절에 점을 찍어주기
    if results.multi_hand_landmarks:
        for handLms in results.multi_hand_landmarks:
            for id, lm in enumerate(handLms.landmark):  # id, landmark
                # print(id, lm)  # 각각의 관절(20개)마다 index가 이미 매겨져 있음
                h, w, c = img.shape
                cx, cy = int(lm.x*w), int(lm.y*h)
                print(id, cx, cy)  # (0,0)이 오른쪽 상단 (화면반전)

                if id == 0:
                    cv2.circle(img, (cx, cy), 15, (255, 255, 0), cv2.FILLED)

            #mpDraw.draw_landmarks(img, handLms)
            # 손 관절의 점을 선으로 이어주기
            mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS)

    cTime = time.time()  # current time
    fps = 1/(cTime-pTime)
    pTime = cTime  # previous time

    # img ,text, 문자열 위치(왼쪽아래), font, fontSize, font color
    cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
                (255, 0, 255), 3)

    cv2.imshow("image", img)
    cv2.waitKey(1)

 

 

 

 

클래스로 코드 정리 - 모듈화

import cv2
import mediapipe as mp
import time


class handDetector():
    def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
        # Hands() concreator
        self.mode = mode  # static_image_mode = False,
        self.maxHands = maxHands  # max_num_hands = 2,
        self.detectionCon = detectionCon  # min_detection_confidence = 0.5,
        self.trackCon = trackCon  # min_tracking_confidence = 0.5

        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(self.mode, self.maxHands,
                                        self.detectionCon, self.trackCon)
        self.mpDraw = mp.solutions.drawing_utils

	# 손 하나의 점과 직선 연결
    def findHands(self, img, draw=True):
        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, handNum=0, draw=True):
        lmList = []
        if self.results.multi_hand_landmarks:
            myHand = self.results.multi_hand_landmarks[handNum]
            for id, lm in enumerate(myHand.landmark):  # id, landmark
                # print(id, lm)  # 각각의 관절(20개)마다 index가 이미 매겨져 있음
                h, w, c = img.shape
                cx, cy = int(lm.x*w), int(lm.y*h)
                lmList.append([id, cx, cy])
                if draw:
                    cv2.circle(img, (cx, cy), 10, (255, 255, 0), cv2.FILLED)
        return lmList


def main():
    pTime = 0
    cTime = 0
    cap = cv2.VideoCapture(0)
    detector = handDetector()
    while True:
        success, img = cap.read()
        img = detector.findHands(img)
        lmList = detector.findPosition(img)
        if len(lmList) != 0:
            print(lmList[12])

        cTime = time.time()  # current time
        fps = 1/(cTime-pTime)
        pTime = cTime  # previous time

        # img ,text, 문자열 위치(왼쪽아래), font, fontSize, font color
        cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
                    (255, 0, 255), 3)

        cv2.imshow("image", img)
        cv2.waitKey(1)


if __name__ == "__main__":
    main()

화면 오른쪽(왼손)일 떼

 

 

화면의 왼쪽 하단의 경우 x, y값

 

 

 

모듈 이용하기

방금 만든 클래스를 import 해오기

 

gameHandTracking.py

import cv2
import time
import handTrackingModule as htm

pTime = 0
cTime = 0
cap = cv2.VideoCapture(0)
detector = htm.handDetector()
while True:
    success, img = cap.read()
    img = detector.findHands(img, draw=False)  # 손에 그려지는 점 선 삭제
    lmList = detector.findPosition(img, draw=False)  # 커스텀 점 삭제
    if len(lmList) != 0:
        print(lmList[12])
    cTime = time.time()  # current time
    fps = 1/(cTime-pTime)
    pTime = cTime  # previous time
    # img ,text, 문자열 위치(왼쪽아래), font, fontSize, font color
    cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
                (255, 0, 255), 3)
    cv2.imshow("image", img)
    cv2.waitKey(1)
728x90
반응형