Back to All Projects
Computer Vision  ·  Python  ·  2024

HandGesture

Draw on screen with just your index finger, real-time hand landmark detection, gesture classification, and canvas rendering from a live webcam feed. No hardware required.

Python MediaPipe OpenCV Computer Vision Real-Time Machine Learning
Status
Completed
Year
2024
Role
Solo Developer
Language
Python 3
Category
Computer Vision
01 Project Overview

HandGesture turns your webcam into a drawing canvas. Raise your index finger to draw; hover over on-screen buttons to switch colours, start, stop, or clear. No mouse, stylus, or touchscreen — just a camera and your hand.

Built in Python using OpenCV for video capture and canvas compositing, and MediaPipe Hands for multi-hand 21-landmark detection. The system can track up to 4 hands simultaneously at 30+ FPS, all on a standard laptop CPU, no GPU required.

What I learned: Every physical hand posture produces a unique spatial relationship between 21 detected joint coordinates. A simple rule-based classifier on those coordinates is enough to reliably distinguish "drawing mode" from "idle mode" in real time.
02 How It Works
1
Video Capture & Preprocessing
OpenCV opens the default webcam, reads frames in a loop, mirrors the image horizontally (so movement feels natural), and converts from BGR → RGB colour space for MediaPipe processing.
2
21-Point Landmark Detection
MediaPipe Hands processes each RGB frame and returns normalised (x, y, z) coordinates for 21 keypoints per hand, wrist (0), MCP joints (1,5,9,13,17), PIP joints (2,6,10,14,18), DIP joints (3,7,11,15,19), and fingertips (4,8,12,16,20).
3
Gesture Classification (Rule-Based)
A geometric classifier checks the y-coordinates of each finger's tip vs. its proximal knuckle (MCP). If only the index fingertip (landmark 8) is above its MCP (landmark 5) while all other tips are below theirs → drawing mode active.
4
Canvas Drawing
When in drawing mode, the app tracks the index fingertip pixel position (landmark 8 × frame dimensions) and calls cv2.line() between the current and previous position onto a persistent canvas layer.
5
Button Hit-Testing & Overlay
On-screen buttons are fixed pixel regions. Each frame, if the fingertip coordinate falls within a button's bounding box, the action fires. The canvas layer is composited onto the live frame using cv2.addWeighted() and displayed in real time.

OpenCV opens the default webcam, reads frames in a loop, mirrors the image horizontally (so movement feels natural), and converts from BGR → RGB colour space for MediaPipe processing.

MediaPipe Hands processes each RGB frame and returns normalised (x, y, z) coordinates for 21 keypoints per hand, wrist, MCP joints, PIP joints, DIP joints, and fingertips.

A geometric classifier checks the y-coordinates of each finger's tip vs. its proximal knuckle (MCP). If only the index fingertip is above its MCP while all others are below → drawing mode.

When in drawing mode, the app tracks the index fingertip pixel position and calls cv2.line() between the current and previous position onto a persistent canvas layer.

On-screen buttons are fixed pixel regions. Each frame, if the fingertip coordinate falls within a button's bounding box, the action fires. The canvas layer is composited onto the live frame using cv2.addWeighted() and displayed in real time.

03 Processing Pipeline
Input
Webcam Frame
BGR · 640×480
Preprocess
Flip + BGR→RGB
Mirror image
Detect
MediaPipe Hands
21 landmarks/hand
Classify
Gesture Check
Rule-based logic
Render
Canvas Overlay
cv2.addWeighted
Output
Display Window
imshow · 30+ FPS
swipe to explore the full pipeline
04 The Math & Gesture Logic

MediaPipe returns normalised landmark coordinates in the range [0.0, 1.0]. To convert to pixel coordinates on the actual frame:

01Coordinate Denormalisation
pixel_x = landmark.x × frame_width
pixel_y = landmark.y × frame_height

Where landmark.x and landmark.y are values from MediaPipe in range [0,1]. Multiplying by frame dimensions gives pixel coordinates, so the same tracking code works identically on a 640×480 or 1920×1080 webcam — the model never needs to know the resolution.

# Webcam frame: 640 × 480
landmark.x = 0.512   landmark.y = 0.347

pixel_x = 0.512 × 640  = 327.68  →  328 px
pixel_y = 0.347 × 480  = 166.56  →  167 px

# Same landmark, 1920×1080 frame:
pixel_x = 0.512 × 1920 = 983.04  →  983 px
pixel_y = 0.347 × 1080 = 374.76  →  375 px
02Drawing Gesture Classifier
is_drawing = (
    tip_y[INDEX]   < mcp_y[INDEX]   AND   # index finger up
    tip_y[MIDDLE]  > mcp_y[MIDDLE]  AND   # middle finger down
    tip_y[RING]    > mcp_y[RING]    AND   # ring finger down
    tip_y[PINKY]   > mcp_y[PINKY]         # pinky down
)

Since MediaPipe's y-axis is top-down (y=0 at top), a fingertip above its knuckle means tip_y < mcp_y. That gives a binary classifier which fires only on the drawing pose — index extended, all other fingers curled. No machine learning; pure landmark geometry, checked every frame.

# Hand landmarks (normalised, from MediaPipe)
tip_y[INDEX]  = 0.31   mcp_y[INDEX]  = 0.52   → 0.31 < 0.52  ✓ UP
tip_y[MIDDLE] = 0.58   mcp_y[MIDDLE] = 0.54   → 0.58 > 0.54  ✓ DOWN
tip_y[RING]   = 0.61   mcp_y[RING]   = 0.55   → 0.61 > 0.55  ✓ DOWN
tip_y[PINKY]  = 0.63   mcp_y[PINKY]  = 0.56   → 0.63 > 0.56  ✓ DOWN

→ all 4 conditions true → is_drawing = True
03Button Hit Test (AABB)
is_hitting_button = (
    btn.x1 <= finger_x <= btn.x2  AND
    btn.y1 <= finger_y <= btn.y2
)

Each on-screen button is an axis-aligned bounding box (AABB), the simplest possible collision test, borrowed straight from 2D game physics. The fingertip's pixel coordinate is checked against every button rectangle each frame — no click event, no debounce beyond a short hold-to-confirm, just geometry re-evaluated 30 times a second.

# "Clear Canvas" button region:
btn = { x1: 500, y1: 20, x2: 620, y2: 70 }

# Fingertip at frame coordinate (560, 45):
500 <= 560 <= 620   →  True
 20 <=  45 <=  70   →  True

→ is_hitting_button = True  →  canvas.clear()
05 Key Features
Real-Time Finger Drawing
Tracks index fingertip position at 30+ FPS and draws continuous strokes on a canvas overlay composited onto the live video feed. Sub-frame latency on standard hardware.
4-Color Brush System
Blue, Green, Red, and Pink brushes selectable by hovering your fingertip over on-screen buttons. Color switches instantly, no pause in drawing required.
Multi-Hand Tracking (up to 4)
MediaPipe processes up to 4 simultaneous hands in a single frame, enabling collaborative multi-finger drawing or left/right hand switching mid-session.
Gesture-Only Controls
Start/Stop drawing and Clear canvas are all triggered by fingertip bounding-box collision with on-screen button regions, zero keyboard/mouse interaction required.
06 Use Cases
Touchless Digital Art
Sketch and paint on screen without any physical input device, useful for hygiene-sensitive or hardware-constrained environments.
Interactive Presentations
Draw annotations on slides or whiteboards in real time during a live lecture or webinar without touching a keyboard.
Assistive Technology
Enables users with limited hand mobility to interact with digital interfaces using only gross motor movements captured by webcam.
Gesture-Based Games
Foundation for building gesture-controlled mini-games, interactive installations, or educational drawing apps for children.
07 Video Demonstration

MediaPipe detecting 21 hand landmarks in real time, the index-finger drawing engine tracing strokes on the canvas overlay, and gesture-based button interactions, all at 30+ FPS directly from a standard webcam.

DemoLandmark tracking, the drawing engine, and gesture buttons running live at 30+ FPS
08 Controls Reference
Control Trigger Action
START Fingertip hover Enable drawing mode, fingertip traces strokes
STOP Fingertip hover Disable drawing, tracking stays active, no strokes
CLEAR Fingertip hover Wipe entire canvas clean
COLOR Hover color button Switch brush: Blue / Green / Red / Pink
Q Keyboard Quit the application
Tech Stack
Python 3 MediaPipe OpenCV NumPy Webcam API cv2.addWeighted
Try it yourself
Clone the repo, install dependencies, and run python handgesture.py. All you need is a webcam and a well-lit room.
View on GitHub