feng-x commited on
Commit
7ca48d2
·
verified ·
1 Parent(s): dbfd887

Upload folder using huggingface_hub

Browse files
measure_finger.py CHANGED
@@ -40,6 +40,7 @@ from src.confidence import (
40
  compute_overall_confidence,
41
  )
42
  from src.debug_observer import draw_comprehensive_edge_overlay, draw_hand_skeleton
 
43
  from src.ring_size import recommend_ring_size, aggregate_ring_sizes, VALID_RING_MODELS, DEFAULT_RING_MODEL
44
  from src.image_quality import (
45
  check_card_in_frame,
@@ -997,10 +998,14 @@ def measure_finger(
997
  # Tint SAM hand + card masks as underlays. Both masks live in the
998
  # pre-precise-rotation canonical frame, so apply the same rotation
999
  # matrix that was used to align the finger.
 
 
 
 
1000
  debug_image = _overlay_sam_masks(
1001
  debug_image,
1002
  hand_mask=hand_data.get("mask") if hand_data else None,
1003
- card_mask=card_result.get("mask") if card_result else None,
1004
  rotation_matrix=rotation_matrix,
1005
  )
1006
 
@@ -1013,16 +1018,16 @@ def measure_finger(
1013
  rotation_matrix=rotation_matrix,
1014
  )
1015
 
1016
- # Draw card bounding box (transform corners if image was rotated)
1017
- if card_result is not None and "corners" in card_result:
1018
- corners = card_result["corners"]
1019
- if corners is not None:
1020
- pts = np.array(corners, dtype=np.float32)
1021
- if rotation_matrix is not None:
1022
- pts = transform_points_rotation(pts, rotation_matrix)
1023
- pts = pts.astype(np.int32).reshape((-1, 1, 2))
1024
- cv2.polylines(debug_image, [pts], isClosed=True,
1025
- color=(0, 255, 0), thickness=3, lineType=cv2.LINE_AA)
1026
 
1027
  # Save result image (downscaled + JPEG-encoded for speed)
1028
  _save_debug_visualization(result_png_path, debug_image)
@@ -1468,11 +1473,13 @@ def _draw_multi_finger_debug(
1468
  vis = image_canonical.copy()
1469
  h, w = vis.shape[:2]
1470
 
1471
- # SAM silhouettes (hand + card) as tinted underlays
 
 
1472
  vis = _overlay_sam_masks(
1473
  vis,
1474
  hand_mask=hand_mask,
1475
- card_mask=(card_result.get("mask") if card_result else None),
1476
  )
1477
 
1478
  # MediaPipe hand skeleton (canonical frame — no rotation needed since the
 
40
  compute_overall_confidence,
41
  )
42
  from src.debug_observer import draw_comprehensive_edge_overlay, draw_hand_skeleton
43
+ from src.visualization import draw_card_overlay
44
  from src.ring_size import recommend_ring_size, aggregate_ring_sizes, VALID_RING_MODELS, DEFAULT_RING_MODEL
45
  from src.image_quality import (
46
  check_card_in_frame,
 
998
  # Tint SAM hand + card masks as underlays. Both masks live in the
999
  # pre-precise-rotation canonical frame, so apply the same rotation
1000
  # matrix that was used to align the finger.
1001
+ # Only the hand SAM mask gets tinted as an underlay. The card SAM
1002
+ # mask often has stray blobs outside the actual card rectangle; the
1003
+ # detected corners already give us a clean quadrilateral, so we
1004
+ # shade that via draw_card_overlay below instead.
1005
  debug_image = _overlay_sam_masks(
1006
  debug_image,
1007
  hand_mask=hand_data.get("mask") if hand_data else None,
1008
+ card_mask=None,
1009
  rotation_matrix=rotation_matrix,
1010
  )
1011
 
 
1018
  rotation_matrix=rotation_matrix,
1019
  )
1020
 
1021
+ # Shade + outline the card using its detected corner rectangle.
1022
+ if card_result is not None and card_result.get("corners") is not None:
1023
+ pts = np.asarray(card_result["corners"], dtype=np.float32)
1024
+ if rotation_matrix is not None:
1025
+ pts = transform_points_rotation(pts, rotation_matrix)
1026
+ draw_card_overlay(
1027
+ debug_image,
1028
+ {"corners": pts},
1029
+ scale_px_per_cm=px_per_cm,
1030
+ )
1031
 
1032
  # Save result image (downscaled + JPEG-encoded for speed)
1033
  _save_debug_visualization(result_png_path, debug_image)
 
1473
  vis = image_canonical.copy()
1474
  h, w = vis.shape[:2]
1475
 
1476
+ # Hand SAM silhouette as a tinted underlay. The card is shaded via its
1477
+ # clean corner rectangle in draw_card_overlay() below rather than the
1478
+ # raw SAM mask (which often has stray blobs outside the card boundary).
1479
  vis = _overlay_sam_masks(
1480
  vis,
1481
  hand_mask=hand_mask,
1482
+ card_mask=None,
1483
  )
1484
 
1485
  # MediaPipe hand skeleton (canonical frame — no rotation needed since the
src/visualization.py CHANGED
@@ -129,10 +129,22 @@ def draw_card_overlay(
129
  card_result: Dict[str, Any],
130
  scale_px_per_cm: Optional[float] = None,
131
  ) -> np.ndarray:
132
- """Draw credit card detection overlay."""
133
- corners = card_result["corners"].astype(np.int32)
 
 
 
 
 
134
  params = get_scaled_font_params(image.shape[0])
135
 
 
 
 
 
 
 
 
136
  # Draw quadrilateral
137
  cv2.polylines(image, [corners], isClosed=True, color=Color.CARD,
138
  thickness=params["contour_thickness"])
 
129
  card_result: Dict[str, Any],
130
  scale_px_per_cm: Optional[float] = None,
131
  ) -> np.ndarray:
132
+ """Draw credit card detection overlay.
133
+
134
+ The card region is highlighted by shading just the detected corner
135
+ rectangle (not the raw SAM mask, which can have noisy overspill). A
136
+ solid outline with TL/TR/BR/BL corner labels is drawn on top.
137
+ """
138
+ corners = np.asarray(card_result["corners"], dtype=np.int32)
139
  params = get_scaled_font_params(image.shape[0])
140
 
141
+ # Semi-transparent fill inside the corner quadrilateral. Avoids the
142
+ # visual clutter of drawing the raw SAM mask (which often has stray
143
+ # blobs outside the real card boundary).
144
+ tint = np.zeros_like(image)
145
+ cv2.fillConvexPoly(tint, corners, Color.CARD)
146
+ cv2.addWeighted(image, 1.0, tint, 0.22, 0, dst=image)
147
+
148
  # Draw quadrilateral
149
  cv2.polylines(image, [corners], isClosed=True, color=Color.CARD,
150
  thickness=params["contour_thickness"])
web_demo/static/app.js CHANGED
@@ -108,8 +108,9 @@ const buildMeasureSettings = () => {
108
  const aiToggle = document.getElementById("aiExplainToggle");
109
  const mode = modeSelect ? modeSelect.value : "multi";
110
  const ringModel = ringModelSelect ? ringModelSelect.value : "gen";
111
- // Hidden inputs (non-dev mode) have no `checked` property treat as on.
112
- const aiOn = aiToggle ? (aiToggle.type === "checkbox" ? aiToggle.checked : true) : false;
 
113
  return {
114
  finger_index: fingerSelect ? fingerSelect.value : "index",
115
  edge_method: "mask",
 
108
  const aiToggle = document.getElementById("aiExplainToggle");
109
  const mode = modeSelect ? modeSelect.value : "multi";
110
  const ringModel = ringModelSelect ? ringModelSelect.value : "gen";
111
+ // AI explanation is off by default. Dev mode shows a checkbox the user
112
+ // can opt into; non-dev mode has no UI control and therefore stays off.
113
+ const aiOn = aiToggle && aiToggle.type === "checkbox" ? aiToggle.checked : false;
114
  return {
115
  finger_index: fingerSelect ? fingerSelect.value : "index",
116
  edge_method: "mask",
web_demo/static/examples/default_sample.jpg CHANGED

Git LFS Details

  • SHA256: 9148ccfc4e8b503d8984d93c855e8c5b3b466d074764db9d53a57e4648fdfb2f
  • Pointer size: 132 Bytes
  • Size of remote file: 2.4 MB

Git LFS Details

  • SHA256: e1eda5bf66094a01ee2c5ba3a1b8af26550a34b90129fe0787ceda60be32f03e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.56 MB
web_demo/templates/index.html CHANGED
@@ -26,11 +26,12 @@
26
  <span class="file-hint">JPG / PNG supported · 1080p or higher recommended</span>
27
  </label>
28
 
29
- <ul class="capture-tips" hidden>
30
- <li><strong>Turn on your phone's flash</strong>, it helps sharpen the finger edges.</li>
 
31
  <li><strong>Use plain white background</strong>, a sheet of paper works great.</li>
32
- <li><strong>Spread your fingers naturally</strong>, place the card beside your hand.</li>
33
- <li>Hold the phone <strong>directly above</strong> your hand, keep it <strong>parallel</strong> to the table.</li>
34
  </ul>
35
 
36
  <div class="controls">
@@ -66,7 +67,7 @@
66
  <label class="toggle-label">
67
  <span>AI Explanation</span>
68
  <div class="toggle-row">
69
- <input type="checkbox" id="aiExplainToggle" checked />
70
  <span class="toggle-hint">Uses OpenAI tokens</span>
71
  </div>
72
  </label>
 
26
  <span class="file-hint">JPG / PNG supported · 1080p or higher recommended</span>
27
  </label>
28
 
29
+ <ul class="capture-tips">
30
+ <li><strong>Turn on your phone's flash</strong>, it sharpens finger edges.</li>
31
+ <li>Hold phone <strong>directly above</strong> hand, <strong>parallel</strong> to table.</li>
32
  <li><strong>Use plain white background</strong>, a sheet of paper works great.</li>
33
+ <li><strong>Spread your fingers naturally</strong>.</li>
34
+ <li>Place the card <strong>beside your hand</strong>, fully visible.</li>
35
  </ul>
36
 
37
  <div class="controls">
 
67
  <label class="toggle-label">
68
  <span>AI Explanation</span>
69
  <div class="toggle-row">
70
+ <input type="checkbox" id="aiExplainToggle" />
71
  <span class="toggle-hint">Uses OpenAI tokens</span>
72
  </div>
73
  </label>