Spaces:
Runtime error
Runtime error
Keep fallback landing center inside safe areas
Browse files- ARCHITECTURE.md +1 -0
- 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 |
-
|
| 344 |
-
if
|
| 345 |
-
|
| 346 |
-
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
cy, cx = cand[0][idx], cand[1][idx]
|
| 354 |
else:
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
if
|
| 362 |
-
|
|
|
|
|
|
|
|
|
|
| 363 |
else:
|
| 364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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]
|