Muhammad Rafi Arsya
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 · 30+ FPS 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, draw freely on screen. No mouse, stylus, or touchscreen — just a camera and your hand. Raise your index finger and draw freely on screen; hover over on-screen buttons to switch colors, start, stop, or clear. No mouse, stylus, or touchscreen needed.

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
scroll for full derivation

Where landmark.x and landmark.y are values from MediaPipe in range [0,1]. Multiplying by frame dimensions gives screen coordinates in pixels — this is what makes the same gesture-tracking code work identically on a 640×480 webcam or a 1920×1080 one, since the model never has 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
scroll to see full computation
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
)
scroll for full derivation

Since MediaPipe's y-axis is top-down (y=0 at top), a fingertip above its knuckle means tip_y < mcp_y. This gives a clean binary classifier that reliably fires only when the drawing pose — index extended, all other fingers curled — is held. No machine learning needed; 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
scroll to see full computation
03Button Hit Test (AABB)
is_hitting_button = (
    btn.x1 <= finger_x <= btn.x2  AND
    btn.y1 <= finger_y <= btn.y2
)
scroll for full derivation

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 denormalised pixel coordinate is checked against every button's rectangle on every frame; no click event, no debounce logic 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()
scroll to see full computation
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.

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
By the Numbers
21
Landmarks / hand
30+
FPS real-time
4
Hands tracked
4
Brush colors
Completion
Landmark Detection100%
Gesture Classifier100%
Canvas Drawing100%
Multi-Hand Support100%
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