mediapipe icon indicating copy to clipboard operation
mediapipe copied to clipboard

Calculating thumb and finger angles from coordinates

Open EigenSpiral opened this issue 3 years ago • 4 comments

What is the best way to calculate the angles of the thumb and finger from the XYZ coordinates?

EigenSpiral avatar Jan 17 '22 13:01 EigenSpiral

Its my code in python:

                    a = np.array(
                        [handLms.landmark[joint[0]].x , handLms.landmark[joint[0]].y ])  # First coord
                    b = np.array([handLms.landmark[joint[1]].x ,
                                  handLms.landmark[joint[1]].y ])  # Second coord
                    c = np.array([handLms.landmark[joint[2]].x ,
                                      handLms.landmark[joint[2]].y ])  # Third coord
                    radians = np.arctan2(c[1] - b[1], c[0] - b[0]) - np.arctan2(a[1] - b[1], a[0] - b[0])
                    angle = int(np.abs(radians * 180.0 / np.pi))
                    if angle > 180:
                        angle = 360 - angle

which joint = [joint1,joint2,joint3] which are 3 joints numbers from mediapipe hand landmarks.

hadi1376tm avatar Jan 18 '22 04:01 hadi1376tm

Thank you! How would you recommend calculating the angle of the thumb?

EigenSpiral avatar Jan 20 '22 21:01 EigenSpiral

Its my code in python:

                    a = np.array(
                        [handLms.landmark[joint[0]].x , handLms.landmark[joint[0]].y ])  # First coord
                    b = np.array([handLms.landmark[joint[1]].x ,
                                  handLms.landmark[joint[1]].y ])  # Second coord
                    c = np.array([handLms.landmark[joint[2]].x ,
                                      handLms.landmark[joint[2]].y ])  # Third coord
                    radians = np.arctan2(c[1] - b[1], c[0] - b[0]) - np.arctan2(a[1] - b[1], a[0] - b[0])
                    angle = int(np.abs(radians * 180.0 / np.pi))
                    if angle > 180:
                        angle = 360 - angle

which joint = [joint1,joint2,joint3] which are 3 joints numbers from mediapipe hand landmarks.

can you share full code with me ?

mslmgzde avatar Jun 13 '22 08:06 mslmgzde

import mediapipe as mp import cv2 import numpy as np import uuid import os mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands

cap = cv2.VideoCapture(0) #Set Frame Size cap.set(3, 1280) cap.set(4, 650) joint_list = [[8,7,6], [12,11,10], [16,15,14], [20,19,18],[2,3,4]]

def fingerAngles(image, results, joint_list):

# Loop through hands
for hand in results.multi_hand_landmarks:
    #Loop through joint sets 
    for joint in joint_list:
        a = np.array([hand.landmark[joint[0]].x, hand.landmark[joint[0]].y]) # First coord
        b = np.array([hand.landmark[joint[1]].x, hand.landmark[joint[1]].y]) # Second coord
        c = np.array([hand.landmark[joint[2]].x, hand.landmark[joint[2]].y]) # Third coord
        
        radians = np.arctan2(c[1] - b[1], c[0]-b[0]) - np.arctan2(a[1]-b[1], a[0]-b[0])
        angle = np.abs(radians*180.0/np.pi)
        
        if angle > 180.0:
            angle = 360-angle
            
        cv2.putText(image, str(round(angle, 2)), tuple(np.multiply(b, [1280, 650]).astype(int)),
                   cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2, cv2.LINE_AA)
return image

#Set the detection confidence and tracking confidence for better result with mp_hands.Hands(min_detection_confidence=0.5, min_tracking_confidence=0.5) as hands: while cap.isOpened(): ret, frame = cap.read()

    # BGR 2 RGB
    image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    
    # Flip on horizontal
    image = cv2.flip(image, 1)
    
    # Set flag
    image.flags.writeable = False
    
    # Detections
    results = hands.process(image)
    
    # Set flag to true
    image.flags.writeable = True
    
    # RGB 2 BGR
    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
  
    # Rendering results
    if results.multi_hand_landmarks:
        for num, hand in enumerate(results.multi_hand_landmarks):
            mp_drawing.draw_landmarks(image, hand, mp_hands.HAND_CONNECTIONS, 
                                    mp_drawing.DrawingSpec(color=(150, 22, 150), thickness=2, circle_radius=4),
                                    mp_drawing.DrawingSpec(color=(150, 200, 250), thickness=2, circle_radius=2),
                                     )
                       
        # Draw angles to image from joint list
        fingerAngles(image, results, joint_list)
    #Showing the camera
    cv2.imshow('Finger Angles', image)
    #exxit the program
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cap.release() cv2.destroyAllWindows()

hamza2559502 avatar Jun 28 '22 12:06 hamza2559502

Here's mine

# https://github.com/google/mediapipe/issues/2999
class HandAngles:
    def __init__(self, fingers):
        self.thumb = fingers[0]
        self.index = fingers[1]
        self.middle = fingers[2]
        self.ring = fingers[3]
        self.pinky = fingers[4]

    # https://google.github.io/mediapipe/solutions/hands#hand-landmark-model
    joint_list = [
        [4, 3, 2, 1],
        [8, 7, 6, 5, 0],
        [12, 11, 10, 9, 0],
        [16, 15, 14, 13, 0],
        [20, 19, 18, 17, 0],
    ]

    def fingerAngles(hand_landmarks):
        fingers = []
        # Loop through joint sets
        for joint in HandAngles.joint_list:
            angle = 0
            for i in range(0, len(joint) - 2):
                a = hand_landmarks.landmark[joint[i]]
                b = hand_landmarks.landmark[joint[i + 1]]
                c = hand_landmarks.landmark[joint[i + 2]]
                angle += HandAngles.angle(a, b, c)
            fingers.append(angle)
        return HandAngles(fingers)

    def angle(a, b, c):
        firstVector = (b.x - a.x, b.y - a.y, b.z - a.z)
        secondVector = (c.x - b.x, c.y - b.y, c.z - b.z)
        return angle_between(firstVector, secondVector)


# https://stackoverflow.com/a/13849249/3492994
def unit_vector(vector):
    return vector / np.linalg.norm(vector)


def angle_between(v1, v2):
    v1_u = unit_vector(v1)
    v2_u = unit_vector(v2)
    return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))

stefnotch avatar Dec 08 '22 21:12 stefnotch

Hello @EigenSpiral, We are upgrading the MediaPipe Legacy Solutions to new MediaPipe solutions However, the libraries, documentation, and source code for all the MediapPipe Legacy Solutions will continue to be available in our GitHub repository and through library distribution services, such as Maven and NPM.

You can continue to use those legacy solutions in your applications if you choose. Though, we would request you to check new MediaPipe solutions which can help you more easily build and customize ML solutions for your applications. These new solutions will provide a superset of capabilities available in the legacy solutions. Thank you

kuaashish avatar May 04 '23 09:05 kuaashish

This issue has been marked stale because it has no recent activity since 7 days. It will be closed if no further activity occurs. Thank you.

github-actions[bot] avatar May 12 '23 01:05 github-actions[bot]

This issue was closed due to lack of activity after being marked stale for past 7 days.

github-actions[bot] avatar May 19 '23 01:05 github-actions[bot]

Are you satisfied with the resolution of your issue? Yes No

google-ml-butler[bot] avatar May 19 '23 01:05 google-ml-butler[bot]