Metadata-Version: 2.4
Name: hand-tracking-mp
Version: 0.1.0
Summary: Real-time hand tracking using MediaPipe and OpenCV
Requires-Python: >=3.11
Requires-Dist: mediapipe==0.10.9
Requires-Dist: opencv-python>=4.13.0.92
Description-Content-Type: text/markdown

# Hand Tracking

Real-time hand tracking using [MediaPipe](https://developers.google.com/mediapipe) and [OpenCV](https://opencv.org/). Detects hands via webcam and processes 21 hand landmarks per hand in real time.

## Demo

| Feature | Status |
|---|---|
| Webcam capture | ✅ |
| Hand detection | ✅ |
| Landmark processing | ✅ |
| Live display window | ✅ |

## How It Works

1. Webcam frame captured via OpenCV (`cv2.VideoCapture`)
2. Frame converted BGR → RGB for MediaPipe
3. MediaPipe Hands model detects up to 2 hands and returns 21 3D landmarks per hand
4. Processed frame rendered in an OpenCV window

### MediaPipe Hand Landmarks

MediaPipe tracks 21 keypoints per hand:

```
  8   12  16  20
  |   |   |   |
  7   11  15  19
  |   |   |   |
  6   10  14  18
  |   |   |   |
  5   9   13  17
   \  |   |  /
    4 |   | 4
     \|   |/
      3   3
      |   |
      2   2
      |   |
      1   1
       \ /
        0  (WRIST)
```

Landmark indices map to: `0` = Wrist, `1-4` = Thumb, `5-8` = Index, `9-12` = Middle, `13-16` = Ring, `17-20` = Pinky.

## Requirements

- Python 3.11+
- Webcam / camera device
- [uv](https://docs.astral.sh/uv/) (recommended) or pip

## Installation

### Install as package via pip

```bash
pip install git+https://github.com/muhammadsufiyanbaig/hand-tracking.git
```

### Install as package via uv

```bash
uv add git+https://github.com/muhammadsufiyanbaig/hand-tracking.git
```

### Local development with uv (Recommended)

```bash
git clone https://github.com/muhammadsufiyanbaig/hand-tracking.git
cd hand-tracking

uv sync
```

### Local development with pip

```bash
git clone https://github.com/muhammadsufiyanbaig/hand-tracking.git
cd hand-tracking

python -m venv venv

# Windows
venv\Scripts\activate

# macOS / Linux
source venv/bin/activate

pip install -e .
```

## Usage

### CLI (after package install)

```bash
hand-tracking
```

### Module

```bash
python -m hand_tracking
```

### Script (local dev)

```bash
# uv
uv run main.py

# activated venv
python main.py
```

Press `Q` to quit.

## Project Structure

```
hand-tracking/
├── hand_tracking/
│   ├── __init__.py         # Package init, exposes __version__
│   └── __main__.py         # Core tracking logic + CLI entry point
├── main.py                 # Thin shim for direct script execution
├── hand_landmarker.task    # MediaPipe hand landmark model (task file)
├── pyproject.toml          # Package metadata, dependencies, build config
├── uv.lock                 # Locked dependency versions
├── .python-version         # Pinned Python version (3.11)
└── README.md
```

## Dependencies

| Package | Version | Purpose |
|---|---|---|
| `mediapipe` | 0.10.9 | Hand landmark detection model |
| `opencv-python` | ≥4.13.0 | Webcam capture and image rendering |

## Configuration

`mpHands.Hands()` accepts optional parameters:

| Parameter | Default | Description |
|---|---|---|
| `static_image_mode` | `False` | `True` for images, `False` for video stream |
| `max_num_hands` | `2` | Maximum number of hands to detect |
| `min_detection_confidence` | `0.5` | Minimum score to consider detection valid |
| `min_tracking_confidence` | `0.5` | Minimum score to keep tracking (video mode) |

Example with custom config:

```python
hands = mpHands.Hands(
    max_num_hands=1,
    min_detection_confidence=0.7,
    min_tracking_confidence=0.6
)
```

## Extending the Project

Common next steps:

**Draw landmarks on frame:**
```python
mpDraw = mp.solutions.drawing_utils
if results.multi_hand_landmarks:
    for handLms in results.multi_hand_landmarks:
        mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS)
```

**Read a specific landmark (e.g. index fingertip = landmark 8):**
```python
if results.multi_hand_landmarks:
    for handLms in results.multi_hand_landmarks:
        h, w, _ = img.shape
        lm = handLms.landmark[8]
        cx, cy = int(lm.x * w), int(lm.y * h)
```

**Display FPS:**
```python
pTime = 0
# inside loop:
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(img, f"FPS: {int(fps)}", (10, 70),
            cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3)
```

## License

MIT
