File size: 3,795 Bytes
e19f48f
 
347d1a8
e19f48f
347d1a8
e19f48f
347d1a8
e19f48f
 
347d1a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
---
title: Ring Sizer
emoji: "\U0001F48D"
colorFrom: blue
colorTo: purple
sdk: docker
app_port: 7860
---

# Ring Sizer

Local computer-vision CLI tool that measures **finger outer diameter** from a single image using a **credit card** as scale reference.

## What it does
- Detects a credit card and computes `px/cm` scale.
- Detects hand/finger with MediaPipe.
- Measures finger width in the ring-wearing zone.
- Supports dual edge modes:
  - `contour` (v0 baseline)
  - `sobel` (v1 refinement)
  - `auto` (default, Sobel with quality fallback)
  - `compare` (returns both method stats)
- Writes JSON output and always writes a result PNG next to it.

## Install
```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

## Run
```bash
python measure_finger.py --input input/test_image.jpg --output output/result.json
```

### Common options
```bash
# Enable intermediate debug folders (card/finger/edge stages)
python measure_finger.py --input image.jpg --output output/result.json --debug

# Finger selection
python measure_finger.py --input image.jpg --output output/result.json --finger-index ring

# Force method
python measure_finger.py --input image.jpg --output output/result.json --edge-method contour
python measure_finger.py --input image.jpg --output output/result.json --edge-method sobel

# Compare contour vs sobel
python measure_finger.py --input image.jpg --output output/result.json --edge-method compare

# Sobel tuning
python measure_finger.py --input image.jpg --output output/result.json \
  --edge-method sobel --sobel-threshold 15 --sobel-kernel-size 3 --no-subpixel
```

## CLI flags (current)
- `--input` (required)
- `--output` (required)
- `--debug` (boolean; saves intermediate debug folders)
- `--save-intermediate`
- `--finger-index {auto,index,middle,ring,pinky}` (default `index`)
- `--confidence-threshold` (default `0.7`)
- `--edge-method {auto,contour,sobel,compare}` (default `auto`)
- `--sobel-threshold` (default `15.0`)
- `--sobel-kernel-size {3,5,7}` (default `3`)
- `--no-subpixel`
- `--skip-card-detection` (testing only)

## Output JSON
```json
{
  "finger_outer_diameter_cm": 1.78,
  "confidence": 0.91,
  "scale_px_per_cm": 203.46,
  "quality_flags": {
    "card_detected": true,
    "finger_detected": true,
    "view_angle_ok": true
  },
  "fail_reason": null,
  "edge_method_used": "contour_fallback",
  "method_comparison": {
    "contour": {
      "width_cm": 1.82,
      "width_px": 371.2,
      "std_dev_px": 3.8,
      "coefficient_variation": 0.01,
      "num_samples": 20,
      "method": "contour"
    },
    "sobel": {
      "width_cm": 1.78,
      "width_px": 362.0,
      "std_dev_px": 3.1,
      "coefficient_variation": 0.008,
      "num_samples": 140,
      "subpixel_used": true,
      "success_rate": 0.42,
      "edge_quality_score": 0.81,
      "method": "sobel"
    },
    "difference": {
      "absolute_cm": -0.04,
      "absolute_px": -9.2,
      "relative_pct": -2.2,
      "precision_improvement": 0.7
    },
    "recommendation": {
      "use_sobel": true,
      "reason": "quality_acceptable",
      "preferred_method": "sobel"
    },
    "quality_comparison": {
      "contour_cv": 0.01,
      "sobel_cv": 0.008,
      "sobel_quality_score": 0.81,
      "sobel_gradient_strength": 0.82,
      "sobel_consistency": 0.42,
      "sobel_smoothness": 0.91,
      "sobel_symmetry": 0.95
    }
  }
}
```

Notes:
- `edge_method_used` and `method_comparison` are optional (present when relevant).
- Result image path is auto-derived: `output/result.json` -> `output/result.png`.

## Documentation map
- Requirement docs: `doc/v{i}/PRD.md`, `doc/v{i}/Plan.md`, `doc/v{i}/Progress.md`
- Algorithms index: `doc/algorithms/README.md`
- Scripts: `script/README.md`
- Web demo: `web_demo/README.md`