yakvrz commited on
Commit
d1989ae
·
1 Parent(s): d41f5d8

Keep fallback landing center inside safe areas

Browse files
Files changed (2) hide show
  1. ARCHITECTURE.md +1 -0
  2. app/safety.py +33 -18
ARCHITECTURE.md CHANGED
@@ -38,6 +38,7 @@ This document describes the flow in the current Gradio app (`app/ui.py`), from i
38
  - Drop small components (< footprint area).
39
  8. **Center selection**:
40
  - Prefer centers where full-footprint coverage exists; choose the largest component and rank by distance transform minus flatness penalty (`openness_weight`).
 
41
  - Fallbacks: landing mask with segmentation removed; if empty, use the flattest patch center.
42
  - Convert depth center to image space; footprint box is scaled to image pixels and clamped to a minimum of 3 px.
43
  9. **Visualization layers**:
 
38
  - Drop small components (< footprint area).
39
  8. **Center selection**:
40
  - Prefer centers where full-footprint coverage exists; choose the largest component and rank by distance transform minus flatness penalty (`openness_weight`).
41
+ - If no full coverage but safe pixels exist, pick the safest point inside the safe mask (distance vs. flatness).
42
  - Fallbacks: landing mask with segmentation removed; if empty, use the flattest patch center.
43
  - Convert depth center to image space; footprint box is scaled to image pixels and clamped to a minimum of 3 px.
44
  9. **Visualization layers**:
app/safety.py CHANGED
@@ -340,28 +340,43 @@ class SafetyAnalyzer:
340
  idx = int(np.argmin(std_cand))
341
  cy, cx = cand[0][idx], cand[1][idx]
342
  else:
343
- fallback_mask = landing_mask.copy()
344
- if not fallback_mask.any():
345
- fallback_mask = np.ones_like(landing_mask, dtype=bool)
346
- if seg_block_mask is not None:
347
- fallback_mask &= (~seg_block_mask)
348
- fallback_mask &= interior_mask
349
- if fallback_mask.any():
350
- cand = np.where(fallback_mask)
351
  std_cand = std_map[cand]
352
- idx = int(np.argmin(std_cand))
 
 
 
 
 
 
 
353
  cy, cx = cand[0][idx], cand[1][idx]
354
  else:
355
- y0, x0, y1, x1 = box[1], box[0], box[3], box[2]
356
- cy, cx = (y0 + y1) // 2, (x0 + x1) // 2
357
- if half_span > 0 and depth.shape[0] > 2 * half_span:
358
- cy = min(max(int(cy), half_span), depth.shape[0] - half_span - 1)
359
- else:
360
- cy = min(max(int(cy), 0), depth.shape[0] - 1)
361
- if half_span > 0 and depth.shape[1] > 2 * half_span:
362
- cx = min(max(int(cx), half_span), depth.shape[1] - half_span - 1)
 
 
 
363
  else:
364
- cx = min(max(int(cx), 0), depth.shape[1] - 1)
 
 
 
 
 
 
 
 
 
365
 
366
  scale_x = image.width / depth.shape[1]
367
  scale_y = image.height / depth.shape[0]
 
340
  idx = int(np.argmin(std_cand))
341
  cy, cx = cand[0][idx], cand[1][idx]
342
  else:
343
+ # Fall back to safest pixel inside any safe region (even if full coverage fails)
344
+ if safe_mask.any():
345
+ cand = np.where(safe_mask)
346
+ dist_cand = distance[cand]
 
 
 
 
347
  std_cand = std_map[cand]
348
+ if dist_cand.size:
349
+ dist_norm = dist_cand / (dist_cand.max() + 1e-6)
350
+ std_norm = (std_cand - std_cand.min()) / (np.ptp(std_cand) + 1e-6)
351
+ weight = max(0.0, min(1.0, request.openness_weight))
352
+ score = dist_norm - weight * std_norm
353
+ idx = int(np.argmax(score))
354
+ else:
355
+ idx = int(np.argmin(std_cand))
356
  cy, cx = cand[0][idx], cand[1][idx]
357
  else:
358
+ fallback_mask = landing_mask.copy()
359
+ if not fallback_mask.any():
360
+ fallback_mask = np.ones_like(landing_mask, dtype=bool)
361
+ if seg_block_mask is not None:
362
+ fallback_mask &= (~seg_block_mask)
363
+ fallback_mask &= interior_mask
364
+ if fallback_mask.any():
365
+ cand = np.where(fallback_mask)
366
+ std_cand = std_map[cand]
367
+ idx = int(np.argmin(std_cand))
368
+ cy, cx = cand[0][idx], cand[1][idx]
369
  else:
370
+ y0, x0, y1, x1 = box[1], box[0], box[3], box[2]
371
+ cy, cx = (y0 + y1) // 2, (x0 + x1) // 2
372
+ if half_span > 0 and depth.shape[0] > 2 * half_span:
373
+ cy = min(max(int(cy), half_span), depth.shape[0] - half_span - 1)
374
+ else:
375
+ cy = min(max(int(cy), 0), depth.shape[0] - 1)
376
+ if half_span > 0 and depth.shape[1] > 2 * half_span:
377
+ cx = min(max(int(cx), half_span), depth.shape[1] - half_span - 1)
378
+ else:
379
+ cx = min(max(int(cx), 0), depth.shape[1] - 1)
380
 
381
  scale_x = image.width / depth.shape[1]
382
  scale_y = image.height / depth.shape[0]