Spaces:
Sleeping
Sleeping
Zhen Ye Claude Opus 4.6 (1M context) commited on
Commit ·
6a3e49a
1
Parent(s): 61b921a
feat: hide class labels on non-mission-relevant objects in rendered video
Browse filesNon-relevant objects now show only a gray bbox/mask with no label text.
Mission-relevant objects keep their red color and visible class label.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- inference.py +29 -13
inference.py
CHANGED
|
@@ -144,20 +144,27 @@ _COLOR_NOT_RELEVANT = (128, 128, 128) # gray
|
|
| 144 |
def _mission_colors_for_dets(
|
| 145 |
dets: list,
|
| 146 |
verdicts: Dict[str, bool],
|
| 147 |
-
) -> Optional[List[Tuple[int, int, int]]]:
|
| 148 |
-
"""Return per-detection BGR colors based on mission verdicts
|
|
|
|
|
|
|
|
|
|
| 149 |
if not verdicts:
|
| 150 |
-
return None
|
| 151 |
colors = []
|
|
|
|
| 152 |
for d in dets:
|
| 153 |
tid = d.get("track_id")
|
| 154 |
if tid and tid in verdicts:
|
| 155 |
-
|
|
|
|
|
|
|
| 156 |
else:
|
| 157 |
-
# Unassessed — use default hash color
|
| 158 |
label = d.get("label", "obj")
|
| 159 |
colors.append(_color_for_label(label))
|
| 160 |
-
|
|
|
|
| 161 |
|
| 162 |
|
| 163 |
def draw_boxes(
|
|
@@ -167,6 +174,7 @@ def draw_boxes(
|
|
| 167 |
queries: Optional[Sequence[str]] = None,
|
| 168 |
label_names: Optional[Sequence[str]] = None,
|
| 169 |
colors: Optional[Sequence[Tuple[int, int, int]]] = None,
|
|
|
|
| 170 |
) -> np.ndarray:
|
| 171 |
output = frame.copy()
|
| 172 |
if boxes is None:
|
|
@@ -188,7 +196,8 @@ def draw_boxes(
|
|
| 188 |
else:
|
| 189 |
color = (128, 128, 128) if not label else _color_for_label(label)
|
| 190 |
cv2.rectangle(output, (x1, y1), (x2, y2), color, thickness=2)
|
| 191 |
-
|
|
|
|
| 192 |
font = cv2.FONT_HERSHEY_SIMPLEX
|
| 193 |
font_scale = 0.6
|
| 194 |
thickness = 2
|
|
@@ -219,6 +228,7 @@ def draw_masks(
|
|
| 219 |
alpha: float = 0.65,
|
| 220 |
labels: Optional[Sequence[str]] = None,
|
| 221 |
colors: Optional[Sequence[Tuple[int, int, int]]] = None,
|
|
|
|
| 222 |
) -> np.ndarray:
|
| 223 |
output = frame.copy()
|
| 224 |
if masks is None or len(masks) == 0:
|
|
@@ -248,8 +258,9 @@ def draw_masks(
|
|
| 248 |
)
|
| 249 |
if contours:
|
| 250 |
cv2.drawContours(output, contours, -1, color, thickness=2)
|
| 251 |
-
# Only draw label text when explicit labels were provided
|
| 252 |
-
|
|
|
|
| 253 |
coords = np.column_stack(np.where(mask_bool))
|
| 254 |
if coords.size:
|
| 255 |
y, x = coords[0]
|
|
@@ -962,10 +973,11 @@ def run_inference(
|
|
| 962 |
display_labels = [d.get('label', 'obj') for d in dets]
|
| 963 |
# Apply mission-relevance colors (red/gray) if verdicts available
|
| 964 |
det_colors = None
|
|
|
|
| 965 |
if job_id:
|
| 966 |
verdicts = get_job_storage().get_mission_verdicts(job_id)
|
| 967 |
-
det_colors = _mission_colors_for_dets(dets, verdicts)
|
| 968 |
-
p_frame = draw_boxes(p_frame, display_boxes, label_names=display_labels, colors=det_colors)
|
| 969 |
|
| 970 |
writer.write(p_frame)
|
| 971 |
|
|
@@ -1108,6 +1120,7 @@ def _gsam2_render_frame(
|
|
| 1108 |
masks_list: List[np.ndarray] = []
|
| 1109 |
mask_labels: List[str] = []
|
| 1110 |
mask_colors: Optional[List[Tuple[int, int, int]]] = None if not mission_verdicts else []
|
|
|
|
| 1111 |
|
| 1112 |
for obj_id, obj_info in frame_objects.items():
|
| 1113 |
mask = obj_info.mask
|
|
@@ -1128,13 +1141,16 @@ def _gsam2_render_frame(
|
|
| 1128 |
if mask_colors is not None:
|
| 1129 |
tid = str(obj_id)
|
| 1130 |
if tid in mission_verdicts:
|
| 1131 |
-
|
|
|
|
|
|
|
| 1132 |
else:
|
| 1133 |
mask_colors.append(_color_for_label(label or f"object_{obj_id}"))
|
|
|
|
| 1134 |
|
| 1135 |
if masks_list:
|
| 1136 |
# Draw masks with labels — no bboxes for segmentation mode
|
| 1137 |
-
frame = draw_masks(frame, np.stack(masks_list), labels=mask_labels, colors=mask_colors)
|
| 1138 |
|
| 1139 |
return frame
|
| 1140 |
|
|
|
|
| 144 |
def _mission_colors_for_dets(
|
| 145 |
dets: list,
|
| 146 |
verdicts: Dict[str, bool],
|
| 147 |
+
) -> Tuple[Optional[List[Tuple[int, int, int]]], Optional[List[bool]]]:
|
| 148 |
+
"""Return per-detection BGR colors and hide_labels flags based on mission verdicts.
|
| 149 |
+
|
| 150 |
+
Returns (None, None) if no verdicts available yet.
|
| 151 |
+
"""
|
| 152 |
if not verdicts:
|
| 153 |
+
return None, None
|
| 154 |
colors = []
|
| 155 |
+
hide = []
|
| 156 |
for d in dets:
|
| 157 |
tid = d.get("track_id")
|
| 158 |
if tid and tid in verdicts:
|
| 159 |
+
relevant = verdicts[tid]
|
| 160 |
+
colors.append(_COLOR_MISSION_RELEVANT if relevant else _COLOR_NOT_RELEVANT)
|
| 161 |
+
hide.append(not relevant)
|
| 162 |
else:
|
| 163 |
+
# Unassessed — use default hash color, show label
|
| 164 |
label = d.get("label", "obj")
|
| 165 |
colors.append(_color_for_label(label))
|
| 166 |
+
hide.append(False)
|
| 167 |
+
return colors, hide
|
| 168 |
|
| 169 |
|
| 170 |
def draw_boxes(
|
|
|
|
| 174 |
queries: Optional[Sequence[str]] = None,
|
| 175 |
label_names: Optional[Sequence[str]] = None,
|
| 176 |
colors: Optional[Sequence[Tuple[int, int, int]]] = None,
|
| 177 |
+
hide_labels: Optional[Sequence[bool]] = None,
|
| 178 |
) -> np.ndarray:
|
| 179 |
output = frame.copy()
|
| 180 |
if boxes is None:
|
|
|
|
| 196 |
else:
|
| 197 |
color = (128, 128, 128) if not label else _color_for_label(label)
|
| 198 |
cv2.rectangle(output, (x1, y1), (x2, y2), color, thickness=2)
|
| 199 |
+
should_hide = hide_labels is not None and idx < len(hide_labels) and hide_labels[idx]
|
| 200 |
+
if label and not should_hide:
|
| 201 |
font = cv2.FONT_HERSHEY_SIMPLEX
|
| 202 |
font_scale = 0.6
|
| 203 |
thickness = 2
|
|
|
|
| 228 |
alpha: float = 0.65,
|
| 229 |
labels: Optional[Sequence[str]] = None,
|
| 230 |
colors: Optional[Sequence[Tuple[int, int, int]]] = None,
|
| 231 |
+
hide_labels: Optional[Sequence[bool]] = None,
|
| 232 |
) -> np.ndarray:
|
| 233 |
output = frame.copy()
|
| 234 |
if masks is None or len(masks) == 0:
|
|
|
|
| 258 |
)
|
| 259 |
if contours:
|
| 260 |
cv2.drawContours(output, contours, -1, color, thickness=2)
|
| 261 |
+
# Only draw label text when explicit labels were provided and not hidden
|
| 262 |
+
should_hide = hide_labels is not None and idx < len(hide_labels) and hide_labels[idx]
|
| 263 |
+
if label and not should_hide:
|
| 264 |
coords = np.column_stack(np.where(mask_bool))
|
| 265 |
if coords.size:
|
| 266 |
y, x = coords[0]
|
|
|
|
| 973 |
display_labels = [d.get('label', 'obj') for d in dets]
|
| 974 |
# Apply mission-relevance colors (red/gray) if verdicts available
|
| 975 |
det_colors = None
|
| 976 |
+
det_hide = None
|
| 977 |
if job_id:
|
| 978 |
verdicts = get_job_storage().get_mission_verdicts(job_id)
|
| 979 |
+
det_colors, det_hide = _mission_colors_for_dets(dets, verdicts)
|
| 980 |
+
p_frame = draw_boxes(p_frame, display_boxes, label_names=display_labels, colors=det_colors, hide_labels=det_hide)
|
| 981 |
|
| 982 |
writer.write(p_frame)
|
| 983 |
|
|
|
|
| 1120 |
masks_list: List[np.ndarray] = []
|
| 1121 |
mask_labels: List[str] = []
|
| 1122 |
mask_colors: Optional[List[Tuple[int, int, int]]] = None if not mission_verdicts else []
|
| 1123 |
+
mask_hide: Optional[List[bool]] = None if not mission_verdicts else []
|
| 1124 |
|
| 1125 |
for obj_id, obj_info in frame_objects.items():
|
| 1126 |
mask = obj_info.mask
|
|
|
|
| 1141 |
if mask_colors is not None:
|
| 1142 |
tid = str(obj_id)
|
| 1143 |
if tid in mission_verdicts:
|
| 1144 |
+
relevant = mission_verdicts[tid]
|
| 1145 |
+
mask_colors.append(_COLOR_MISSION_RELEVANT if relevant else _COLOR_NOT_RELEVANT)
|
| 1146 |
+
mask_hide.append(not relevant)
|
| 1147 |
else:
|
| 1148 |
mask_colors.append(_color_for_label(label or f"object_{obj_id}"))
|
| 1149 |
+
mask_hide.append(False)
|
| 1150 |
|
| 1151 |
if masks_list:
|
| 1152 |
# Draw masks with labels — no bboxes for segmentation mode
|
| 1153 |
+
frame = draw_masks(frame, np.stack(masks_list), labels=mask_labels, colors=mask_colors, hide_labels=mask_hide)
|
| 1154 |
|
| 1155 |
return frame
|
| 1156 |
|