πŸ€– LateAI
Home β€Ί Tutorials β€Ί Hand Tracking
πŸ–οΈ

Hand Tracking

Beginner Β· 1-2 hours
πŸ“Ά Beginner ⏱ 1-2 hours πŸ’° Free (software only) 🏷 CV Zone

πŸ“Œ Overview

Hand tracking is the classic entry point into CV Zone: a camera detects hands in real time and locates the 21 hand landmarks (fingertips, knuckles, wrist, and so on).

Under the hood it uses Google's MediaPipe hand model plus OpenCV for the video feed, and the video author wrapped it into the cvzone HandTrackingModule so it runs in just a few lines of code. Later projects such as the virtual mouse, virtual painter, and finger counter all build on this module, which is why it is considered the foundation of hand-gesture applications.

πŸ”¬ How it works

1. How to read the 21 hand landmarks

MediaPipe outputs 21 landmarks per hand with fixed indices: 0 is the wrist; 1-4 the thumb (4 is the tip); 5-8 the index finger (8 is the tip); 9-12 the middle finger (12); 13-16 the ring finger (16); 17-20 the little finger (20).

Remember the rule 'fingertip indices = 4 / 8 / 12 / 16 / 20' - the virtual mouse, finger counter, and volume control all read these points and reason about their geometry.

2. What the HandDetector wraps

cvzone's HandTrackingModule packs three things into a few lines of API: running the MediaPipe Hands inference, converting normalised coordinates back to frame pixels, and tidying the result into a dictionary.

The dictionary returned for each hand has four keys: lmList (a list of 21 [x, y, z] points), bbox (the hand bounding box x/y/w/h), center (the palm centre), and type (Left/Right).

It is the shared foundation of the rest of the gesture projects on this site - learn this one and you already have the detection half of the virtual mouse, virtual painter, and finger counter.

3. How recognition works (the plain-English version)

MediaPipe Hands works in two steps: a lightweight network first locates the hand in the whole frame (palm detection), then keypoint regression runs on the cropped hand region; once a hand is found, later frames take the faster tracking path, so it comfortably hits real-time frame rates.

The trackCon and detectionCon confidences control whether it tracks or re-detects: when the hand is lost (confidence drops below trackCon) it automatically falls back to full detection.

🧰 What you need

πŸ”§ Step by step

1

Set up the environment

Create a virtual environment and run pip install opencv-python mediapipe cvzone

Use a local mirror if the download is slow

2

Capture the camera stream

Open the camera with OpenCV's VideoCapture(0)

Flip the frame after reading it so the controls feel natural

3

Initialise the hand detector

Import and instantiate HandTrackingModule from cvzone

Key parameters: static mode, max hands (1 by default), detection confidence

4

Detect, draw points, and connect them

Call findHands() every frame to get the landmark coordinates

drawLandmarks paints the 21 points and the skeleton connections onto the frame

5

Read individual landmark coordinates

Use lmList to get the (x, y) pixel coordinate of each landmark

Index into it to pick fingertips and other key points for your own logic

6

Wrap it up and extend

Wrap the detection logic in a function or class so it can be reused

This module is the base layer for the virtual mouse, painter, and volume control

πŸ’» Full code examples

Code 1 - Minimal working version (draw the skeleton and mark the index fingertip)
# Dependencies: pip install opencv-python mediapipe==0.10.14 cvzone
# Note: cvzone still uses the older MediaPipe Hands API,
#       installing the latest mediapipe breaks the solutions module - pin 0.10.14
import cv2
from cvzone.HandTrackingModule import HandDetector

cap = cv2.VideoCapture(0)                # open the camera (0 is the default camera)
detector = HandDetector(detectionCon=0.8, maxHands=1)   # detection confidence 0.8, at most 1 hand

while True:
    ok, img = cap.read()                 # read frame by frame
    if not ok:
        break
    img = cv2.flip(img, 1)               # mirror horizontally, like looking in a mirror

    hands, img = detector.findHands(img) # detect and draw the 21-point skeleton, returns the list of hands

    if hands:
        hand = hands[0]
        lmList = hand["lmList"]          # 21 landmarks [[x, y, z], ...], z is depth
        bbox   = hand["bbox"]            # (x, y, w, h)
        cx, cy = hand["center"]          # palm centre
        tip    = lmList[8][:2]           # index fingertip coordinate (index 8)
        cv2.circle(img, tip, 8, (0, 255, 255), cv2.FILLED)  # highlight the index fingertip in yellow

    cv2.imshow("Hand Tracking", img)
    if cv2.waitKey(1) & 0xFF == ord("q"):  # press q to quit
        break

cap.release()
cv2.destroyAllWindows()
Code 2 - Multiple hands, marked fingertips, and left/right labels
import cv2
from cvzone.HandTrackingModule import HandDetector

cap = cv2.VideoCapture(0)
detector = HandDetector(detectionCon=0.8, maxHands=2)   # detect up to 2 hands at once

while True:
    ok, img = cap.read()
    if not ok:
        break
    img = cv2.flip(img, 1)
    hands, img = detector.findHands(img)   # findHands already draws the skeleton and box by default

    if hands:
        for hand in hands:
            # five fingertip indices: thumb 4, index 8, middle 12, ring 16, little 20
            for i in [4, 8, 12, 16, 20]:
                x, y = hand["lmList"][i][:2]
                cv2.circle(img, (x, y), 7, (0, 255, 0), cv2.FILLED)
            x, y = hand["bbox"][:2]
            cv2.putText(img, hand["type"], (x, y - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 255), 2)

    cv2.imshow("Hand Tracking", img)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

βš™οΈ Key parameters

ParameterDefaultWhat it does
staticModeFalseWhether to run full detection on every frame. With False it switches to tracking mode once a hand is found, which raises the frame rate; True suits scenes where the hand is still and you want maximum stability, at a higher CPU cost.
maxHands2Maximum number of hands detected in the frame. Set it to 1 for single-hand control applications to save compute.
modelComplexity1Model complexity, 0 or 1. Higher is more accurate but slower; the default of 1 is fine on an ordinary laptop.
detectionCon0.5Confidence threshold for the initial detection (0-1). If hands are not being detected, lowering it to 0.5-0.6 helps, but too low introduces false positives.
trackCon0.5Confidence threshold for frame-to-frame tracking. Once tracking is lost it falls back to full detection automatically; you normally do not need to change this.

πŸ’‘ Tips

🧯 Troubleshooting

Import fails after installing mediapipe, or it cannot find Hands?

Newer mediapipe releases (0.10.20+) removed the older solutions.hands interface, while cvzone still depends on it. Pin the version: pip install mediapipe==0.10.14, and use Python 3.8-3.11 (there are no prebuilt wheels of the old mediapipe for 3.12+).

The camera works but no hand is ever detected?

Work through this order: 1) is the lighting even (strong backlight almost always fails, side lighting is best); 2) is the hand 30-80cm from the lens and fully in frame; 3) drop detectionCon from 0.8 to 0.5-0.6 and retry; 4) confirm maxHands is not set to 0.

The video stutters and CPU usage is high?

Set the camera resolution to 640x480; keep staticMode=False; use findHands(img, draw=False) when you do not need the skeleton drawn; and reduce the number of hands detected at once.

The left/right type is reversed?

type is labelled by where the hand appears in the frame, not by your physical left or right. It is normal for it to look swapped after mirroring; if your logic depends on the real hand, swap the two values or derive it yourself from the x difference between the index-finger base and the palm centre.

What units are the lmList coordinates in?

lmList holds pixel coordinates [x, y, z]: x and y are frame pixel positions, and z is a normalised relative depth (0 at the wrist, useful for telling whether a finger is curling towards the camera). Use x and y directly when mapping to a canvas or the screen.

πŸ“¦ Course & resources

View original β†— ← Back to LateAI home