feng-x commited on
Commit
8e8d804
·
verified ·
1 Parent(s): b18951f

Upload folder using huggingface_hub

Browse files
measure_finger.py CHANGED
@@ -368,6 +368,10 @@ def _overlay_card_seeds(
368
  precise-rotation) frame; pass ``rotation_matrix`` to align with an image
369
  that had the finger rotation applied.
370
  """
 
 
 
 
371
  if not seed_debug:
372
  return image
373
  from src.geometry import transform_points_rotation
@@ -501,13 +505,13 @@ def _sam_card_detect(
501
  hand_mask = hand_data.get("mask")
502
  landmarks = hand_data.get("landmarks")
503
 
504
- if hand_mask is None or landmarks is None or len(landmarks) <= 10:
505
  return None
506
 
507
- middle_pip = landmarks[10, :2]
508
- anchor_xy = (int(round(middle_pip[0])), int(round(middle_pip[1])))
509
 
510
- seed_info = suggest_card_seeds(hand_mask, image_canonical.shape[:2], anchor_xy)
511
  seeds = seed_info["kept"]
512
  dropped_seeds = seed_info["dropped"]
513
  if not seeds:
@@ -530,7 +534,6 @@ def _sam_card_detect(
530
  # Stash seed geometry so the final result PNG can visualize what was
531
  # prompted into SAM, even when card detection fails.
532
  seed_debug = {
533
- "anchor": anchor_xy,
534
  "seeds": list(seeds),
535
  "dropped": list(dropped_seeds),
536
  "negatives": list(negatives),
 
368
  precise-rotation) frame; pass ``rotation_matrix`` to align with an image
369
  that had the finger rotation applied.
370
  """
371
+
372
+ # temprary bypass by Feng
373
+ return image
374
+
375
  if not seed_debug:
376
  return image
377
  from src.geometry import transform_points_rotation
 
505
  hand_mask = hand_data.get("mask")
506
  landmarks = hand_data.get("landmarks")
507
 
508
+ if hand_mask is None or landmarks is None or len(landmarks) <= 9:
509
  return None
510
 
511
+ middle_mcp = landmarks[9, :2]
512
+ y_limit = int(round(middle_mcp[1]))
513
 
514
+ seed_info = suggest_card_seeds(hand_mask, image_canonical.shape[:2], y_limit)
515
  seeds = seed_info["kept"]
516
  dropped_seeds = seed_info["dropped"]
517
  if not seeds:
 
534
  # Stash seed geometry so the final result PNG can visualize what was
535
  # prompted into SAM, even when card detection fails.
536
  seed_debug = {
 
537
  "seeds": list(seeds),
538
  "dropped": list(dropped_seeds),
539
  "negatives": list(negatives),
script/validate_sam_card.py CHANGED
@@ -78,11 +78,11 @@ def run_one(img_path: Path) -> dict:
78
  if hand_data is not None:
79
  prompt_debug = OUT_DIR / img_path.stem / "sam_card_prompt"
80
  landmarks = hand_data.get("landmarks")
81
- if landmarks is None or len(landmarks) <= 10:
82
  return rec
83
- mp = landmarks[10, :2]
84
- anchor_xy = (int(round(mp[0])), int(round(mp[1])))
85
- seed_info = suggest_card_seeds(hand_data["mask"], canonical.shape[:2], anchor_xy)
86
  seeds = seed_info["kept"]
87
  rec["prompt_n_seeds"] = len(seeds)
88
  negs = _negatives_from_landmarks(hand_data["landmarks"])
 
78
  if hand_data is not None:
79
  prompt_debug = OUT_DIR / img_path.stem / "sam_card_prompt"
80
  landmarks = hand_data.get("landmarks")
81
+ if landmarks is None or len(landmarks) <= 9:
82
  return rec
83
+ middle_mcp = landmarks[9, :2]
84
+ y_limit = int(round(middle_mcp[1]))
85
+ seed_info = suggest_card_seeds(hand_data["mask"], canonical.shape[:2], y_limit)
86
  seeds = seed_info["kept"]
87
  rec["prompt_n_seeds"] = len(seeds)
88
  negs = _negatives_from_landmarks(hand_data["landmarks"])
src/sam_card_detection.py CHANGED
@@ -139,33 +139,50 @@ def _score_card_mask(
139
  def suggest_card_seeds(
140
  hand_mask: np.ndarray,
141
  image_shape: Tuple[int, int],
142
- anchor_xy: Tuple[int, int],
143
  ) -> Dict[str, List[Tuple[int, int]]]:
144
- """Cross-shaped seed points through the anchor (middle-finger PIP).
145
 
146
- Users place the credit card either above/below or left/right of the
147
- middle-finger PIP, so a rake along the horizontal and vertical lines
148
- through PIP catches it with far fewer prompts than a dense grid.
149
- 5 points per arm (step 0.15·dim), shared center deduped.
 
 
 
150
 
151
- Returns a dict with two lists:
152
- - "kept": seeds that passed the hand-mask filter (sent to SAM).
153
- - "dropped": seeds whose (x, y) landed inside the hand mask and
154
- were filtered out. Retained purely for debug visualization.
 
 
 
 
 
 
 
155
  """
156
  h, w = image_shape
157
  mask_bool = hand_mask.astype(bool) if hand_mask.dtype != bool else hand_mask
158
 
159
- ax = int(round(anchor_xy[0]))
160
- ay = int(round(anchor_xy[1]))
161
- dx = int(round(0.15 * w))
162
- dy = int(round(0.15 * h))
 
 
 
163
 
 
164
  candidates: List[Tuple[int, int]] = []
165
- for k in (-2, -1, 0, 1, 2):
166
- candidates.append((ax + k * dx, ay))
167
- for k in (-2, -1, 1, 2):
168
- candidates.append((ax, ay + k * dy))
 
 
 
169
 
170
  kept: List[Tuple[int, int]] = []
171
  dropped: List[Tuple[int, int]] = []
 
139
  def suggest_card_seeds(
140
  hand_mask: np.ndarray,
141
  image_shape: Tuple[int, int],
142
+ y_limit: int,
143
  ) -> Dict[str, List[Tuple[int, int]]]:
144
+ """Uniform 4x4 grid seeds in the top band of the canonical image.
145
 
146
+ In canonical orientation the fingertips point up, so the middle-finger
147
+ MCP is the lowest landmark of the middle finger. Users overwhelmingly
148
+ place the card in the band between the top of the frame and the MCP
149
+ row (beside or above the fingers), so sampling that band catches the
150
+ card with a handful of prompts. The grid excludes a 10% border padding
151
+ on all four sides of the band and drops any seed that lands on the
152
+ hand mask.
153
 
154
+ Args:
155
+ hand_mask: SAM hand mask (HxW, bool or uint8).
156
+ image_shape: (H, W) of the canonical image.
157
+ y_limit: Y coordinate of the middle-finger MCP; the grid spans
158
+ [0.1·H, y_limit] vertically.
159
+
160
+ Returns:
161
+ Dict with two lists:
162
+ - "kept": seeds that passed the hand-mask filter (sent to SAM).
163
+ - "dropped": seeds whose (x, y) landed inside the hand mask and
164
+ were filtered out. Retained purely for debug visualization.
165
  """
166
  h, w = image_shape
167
  mask_bool = hand_mask.astype(bool) if hand_mask.dtype != bool else hand_mask
168
 
169
+ x_min = 0.1 * w
170
+ x_max = 0.9 * w
171
+ y_min = 0.1 * h
172
+ y_max = float(y_limit)
173
+ # Guard against degenerate bands (e.g., MCP above the 10% top padding).
174
+ if y_max <= y_min:
175
+ y_max = y_min + 1.0
176
 
177
+ n = 4
178
  candidates: List[Tuple[int, int]] = []
179
+ for iy in range(n):
180
+ fy = (iy + 0.5) / n
181
+ py = int(round(y_min + fy * (y_max - y_min)))
182
+ for ix in range(n):
183
+ fx = (ix + 0.5) / n
184
+ px = int(round(x_min + fx * (x_max - x_min)))
185
+ candidates.append((px, py))
186
 
187
  kept: List[Tuple[int, int]] = []
188
  dropped: List[Tuple[int, int]] = []