Skip to content

Instantly share code, notes, and snippets.

@TheJLifeX
Last active June 15, 2024 11:59
Show Gist options
  • Save TheJLifeX/74958cc59db477a91837244ff598ef4a to your computer and use it in GitHub Desktop.
Save TheJLifeX/74958cc59db477a91837244ff598ef4a to your computer and use it in GitHub Desktop.
Simple Hand Gesture Recognition Code - Hand tracking - Mediapipe

Simple Hand Gesture Recognition Code - Hand tracking - Mediapipe

Goal of this gist is to recognize ONE, TWO, TREE, FOUR, FIVE, SIX, YEAH, ROCK, SPIDERMAN and OK. We use the LANDMARKS output of the LandmarkLetterboxRemovalCalculator. This output is a landmark list that contains 21 landmark. In the 02-landmarks.jpg picture below you can see the index of each landmark. Each landmark have x, y and z values. But only x, y values are sufficient for our Goal. If you dont want to copy/paste each the code on this gist, you can clone my forked version of mediapipe here: https://github.com/TheJLifeX/mediapipe. I have already commited all code in that repository.

We have five finger states.

  1. thumbIsOpen
  2. firstFingerIsOpen
  3. secondFingerIsOpen
  4. thirdFingerIsOpen
  5. fourthFingerIsOpen

For exmaple: thumb is open if the x value of landmark 3 and the x value of landmark 4 are less than x value of landmark 2 else it is close

PS: thumb open/close works only for the right hand. Because we can not yet determine if you show your left or right hand. For more info see this issue: Can palm_detection distinguish between right and left hand?

Prerequisite: You kwon how to run the hand tracking example.

  1. Get Started with mediapipe
  2. Hand Tracking on Desktop

If you want to know how to recognize some simple hand mouvements like Scrolling, Zoom in/out and Slide left/right (see comment below) you can read this gist: Simple Hand Mouvement Recognition Code.

#include <cmath>
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/rect.pb.h"
namespace mediapipe
{
namespace
{
constexpr char normRectTag[] = "NORM_RECT";
constexpr char normalizedLandmarkListTag[] = "NORM_LANDMARKS";
} // namespace
// Graph config:
//
// node {
// calculator: "HandGestureRecognitionCalculator"
// input_stream: "NORM_LANDMARKS:scaled_landmarks"
// input_stream: "NORM_RECT:hand_rect_for_next_frame"
// }
class HandGestureRecognitionCalculator : public CalculatorBase
{
public:
static ::mediapipe::Status GetContract(CalculatorContract *cc);
::mediapipe::Status Open(CalculatorContext *cc) override;
::mediapipe::Status Process(CalculatorContext *cc) override;
private:
float get_Euclidean_DistanceAB(float a_x, float a_y, float b_x, float b_y)
{
float dist = std::pow(a_x - b_x, 2) + pow(a_y - b_y, 2);
return std::sqrt(dist);
}
bool isThumbNearFirstFinger(NormalizedLandmark point1, NormalizedLandmark point2)
{
float distance = this->get_Euclidean_DistanceAB(point1.x(), point1.y(), point2.x(), point2.y());
return distance < 0.1;
}
};
REGISTER_CALCULATOR(HandGestureRecognitionCalculator);
::mediapipe::Status HandGestureRecognitionCalculator::GetContract(
CalculatorContract *cc)
{
RET_CHECK(cc->Inputs().HasTag(normalizedLandmarkListTag));
cc->Inputs().Tag(normalizedLandmarkListTag).Set<mediapipe::NormalizedLandmarkList>();
RET_CHECK(cc->Inputs().HasTag(normRectTag));
cc->Inputs().Tag(normRectTag).Set<NormalizedRect>();
return ::mediapipe::OkStatus();
}
::mediapipe::Status HandGestureRecognitionCalculator::Open(
CalculatorContext *cc)
{
cc->SetOffset(TimestampDiff(0));
return ::mediapipe::OkStatus();
}
::mediapipe::Status HandGestureRecognitionCalculator::Process(
CalculatorContext *cc)
{
// hand closed (red) rectangle
const auto rect = &(cc->Inputs().Tag(normRectTag).Get<NormalizedRect>());
float width = rect->width();
float height = rect->height();
if (width < 0.01 || height < 0.01)
{
LOG(INFO) << "No Hand Detected";
return ::mediapipe::OkStatus();
}
const auto &landmarkList = cc->Inputs()
.Tag(normalizedLandmarkListTag)
.Get<mediapipe::NormalizedLandmarkList>();
RET_CHECK_GT(landmarkList.landmark_size(), 0) << "Input landmark vector is empty.";
// finger states
bool thumbIsOpen = false;
bool firstFingerIsOpen = false;
bool secondFingerIsOpen = false;
bool thirdFingerIsOpen = false;
bool fourthFingerIsOpen = false;
//
float pseudoFixKeyPoint = landmarkList.landmark(2).x();
if (landmarkList.landmark(3).x() < pseudoFixKeyPoint && landmarkList.landmark(4).x() < pseudoFixKeyPoint)
{
thumbIsOpen = true;
}
pseudoFixKeyPoint = landmarkList.landmark(6).y();
if (landmarkList.landmark(7).y() < pseudoFixKeyPoint && landmarkList.landmark(8).y() < pseudoFixKeyPoint)
{
firstFingerIsOpen = true;
}
pseudoFixKeyPoint = landmarkList.landmark(10).y();
if (landmarkList.landmark(11).y() < pseudoFixKeyPoint && landmarkList.landmark(12).y() < pseudoFixKeyPoint)
{
secondFingerIsOpen = true;
}
pseudoFixKeyPoint = landmarkList.landmark(14).y();
if (landmarkList.landmark(15).y() < pseudoFixKeyPoint && landmarkList.landmark(16).y() < pseudoFixKeyPoint)
{
thirdFingerIsOpen = true;
}
pseudoFixKeyPoint = landmarkList.landmark(18).y();
if (landmarkList.landmark(19).y() < pseudoFixKeyPoint && landmarkList.landmark(20).y() < pseudoFixKeyPoint)
{
fourthFingerIsOpen = true;
}
// Hand gesture recognition
if (thumbIsOpen && firstFingerIsOpen && secondFingerIsOpen && thirdFingerIsOpen && fourthFingerIsOpen)
{
LOG(INFO) << "FIVE!";
}
else if (!thumbIsOpen && firstFingerIsOpen && secondFingerIsOpen && thirdFingerIsOpen && fourthFingerIsOpen)
{
LOG(INFO) << "FOUR!";
}
else if (thumbIsOpen && firstFingerIsOpen && secondFingerIsOpen && !thirdFingerIsOpen && !fourthFingerIsOpen)
{
LOG(INFO) << "TREE!";
}
else if (thumbIsOpen && firstFingerIsOpen && !secondFingerIsOpen && !thirdFingerIsOpen && !fourthFingerIsOpen)
{
LOG(INFO) << "TWO!";
}
else if (!thumbIsOpen && firstFingerIsOpen && !secondFingerIsOpen && !thirdFingerIsOpen && !fourthFingerIsOpen)
{
LOG(INFO) << "ONE!";
}
else if (!thumbIsOpen && firstFingerIsOpen && secondFingerIsOpen && !thirdFingerIsOpen && !fourthFingerIsOpen)
{
LOG(INFO) << "YEAH!";
}
else if (!thumbIsOpen && firstFingerIsOpen && !secondFingerIsOpen && !thirdFingerIsOpen && fourthFingerIsOpen)
{
LOG(INFO) << "ROCK!";
}
else if (thumbIsOpen && firstFingerIsOpen && !secondFingerIsOpen && !thirdFingerIsOpen && fourthFingerIsOpen)
{
LOG(INFO) << "SPIDERMAN!";
}
else if (!thumbIsOpen && !firstFingerIsOpen && !secondFingerIsOpen && !thirdFingerIsOpen && !fourthFingerIsOpen)
{
LOG(INFO) << "FIST!";
}
else if (!firstFingerIsOpen && secondFingerIsOpen && thirdFingerIsOpen && fourthFingerIsOpen && this->isThumbNearFirstFinger(landmarkList.landmark(4), landmarkList.landmark(8)))
{
LOG(INFO) << "OK!";
}
else
{
LOG(INFO) << "Finger States: " << thumbIsOpen << firstFingerIsOpen << secondFingerIsOpen << thirdFingerIsOpen << fourthFingerIsOpen;
LOG(INFO) << "___";
}
return ::mediapipe::OkStatus();
} // namespace mediapipe
} // namespace mediapipe

We have to add the HandGestureRecognitionCalculator node config in the in the hand_landmark_cpu.pbtxt or hand_landmark_gpu.pbtxt graph file.

  node {
      calculator: "HandGestureRecognitionCalculator"
      input_stream: "NORM_LANDMARKS:scaled_landmarks"
      input_stream: "NORM_RECT:hand_rect_for_next_frame"
    }

For example:

  1. in the hand_landmark_cpu.pbtx see here: https://github.com/TheJLifeX/mediapipe/blob/master/mediapipe/graphs/hand_tracking/subgraphs/hand_landmark_cpu.pbtxt#L187-L191
  2. in the hand_landmark_gpu.pbtx see here: https://github.com/TheJLifeX/mediapipe/blob/master/mediapipe/graphs/hand_tracking/subgraphs/hand_landmark_gpu.pbtxt#L182-L186

We have to create a bazel build config for our Calculator.

cc_library(
name = "hand-gesture-recognition-calculator",
srcs = ["hand-gesture-recognition-calculator.cc"],
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/port:status",
"//mediapipe/framework/formats:rect_cc_proto",
"//mediapipe/framework/port:ret_check",
],
alwayslink = 1,
)

We have to add the path to the "hand-gesture-recognition-calculator" bazel build config in the hand_landmark_cpu or hand_landmark_cpu bazel build config.

For example: "//hand-gesture-recognition:hand-gesture-recognition-calculator"

  1. in the hand_landmark_cpu see here: https://github.com/TheJLifeX/mediapipe/blob/a069e5b6e1097f3f69c161a11f336e9e3b9751dd/mediapipe/graphs/hand_tracking/subgraphs/BUILD#L88
  2. in the hand_landmark_gpu see here: https://github.com/TheJLifeX/mediapipe/blob/a069e5b6e1097f3f69c161a11f336e9e3b9751dd/mediapipe/graphs/hand_tracking/subgraphs/BUILD#L192

You can now build the project and run it.

@jitendersaini
Copy link

jitendersaini commented Mar 24, 2020

Thanks a lot for such a nice tutorial and it is really very helpful to me the objective I want to achieve. Basically, I'm trying to build sign language use case using this approach and I'm little succeed decoding few signs but I'm facing few challenges and I really need your help to overcome those. Few hands signs like G (https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ-5AXHWBUUzbmELozMjac_B2oX7AQKgm49FZ5Xv8AKHTRuFIa4), P (https://i.pinimg.com/originals/a2/15/b8/a215b8aaa0a8584fc564a5925bff81f9.png) and espeially J (https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcS_4HEUv8Nxxis3E-a5SY1k8zalYspjmNHXYqr1Qe4z70k5lXsr) and Z (https://www.seekpng.com/png/detail/392-3923100_american-sign-language-british-sign-language-letter-z.png). The challenge is, sign like G and P involves horizontal orientation of hand so I'm not sure how to detect horizontal orientation of fingers and sign like J and Z involves movements so again there is grey area for me how we can achieve movement base gesture recognition using mediapipe.
I've tried detect vertical and horizontal orientation using below method but I'm not sure if this is the right way to do it, or you can suggest some better and stable approach for doing the same.
string getOrientation(NormalizedLandmark pt1)
{
string orientation = "";
if ((pt1.x() - pt1.y()) > .25)
{
orientation = "Vertical";
}
else if ((pt1.x() - pt1.y()) < .16)
{
orientation = "Horizontal";
}
return orientation;
}

Thanks again for your help.

Jitender

@bestwangwang
Copy link

How do you get gesture results on iOS?

@AnimeshJaiswal
Copy link

AnimeshJaiswal commented Mar 27, 2020

Hi. I'm a newbie in android app development. I'm trying to make a "Gesture Recognition Service" using this framework.
Can you please provide some direction on how to convert this app into a service as there are many dependencies and framework constraints?

@jitendersaini
Copy link

Hello, I hope you've got a chance to see my query, Please reply as I'm got stuck at this point and I really need your help here. And Can you please tell how to build this calculator on android phone. I was not able to get any help on web as well that how one can build his own calculator on android. what are all configurations needed.

Thanks
Jitender

@psykid
Copy link

psykid commented Apr 9, 2020

Hi, thanks for the tutorial.

I have added some code to detect "5" on left hand or on right hand with palm facing the user:

float pseudoFixKeyPoint = landmarkList.landmark(2).x();
    if (landmarkList.landmark(3).x() < pseudoFixKeyPoint && landmarkList.landmark(4).x() < pseudoFixKeyPoint)
    {
        // palm facing the camera and thumb is open
        thumbIsOpen = true;
    } else if (landmarkList.landmark(4).x() > landmarkList.landmark(8).x() && 
        (landmarkList.landmark(3).x() > pseudoFixKeyPoint && landmarkList.landmark(4).x() > pseudoFixKeyPoint)) 
    {
        // thumb is on right of index finger. Either this is left hand or right hand with palm facing the user
        thumbIsOpen = true;
    }

@jitendersaini
Copy link

Hello,
I've updated the latest bazel version and mediapipe project and configured this project over there, It was successfully build and running but label that was detected is not getting displayed on red box in the camera where as I've cout the gesture in hand-gesture-recognition-calculator.cc and it's been getting detected well. the only thing it's not printing on the screen. Please check if there is some additional configuration needed with new mediapipe project.
Thanks
Jitender

@ihmc3jn09hk
Copy link

@TheJLifeX Thank you very much for such tutorial. Based on your steps, I tried to connect the proposed node to another example of hands-tracking and this is it.
ezgif com-gif-maker

@TheJLifeX
Copy link
Author

TheJLifeX commented Apr 25, 2020

Thanks a lot for such a nice tutorial and it is really very helpful to me the objective I want to achieve. Basically, I'm trying to build sign language use case using this approach and I'm little succeed decoding few signs but I'm facing few challenges and I really need your help to overcome those.
...
...
I've tried detect vertical and horizontal orientation using below method but I'm not sure if this is the right way to do it, or you can suggest some better and stable approach for doing the same.
string getOrientation(NormalizedLandmark pt1)
{ string orientation = ""; if ((pt1.x() - pt1.y()) > .25) { orientation = "Vertical"; } else if ((pt1.x() - pt1.y()) < .16) { orientation = "Horizontal"; } return orientation; }

Thanks again for your help.

Jitender

Hi jitendersaini, you can use the landmarks from the output stream (hand_landmarks) of the LandmarkProjectionCalculator as input stream (see: here).

  • Before the LandmarkProjectionCalculator, the landmarks (scaled_landmarks) are in the hand enclosed rectangle (the red rectangle) coordinate system with origin the top left corner of the hand enclosed rectangle.
  • After the LandmarkProjectionCalculator, the landmarks are projected to the full image coordinate system with origin the top left corner of the full image.

To determine the orientation of the hand. We can calculate the angle between the line connecting center the wirst, the MCP of the middle finger and the X-axis.

NormalizedLandmark wrist = landmarkList.landmark(0);
NormalizedLandmark MCP_of_middle_finger = landmarkList.landmark(9);
                                                                                                                        
float ang_in_radian = getAngleABC(MCP_of_middle_finger.x(), MCP_of_middle_finger.y(), wrist.x(), wrist.y(), wrist.x() + 0.1, wrist.y());
int ang_in_degree = radianToDegree(ang_in_radian);

LOG(INFO) << "Hand Orientation in degree: " << ang_in_degree ;

// util functions
float getAngleABC(float a_x, float a_y, float b_x, float b_y, float c_x, float c_y)
{
  float ab_x = b_x - a_x;
  float ab_y = b_y - a_y;
  float cb_x = b_x - c_x;
  float cb_y = b_y - c_y;

  float dot = (ab_x * cb_x + ab_y * cb_y);   // dot product
  float cross = (ab_x * cb_y - ab_y * cb_x); // cross product

  float alpha = std::atan2(cross, dot);

  return alpha;
}

int radianToDegree(float radian)
{
    return (int)floor(radian * 180. / M_PI + 0.5);
}

image

@TheJLifeX
Copy link
Author

@TheJLifeX Thank you very much for such tutorial. Based on your steps, I tried to connect the proposed node to another example of hands-tracking and this is it.
...
i dont know if im asking right or if it makes sense, but can you upload the apk for this?

Hi @gasantiago, great that this gist could help you. You can find the instructions to build an apk with mediapipe on the following links:

@TheJLifeX
Copy link
Author

I wrote another gist: Simple Hand Mouvement Recognition Code to recognize some simple hand mouvements like Scrolling, Zoom in/out and Slide left/right (see picture below).

08-hand-mouvement

@OrangeSmoothie
Copy link

HI @jitendersaini can you show your approach to recognizing static gestures?

Thank you for this tutorial, @TheJLifeX, do you have any suggestions what is better to use for recognizing simple static sign alphabet? Checking if open and checking if close to something do not show good results with 26+ options

@TheJLifeX
Copy link
Author

TheJLifeX commented May 17, 2020

Hi @OrangeSmoothie,
I don't have any precise suggestions how to achieve that. You may use a threshold to get more robust result like on the example below.

float threshold = 0.01;
float pseudoFixKeyPoint = landmarkList.landmark(2).x();
if (landmarkList.landmark(3).x() + threshold < pseudoFixKeyPoint 
&& landmarkList.landmark(4).x() + threshold < landmarkList.landmark(3).x())
{
    thumbIsOpen = true;
}

see hand-gesture-recognition-calculator.cc file from the hand gesture recognition with threshold branch.

@SaddamBInSyed
Copy link

@TheJLifeX, Thanks for your gesture code.

Could you please advise whether your gesture code available in python.

since I am new to c++ I don't understand the flow.

highly appreciated your advice,

@TheJLifeX
Copy link
Author

TheJLifeX commented Jun 8, 2020

Hi @SaddamBInSyed, below you can find the hand gesture recognition code written in python. I hope this can help you.

# The landmarks array has the following structur: [x0, y0, x1, y1, ....., x20, y20]
# with for example x0 and y0 the x and y values of the landmark at index 0.
test_landmarks_data = [
  0.499651,0.849638,0.614354,0.796254,
  0.686660,0.692482, 0.743792,0.606666,
  0.809362,0.512337,0.538779,0.499517,
  0.513829,0.361394,0.484049,0.260214,
  0.452508,0.173999, 0.445565,0.512067,
  0.396448,0.358399,0.355494,0.245083,0.318670,
  0.157915,0.355069,0.562040, 0.278774,
  0.435983,0.221781,0.345394,0.178977,0.273430,
  0.288238,0.631016,0.219506, 0.544787,
  0.162939,0.483343,0.110222,0.422808] # true label: 5

recognizedHandGesture = recognizeHandGesture(getStructuredLandmarks(test_landmarks_data))
print("recognized hand gesture: ", recognizedHandGesture) # print: "recognized hand gesture: 5"


### Functions
def recognizeHandGesture(landmarks):
  thumbState = 'UNKNOW'
  indexFingerState = 'UNKNOW'
  middleFingerState = 'UNKNOW'
  ringFingerState = 'UNKNOW'
  littleFingerState = 'UNKNOW'
  recognizedHandGesture = None

  pseudoFixKeyPoint = landmarks[2]['x']
  if (landmarks[3]['x'] < pseudoFixKeyPoint and landmarks[4]['x'] < landmarks[3]['x']):
    thumbState = 'CLOSE'    
  elif (pseudoFixKeyPoint < landmarks[3]['x'] and landmarks[3]['x'] < landmarks[4]['x']):
    thumbState = 'OPEN'    

  pseudoFixKeyPoint = landmarks[6]['y']
  if (landmarks[7]['y'] < pseudoFixKeyPoint and landmarks[8]['y'] < landmarks[7]['y']):
    indexFingerState = 'OPEN'    
  elif (pseudoFixKeyPoint < landmarks[7]['y'] and landmarks[7]['y'] < landmarks[8]['y']):
    indexFingerState = 'CLOSE'    

  pseudoFixKeyPoint = landmarks[10]['y']
  if (landmarks[11]['y'] < pseudoFixKeyPoint and landmarks[12]['y'] < landmarks[11]['y']):
    middleFingerState = 'OPEN'    
  elif (pseudoFixKeyPoint < landmarks[11]['y'] and landmarks[11]['y'] < landmarks[12]['y']):
    middleFingerState = 'CLOSE'

  pseudoFixKeyPoint = landmarks[14]['y']
  if (landmarks[15]['y'] < pseudoFixKeyPoint and landmarks[16]['y'] < landmarks[15]['y']):
    ringFingerState = 'OPEN'    
  elif (pseudoFixKeyPoint < landmarks[15]['y'] and landmarks[15]['y'] < landmarks[16]['y']):
    ringFingerState = 'CLOSE'
  
  pseudoFixKeyPoint = landmarks[18]['y']
  if (landmarks[19]['y'] < pseudoFixKeyPoint and landmarks[20]['y'] < landmarks[19]['y']):
    littleFingerState = 'OPEN'    
  elif (pseudoFixKeyPoint < landmarks[19]['y'] and landmarks[19]['y'] < landmarks[20]['y']):
    littleFingerState = 'CLOSE'
    
  if (thumbState == 'OPEN' and indexFingerState == 'OPEN' and middleFingerState == 'OPEN' and ringFingerState == 'OPEN' and littleFingerState == 'OPEN'):
    recognizedHandGesture = 5 # "FIVE"   
  elif (thumbState == 'CLOSE' and indexFingerState == 'OPEN' and middleFingerState == 'OPEN' and ringFingerState == 'OPEN' and littleFingerState == 'OPEN'):
    recognizedHandGesture = 4 # "FOUR"  
  elif (thumbState == 'OPEN' and indexFingerState == 'OPEN' and middleFingerState == 'OPEN' and ringFingerState == 'CLOSE' and littleFingerState == 'CLOSE'):
    recognizedHandGesture = 3 # "TREE"   
  elif (thumbState == 'OPEN' and indexFingerState == 'OPEN' and middleFingerState == 'CLOSE' and ringFingerState == 'CLOSE' and littleFingerState == 'CLOSE'):
    recognizedHandGesture = 2 # "TWO"   
  elif (thumbState == 'CLOSE' and indexFingerState == 'CLOSE' and middleFingerState == 'CLOSE' and ringFingerState == 'CLOSE' and littleFingerState == 'CLOSE'):
    recognizedHandGesture = 10 # "FIST"
  else:
    recognizedHandGesture = 0 # "UNKNOW"
  return recognizedHandGesture

def getStructuredLandmarks(landmarks):
  structuredLandmarks = []
  for j in range(42):
    if( j %2 == 1):
      structuredLandmarks.append({ 'x': landmarks[j - 1], 'y': landmarks[j] })
  return structuredLandmarks

@SaddamBInSyed
Copy link

SaddamBInSyed commented Jun 9, 2020

@TheJLifeX

Thank you very much. you save my time a lot.

I have tried the same and working fine but finger landmark detection is NOT good.

image

Here I am trying to detect the index finger is touching the thumb finger or not. but since the index finger landmark point is not always correct my prediction going wrong.

could you please advise in this part?

@OrangeSmoothie
Copy link

@TheJLifeX

I tried to figure hand orientation like you suggested on the top. But this "int ang_in_degree = radianToDegree(ang_in_radian);" always gives result about 90 degrees because axis x rotates just liket axis y. Any advice would be helpful, thank you.

@SaddamBInSyed
Copy link

Now the recognized hand gesture (text) is displayed on the webcam on my forked version of mediapipe (https://github.com/TheJLifeX/mediapipe)
You can find all changes I made to do that on this commit: Render recognized hand gesture (text).

hand-gesture

@TheJLifeX,

Seems your output is more accurate.

which model you used whether .tflite.model or (desktop) Tensorflow .pb model file.
If we use the TFLITE model in the desktop app then the accuracy will be less?

please advise.

@TheJLifeX
Copy link
Author

Hi @SaddamBInSyed, it just a visual effect. This GIF has not been created with a video but with the combination of images/screenshots (each image showing one hand gesture). I used this tool: Images to GIF to create that.

@TheJLifeX
Copy link
Author

Hi @OrangeSmoothie, make sure that you use the landmarks from the output stream (hand_landmarks) of the LandmarkProjectionCalculator as input stream (see: here).

  • Before the LandmarkProjectionCalculator, the landmarks (scaled_landmarks) are in the hand enclosed rectangle (the red rectangle) coordinate system with origin the top left corner of the hand enclosed rectangle.
  • After the LandmarkProjectionCalculator, the landmarks are projected to the full image coordinate system with origin the top left corner of the full image.

@OrangeSmoothie
Copy link

@TheJLifeX Thank you!

@SaddamBInSyed
Copy link

@TheJLifeX

Thank you very much. you save my time a lot.

I have tried the same and working fine but finger landmark detection is NOT good.

image

Here I am trying to detect the index finger is touching the thumb finger or not. but since the index finger landmark point is not always correct my prediction going wrong.

could you please advise in this part?

Could you please advise on this ?

Thanks

@TheJLifeX
Copy link
Author

TheJLifeX commented Jun 15, 2020

Hi @SaddamBInSyed, the Hand Tracking with mediapipe is not perfect. See “Mean regression error” in the On-Device, Real-Time Hand Tracking with MediaPipe article. So you have to deal with this percent of error if you build something on top of the Hand Tracking. It means your results will also be in some way erroneous due to this percent of error.

@mmm2016
Copy link

mmm2016 commented Jun 20, 2020

@risi7
Copy link

risi7 commented Jul 10, 2020

It will be very helpful if you can guide in how to proceed with this mediapipe hand recognition in windows. I cant find much resources for how to use mediapipe in windows and use it for hand gesture recognition. And also what do you think that using the windows subsystem for Linux will be better than windows for this medaipipe hand guesture.

@TheJLifeX
Copy link
Author

Hi @risi7, you can find information about how you can use MediaPipe on Windows here.

@risi7
Copy link

risi7 commented Jul 13, 2020

How can we get this hand recognition in an App? Can you please help with the steps.

@TheJLifeX
Copy link
Author

Hi @risi7, I haven't built an app in which MediaPipe is used right now. Feel free to search about that to find a way to build one.

@nyanmn
Copy link

nyanmn commented Jul 15, 2020

When I do docker build --tag=mediapipe . at my pc.
I have error as

Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
E: Unable to locate package python-pip

Actually I have pip2 and pip3 installed.

@nyanmn
Copy link

nyanmn commented Jul 15, 2020

How can I detect the hand move end to end horizontally?

@risi7
Copy link

risi7 commented Jul 15, 2020

How can we test this hand recognition by giving an input video (like the path of video) and getting an output video with hand gesture recognition?
And also can you please share the build and run commands to build and run project.

@miltonhuang
Copy link

miltonhuang commented Jul 18, 2020

--input_video_path /home/user/Desktop/videos/input.mp4 --output_video_path /home/user/Desktop/videos/outputvideofile.mp4
execute either one of those two scripts. run-hand-tracking-desktop-cpu.sh run-hand-tracking-desktop-gpu.sh, you could check the scripts for details.

@wonjongbot
Copy link

wonjongbot commented Jul 20, 2020

Hi @TheJLifeX,
First of all, thank you so much for this awesome method for gesture recognition.
I've been trying to implement this to multi hand tracking example, but the calculators are very different from the single handed one so I'm not sure of how to approach this.
I succeeded to print out some gestures in the command line by modifying the demo_run_graph_main_gpu.cc file, but failed to do so on a separate calculator like yours.
Any insights? Thank you so much :)

@nyanmn
Copy link

nyanmn commented Jul 21, 2020

@TheJLifeX
Your forkout lib is very useful.

How can I add in third party library like https://github.com/felHR85/UsbSerial to mediapipe?
For normal Android Studio project, I just need to add in

allprojects {
	repositories {
		jcenter()
		maven { url "https://jitpack.io" }
	}
}

to build.gradle.
And add the dependency to module's build.gradle:

implementation 'com.github.felHR85:UsbSerial:6.1.0'

But for mediapipe, how can I add in to interface usbserial?

@risi7
Copy link

risi7 commented Jul 21, 2020

@TheJLifeX, Why does it show the wrong gesture when hand is flipped. Like it recognizes rock correctly when the palm is facing the camera but as the hand is flipped(palm is not facing the camera) it shows the incorrect output or recognition. And also can you please suggest how to recognize thumbs up and thumbs down.

@methomas98
Copy link

methomas98 commented Jul 23, 2020

@TheJLifeX, thanks for your work on the gesture recognition. It came in handy in my project!

If you're interested, I modified it so that it can recognize both hands, facing toward and away from the camera. You can find the changes in this commit. I just determined the hand orientation and took it into account when checking if the thumb was in or out.

@FabricioGuimaraesOliveira

Hello. How can I integrate media pipe pose and a multitracking hands in real time? Its possible?

@johntranz
Copy link

@TheJLifeX,
Can you instruct me to train the sign language recognition model ?
Or steps taken to let the model recognize a new gesture.
I would be very grateful for that

@tonywang531
Copy link

Since mediapipe can now detect left or right hand, how to implement this feature? I got this code working in IOS, if anyone is interested I will upload it in the mediapipe repository.

@happyCodingSusan
Copy link

@TheJLifeX,
Thank you for sharing your ideas and codes.
I found you simple gestures work well when I use my right hand but not work when I use my left hand. When I use my left hand, so many mistakes. For example, when my left hand shows 5 fingers, your detection result is 4. Do you encounter this issue before? Any ideas why this happens?
Many thanks.

@tonywang531
Copy link

tonywang531 commented Nov 4, 2020

@happyCodingSusan,
The detection algorithm is very basic in the example. It does not take into account of left or right hand. In order to properly recognize both hands, the left or right hand information need to be retrieved from mediapipe landmark data. So the logic would be something like if the detected hand is left, flip the positions of the fingers then the detection algorithm will work. I am still trying to work out how to access this information.
At the worst case, we could identify left or right hand by using landmark data alone. Take for example, landmark position 4 and position 10, if 4 is on the left of 10 then it is like the palm in the example picture and vice versa. By checking the positions of the 5 fingers we should be able to detect if it is a left hand or right hand. It's just that I prefer not to reinvent the wheel when Mediapipe already can detect left or right hand in the current version.
I also give a bit thought on the front of the hand or the back of the hand. It seems to be impossible to detect if it is the front of the hand and the back of the hand by using landmark data alone. What I mean is that left hand with finger lines facing your face would be detected the same as right hand facing your face, sort like when you clap your hands. I don't feel you can distinguish this by using mediapipe. Therefore you would need to specify which side of the hand in your application.

@adarshx11
Copy link

@TheJLifeX Help me,
Can you Do it with Python .py

@adarshx11
Copy link

@TheJLifeX

Thank you very much. you save my time a lot.

I have tried the same and working fine but finger landmark detection is NOT good.

image

Here I am trying to detect the index finger is touching the thumb finger or not. but since the index finger landmark point is not always correct my prediction going wrong.

could you please advise in this part?

@TheJLifeX

Thank you very much. you save my time a lot.

I have tried the same and working fine but finger landmark detection is NOT good.

image

Here I am trying to detect the index finger is touching the thumb finger or not. but since the index finger landmark point is not always correct my prediction going wrong.

could you please advise in this part?

Saddam share Code Please

@denzero13
Copy link

Hi @TheJLifeX, I have a problem, I want to use the MediaPipe Hands library for python, I display a list of positions, but I don't understand which position corresponds to the point I need, and some positions are repeated, I used your code from above, but it doesn't work, I created a function that generates the required list. I output the frozen set mp_hands.HAND_CONNECTIONS and get the result
How to decipher correctly to understand which position belongs to which point?
sorry for bad english, i use google translator)))

frozenset({(<HandLandmark.THUMB_IP: 3>, <HandLandmark.THUMB_TIP: 4>), (<HandLandmark.WRIST: 0>, <HandLandmark.INDEX_FINGER_MCP: 5>), (<HandLandmark.PINKY_MCP: 17>, <HandLandmark.PINKY_PIP: 18>), (<HandLandmark.WRIST: 0>, <HandLandmark.PINKY_MCP: 17>), (<HandLandmark.RING_FINGER_MCP: 13>, <HandLandmark.RING_FINGER_PIP: 14>), (<HandLandmark.RING_FINGER_MCP: 13>, <HandLandmark.PINKY_MCP: 17>), (<HandLandmark.PINKY_PIP: 18>, <HandLandmark.PINKY_DIP: 19>), (<HandLandmark.INDEX_FINGER_MCP: 5>, <HandLandmark.INDEX_FINGER_PIP: 6>), (<HandLandmark.INDEX_FINGER_MCP: 5>, <HandLandmark.MIDDLE_FINGER_MCP: 9>), (<HandLandmark.RING_FINGER_PIP: 14>, <HandLandmark.RING_FINGER_DIP: 15>), (<HandLandmark.WRIST: 0>, <HandLandmark.THUMB_CMC: 1>), (<HandLandmark.MIDDLE_FINGER_MCP: 9>, <HandLandmark.MIDDLE_FINGER_PIP: 10>), (<HandLandmark.THUMB_CMC: 1>, <HandLandmark.THUMB_MCP: 2>), (<HandLandmark.MIDDLE_FINGER_PIP: 10>, <HandLandmark.MIDDLE_FINGER_DIP: 11>), (<HandLandmark.MIDDLE_FINGER_MCP: 9>, <HandLandmark.RING_FINGER_MCP: 13>), (<HandLandmark.PINKY_DIP: 19>, <HandLandmark.PINKY_TIP: 20>), (<HandLandmark.INDEX_FINGER_PIP: 6>, <HandLandmark.INDEX_FINGER_DIP: 7>), (<HandLandmark.RING_FINGER_DIP: 15>, <HandLandmark.RING_FINGER_TIP: 16>), (<HandLandmark.THUMB_MCP: 2>, <HandLandmark.THUMB_IP: 3>), (<HandLandmark.MIDDLE_FINGER_DIP: 11>, <HandLandmark.MIDDLE_FINGER_TIP: 12>), (<HandLandmark.INDEX_FINGER_DIP: 7>, <HandLandmark.INDEX_FINGER_TIP: 8>)})

@Jaguaribe21
Copy link

Jaguaribe21 commented Dec 8, 2020

Hi,

Has anyone managed to implement in mediapipe 0.8.0?

I tried to modify the files, but when I run, it displays this error:

AnnotationOverlayCalculator :: GetContract failed to validate:
For input streams ValidatePacketTypeSet failed:
"INPUT_FRAME" tag index 0 was not expected.
For output streams ValidatePacketTypeSet failed:
"OUTPUT_FRAME" tag index 0 was not expected.

Any tips or solutions?

Note: I am using Bazel 3.4.1, it runs normally, without the codes to be deployed.

Thanks.

@tonywang531
Copy link

Sorry for the delay. I have uploaded the IOS version handtracking to this location:
https://github.com/tonywang531/Temporary-code/tree/master/IOS
Disclaimer: Please just use it as a reference material and work from there. I no longer work on Mediapipe because I used Apple Vision framework directly. The big reason is that Mediapipe does not support Swift, which is the main thing used by Apple. Objective C is hard to program and does not work well with Xcode. By this point I probably forgot what I have wrote before and unable to answer questions regarding to this code.

@czming
Copy link

czming commented Feb 7, 2021

Hi, I managed to get the code to build with the new calculator and subgraph but seem to be getting this error when trying to run the hand_tracking_cpu code after inserting the subgraph, do you know of any possible solutions? Thanks!

~/mediapipe$ GLOG_logtostderr=1 bazel-bin/mediapipe/examples/desktop/hand_tracking/hand_tracking_cpu --calculator_graph_config_file=mediapipe/graphs/hand_tracking/hand_tracking_desktop_live.pbtxt
I20210207 20:12:09.581851 163311 demo_run_graph_main.cc:47] Get calculator graph config contents: # MediaPipe graph that performs hands tracking on desktop with TensorFlow

... truncated (same as values in mediapipe/graphs/hand_tracking/hand_tracking_desktop_live.pbtxt on the Mediapipe's github repo)

node {
calculator: "HandLandmarkSubgraph"
input_stream: "IMAGE:input_video"
input_stream: "NORM_RECT:hand_rect"
output_stream: "LANDMARKS:hand_landmarks"
output_stream: "NORM_RECT:hand_rect_for_next_frame"
output_stream: "PRESENCE:hand_presence"
output_stream: "RECOGNIZED_HAND_GESTURE:recognized_hand_gesture"
}
I20210207 20:12:09.582515 163311 demo_run_graph_main.cc:53] Initialize the calculator graph.
E20210207 20:12:09.584162 163311 demo_run_graph_main.cc:153] Failed to run the graph: ValidatedGraphConfig Initialization failed.
HandGestureRecognitionCalculator::GetContract failed to validate:
For output streams ValidatePacketTypeSet failed:
Tag "RECOGNIZED_HAND_GESTURE" index 0 was not expected.

@adarshx11
Copy link

how to print Normalized Keypoint using Python ?
image

@Rudrrr
Copy link

Rudrrr commented Feb 27, 2021

Can this project run on single raspberry pi ?

@atharvakale31
Copy link

Hey, I created a desktop application using some of your logic do check out.

https://github.com/atharvakale31/Custom_Gesture_Control

UI

eg: Control power point slide

@LexQzim
Copy link

LexQzim commented Mar 23, 2021

Some people are asking for a python implementation. This is my python interpretaion of @TheJLifeX tutorial. Maybe it helps someone:

Thank you @TheJLifeX for your nice simple tutorial.

        import math
        import mediapipe as mp
        import cv2
        
        class SimpleGestureDetector:
            # region: Member variables
            # mediaPipe configuration hands object
            __mpHands = mp.solutions.hands
            # mediaPipe detector objet
            __mpHandDetector = None
        
            def __init__(self):
                self.__setDefaultHandConfiguration()
        
            def __setDefaultHandConfiguration(self):
                self.__mpHandDetector = self.__mpHands.Hands(
                    # default = 2
                    max_num_hands=2,
                    # Minimum confidence value ([0.0, 1.0]) from the landmark-tracking model for the hand landmarks to be considered tracked successfully (default= 0.5)
                    min_detection_confidence=0.5,
                    # Minimum confidence value ([0.0, 1.0]) from the hand detection model for the detection to be considered successful. (default = 0.5)
                    min_tracking_confidence=0.5
                )
        
        
            def __getEuclideanDistance(self, posA, posB):
                return math.sqrt((posA.x - posB.x)**2 + (posA.y - posB.y)**2)
        
            def __isThumbNearIndexFinger(self, thumbPos, indexPos):
                return self.__getEuclideanDistance(thumbPos, indexPos) < 0.1
        
        
            def detectHands(self, capture):
                if self.__mpHandDetector is None:
                    return
        
                image = capture.color
                # Input image must contain three channel rgb data.
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                # lock image for hand detection
                image.flags.writeable = False
                # start handDetector on current image
                detectorResults = self.__mpHandDetector.process(image)
                # unlock image
                image.flags.writeable = True
        
                if detectorResults.multi_hand_landmarks:
                    for handLandmarks in detectorResults.multi_hand_landmarks:
                        self.simpleGesture(handLandmarks.landmark)
        
            def simpleGesture(self, handLandmarks):
        
                thumbIsOpen = False
                indexIsOpen = False
                middelIsOpen = False
                ringIsOpen = False
                pinkyIsOpen = False
        
                pseudoFixKeyPoint = handLandmarks[2].x
                if handLandmarks[3].x < pseudoFixKeyPoint and handLandmarks[4].x < pseudoFixKeyPoint:
                    thumbIsOpen = True
        
                pseudoFixKeyPoint = handLandmarks[6].y
                if handLandmarks[7].y < pseudoFixKeyPoint and handLandmarks[8].y < pseudoFixKeyPoint:
                    indexIsOpen = True
        
                pseudoFixKeyPoint = handLandmarks[10].y
                if handLandmarks[11].y < pseudoFixKeyPoint and handLandmarks[12].y < pseudoFixKeyPoint:
                    middelIsOpen = True
        
                pseudoFixKeyPoint = handLandmarks[14].y
                if handLandmarks[15].y < pseudoFixKeyPoint and handLandmarks[16].y < pseudoFixKeyPoint:
                    ringIsOpen = True
        
                pseudoFixKeyPoint = handLandmarks[18].y
                if handLandmarks[19].y < pseudoFixKeyPoint and handLandmarks[20].y < pseudoFixKeyPoint:
                    pinkyIsOpen = True
        
                if thumbIsOpen and indexIsOpen and middelIsOpen and ringIsOpen and pinkyIsOpen:
                    print("FIVE!")
        
                elif not thumbIsOpen and indexIsOpen and middelIsOpen and ringIsOpen and pinkyIsOpen:
                    print("FOUR!")
        
                elif not thumbIsOpen and indexIsOpen and middelIsOpen and ringIsOpen and not pinkyIsOpen:
                    print("THREE!")
        
                elif not thumbIsOpen and indexIsOpen and middelIsOpen and not ringIsOpen and not pinkyIsOpen:
                    print("TWO!")
        
                elif not thumbIsOpen and indexIsOpen and not middelIsOpen and not ringIsOpen and not pinkyIsOpen:
                    print("ONE!")
        
                elif not thumbIsOpen and indexIsOpen and not middelIsOpen and not ringIsOpen and pinkyIsOpen:
                    print("ROCK!")
        
                elif thumbIsOpen and indexIsOpen and not middelIsOpen and not ringIsOpen and pinkyIsOpen:
                    print("SPIDERMAN!")
        
                elif not thumbIsOpen and not indexIsOpen and not middelIsOpen and not ringIsOpen and not pinkyIsOpen:
                    print("FIST!")
        
                elif not indexIsOpen and middelIsOpen and ringIsOpen and pinkyIsOpen and self.__isThumbNearIndexFinger(handLandmarks[4], handLandmarks[8]):
                    print("OK!")
        
                 print("FingerState: thumbIsOpen? " + str(thumbIsOpen) + " - indexIsOpen? " + str(indexIsOpen) + " - middelIsOpen? " +
                       str(middelIsOpen) + " - ringIsOpen? " + str(ringIsOpen) + " - pinkyIsOpen? " + str(pinkyIsOpen))

@adarshx11
Copy link

image

I can Predict the Sign Gesture from A to Z and numerics also but this is like Static I've input the image file which having gesture to the model (KNN) but i want to Predict in realtime like through webcam How Can I do it?? anyone help ..... @TheJLifeX

@Jagadishrathod
Copy link

INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
Traceback (most recent call last):
File "project.py", line 80, in
recognizedHandGesture = recognizeHandGesture(getStructuredLandmarks(results.multi_hand_landmarks))
File "project.py", line 67, in getStructuredLandmarks
structuredlandmarks.append({ 'x': hand_landmarks[j], 'y': hand_landmarks[j] })
IndexError: list index out of range

@yanzhoupan
Copy link

for landmarks in detectorResults.multi_hand_landmarks:
        self.simpleGesture(landmarks)

gives me a type error
TypeError: 'NormalizedLandmarkList' object does not support indexing

It should be:

for landmarks in detectorResults.multi_hand_landmarks:
        self.simpleGesture(landmarks.landmark)

@LexQzim
Copy link

LexQzim commented Apr 7, 2021

for landmarks in detectorResults.multi_hand_landmarks:
        self.simpleGesture(landmarks)

gives me a type error
TypeError: 'NormalizedLandmarkList' object does not support indexing

It should be:

for landmarks in detectorResults.multi_hand_landmarks:
        self.simpleGesture(landmarks.landmark)

Sry, my bad.
Fixed my comment.
Thank you

@titoasty
Copy link

Nice job!
I've been able to easily detect gestures thanks to you ;)

Has any of you been able to detect hand orientation???
I'm desperately trying to compute it...
Thanks for your help!

@FarhanAhmadISM
Copy link

@TheJLifeX the link you posted above for building this repo is not working. Could you please look into it and help me how to build and run this.

@TheJLifeX
Copy link
Author

Hi @FarhanAhmadISM, the MediaPipe documentation website has changed (from https://mediapipe.readthedocs.io to https://google.github.io/mediapipe). Please visit the following links to get started with MediaPipe:

  1. Get Started with MediaPipe
  2. Hand Tracking on Desktop

@FarhanAhmadISM
Copy link

@TheJLifeX I am facing some issues to run your Hand-gesture-recognition repositories. Can you please tell me the exact commands for running your repository.
Like for hello world we need to write
bazel run --define MEDIAPIPE_DISABLE_GPU=1
mediapipe/examples/desktop/hello_world:hello_world
So for your repo to run please tell me step by step. I shall be grateful to you

@RohitSingh1226
Copy link

@TheJLifeX Will this run on windows
I am getting the following error

'build' options: --jobs 128 --define=absl=1 --cxxopt=-std=c++14 --copt=-Wno-sign-compare --copt=-Wno-unused-function --copt=-Wno-uninitialized --copt=-Wno-unused-result --copt=-Wno-comment --copt=-Wno-return-type --copt=-Wno-unused-local-typedefs --copt=-Wno-ignored-attributes --incompatible_disable_deprecated_attr_params=false --incompatible_depset_is_not_iterable=false --apple_platform_type=macos --apple_generate_dsym
ERROR: --incompatible_disable_deprecated_attr_params=false :: Unrecognized option: --incompatible_disable_deprecated_attr_params=false

@RohitSingh1226
Copy link

Updated Error

@TheJLifeX Will this run on windows
I am getting the following error

'build' options: --jobs 128 --define=absl=1 --cxxopt=-std=c++14 --copt=-Wno-sign-compare --copt=-Wno-unused-function --copt=-Wno-uninitialized --copt=-Wno-unused-result --copt=-Wno-comment --copt=-Wno-return-type --copt=-Wno-unused-local-typedefs --copt=-Wno-ignored-attributes --incompatible_disable_deprecated_attr_params=false --incompatible_depset_is_not_iterable=false --apple_platform_type=macos --apple_generate_dsym
ERROR: --incompatible_disable_deprecated_attr_params=false :: Unrecognized option: --incompatible_disable_deprecated_attr_params=false

Updated error:
mediapipe-master/mediapipe/framework/deps/BUILD:193:1: C++ compilation of rule '//mediapipe/framework/deps:registration_token' failed (Exit 2)
cl : Command line error D8021 : invalid numeric argument '/Wno-sign-compare'

@pkoppise
Copy link

pkoppise commented Nov 29, 2021

Hi @TheJLifeX

I have ported the above gist to the latest mediapipe hand tracking gpu as follows

ubuntu20@ubuntu20-OptiPlex-9020:~/mediapipe/hand-gesture-recognition$ ls
BUILD hand-gesture-recognition-calculator.cc


annotation_overlay_calculator.cc

....
....
constexpr char recognizedHandGestureTag[] = "RECOGNIZED_HAND_GESTURE";

absl::Status AnnotationOverlayCalculator::GetContract(CalculatorContract* cc) {
+RET_CHECK(cc->Inputs().HasTag(recognizedHandGestureTag)); 
+cc->Inputs().Tag(recognizedHandGestureTag).Set<std::string>();

 absl::Status AnnotationOverlayCalculator::Process(CalculatorContext* cc) {
....
.....
+const auto &recognizedHandGesture = cc->Inputs().Tag(recognizedHandGestureTag).Get<std::string>();
+renderer_->DrawText(recognizedHandGesture);

mediapipe/graphs/hand_tracking/hand_tracking_desktop_live_gpu.pbtxt

node {
calculator: "HandLandmarkTrackingGpu"
....
....
+output_stream: "RECOGNIZED_HAND_GESTURE:recognized_hand_gesture"  

node {
calculator: "HandRendererSubgraph" 
....
....
+input_stream: "RECOGNIZED_HAND_GESTURE:recognized_hand_gesture"

mediapipe/graphs/hand_tracking/subgraphs/hand_renderer_gpu.pbtxt

....
....
+input_stream: "RECOGNIZED_HAND_GESTURE:recognized_hand_gesture"

node {
calculator: "AnnotationOverlayCalculator"
....
....
+input_stream: "RECOGNIZED_HAND_GESTURE:recognized_hand_gesture"

mediapipe/modules/hand_landmark/hand_landmark_gpu.pbtxt
....
....
+node {
+calculator: "HandGestureRecognitionCalculator"
+input_stream: "NORM_LANDMARKS:scaled_landmarks"
+input_stream: "NORM_RECT:hand_rect_for_next_frame"
+}


mediapipe/modules/hand_landmark/hand_landmark_tracking_gpu.pbtxt
....
....
+output_stream: "RECOGNIZED_HAND_GESTURE:recognized_hand_gesture"

+node {
+calculator: "HandGestureRecognitionCalculator"
+output_stream: "RECOGNIZED_HAND_GESTURE:recognized_hand_gesture"
+}

mediapipe/modules/hand_landmark/BUILD

mediapipe_simple_subgraph(
name = "hand_landmark_tracking_gpu",
....
....
+"//hand-gesture-recognition:hand-gesture-recognition-calculator",

mediapipe/util/annotation_renderer.h

+void DrawText(std::string text);

mediapipe/util/annotation_renderer.cc

+void AnnotationRenderer::DrawText(std::string text)  
+{
+const int left = 275;
+const int top = 50;
+const cv::Point origin(left, top);
+const int font_size = 35;
+ const int thickness = 5;
+const cv::Scalar color = cv::Scalar(255.0, 0.0, 0.0);
+const cv::HersheyFonts font_face = cv::FONT_HERSHEY_PLAIN;
+const double font_scale = ComputeFontScale(font_face, font_size, thickness);
+cv::putText(mat_image_, text, origin, font_face, font_scale, color, thickness);
+}

got below error

E20211130 02:20:28.672209 113817 demo_run_graph_main_gpu.cc:197] Failed to run the graph: ValidatedGraphConfig Initialization failed.
HandGestureRecognitionCalculator: ; cc->Inputs().HasTag(normalizedLandmarkListTag)nd-gesture-recognition-calculator.cc:49)
HandGestureRecognitionCalculator: ; cc->Outputs().HasTag(recognizedHandGestureTag)nd-gesture-recognition-calculator.cc:55)

49---->RET_CHECK(cc->Inputs().HasTag(normalizedLandmarkListTag));
55--->RET_CHECK(cc->Outputs().HasTag(recognizedHandGestureTag));

Could you please provide any inputs on resolving the issue?

Thanks in advance

@pkoppise
Copy link

I20211130 15:43:17.350132 159695 demo_run_graph_main_gpu.cc:58] Initialize the calculator graph.
E20211130 15:43:17.352228 159695 demo_run_graph_main_gpu.cc:197] Failed to run the graph: ; Input Stream "recognized_hand_gesture" for node with sorted index 50 does not have a corresponding output stream.

@KarinaKatke
Copy link

I20211130 15:43:17.350132 159695 demo_run_graph_main_gpu.cc:58] Initialize the calculator graph. E20211130 15:43:17.352228 159695 demo_run_graph_main_gpu.cc:197] Failed to run the graph: ; Input Stream "recognized_hand_gesture" for node with sorted index 50 does not have a corresponding output stream.

I have the same Problem. Did you find a way to solve it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment