| 288 | } |
| 289 | |
| 290 | static void add_instance_from_prompts(vapp_state& app) { |
| 291 | if (!app.tracker_created || !app.frame_encoded) return; |
| 292 | sam3_pvs_params pvs; |
| 293 | pvs.pos_points = app.init_pos_points; |
| 294 | pvs.neg_points = app.init_neg_points; |
| 295 | if (app.has_init_box) { |
| 296 | pvs.box = app.init_box; |
| 297 | pvs.use_box = true; |
| 298 | } |
| 299 | pvs.multimask = false; |
| 300 | |
| 301 | // sam3_tracker_add_instance runs PVS internally and registers the instance |
| 302 | // in the tracker's memory bank. We must NOT call decode_and_track afterwards |
| 303 | // because sam3_track_frame increments tracker.frame_index, which would |
| 304 | // desynchronize the tracker's internal counter from the actual frame. |
| 305 | // |
| 306 | // Instead, run PVS again (cheap — image is already encoded) to obtain a |
| 307 | // display mask and append it to the current result. |
| 308 | int new_id = sam3_tracker_add_instance(*app.tracker, *app.state, *app.model, pvs); |
| 309 | if (new_id >= 0) { |
| 310 | snprintf(app.status, sizeof(app.status), "Added instance #%d", new_id); |
| 311 | |
| 312 | // Re-run PVS to get the mask for display (image features are still valid) |
| 313 | auto pvs_result = sam3_segment_pvs(*app.state, *app.model, pvs); |
| 314 | if (!pvs_result.detections.empty()) { |
| 315 | sam3_detection det = pvs_result.detections[0]; |
| 316 | det.instance_id = new_id; |
| 317 | det.mask.instance_id = new_id; |
| 318 | app.result.detections.push_back(std::move(det)); |
| 319 | } |
| 320 | // Update timeline for current frame |
| 321 | int fi = app.frame_index; |
| 322 | if (fi >= (int)app.timeline.size()) |
| 323 | app.timeline.resize(fi + 1); |
| 324 | app.timeline[fi].instances.clear(); |
| 325 | for (const auto& d : app.result.detections) |
| 326 | app.timeline[fi].instances.push_back({d.instance_id, d.score}); |
| 327 | if (fi > app.timeline_max_frame) app.timeline_max_frame = fi; |
| 328 | } else { |
| 329 | snprintf(app.status, sizeof(app.status), "Failed to add instance"); |
| 330 | } |
| 331 | |
| 332 | // Clear pending prompts |
| 333 | app.init_pos_points.clear(); |
| 334 | app.init_neg_points.clear(); |
| 335 | app.init_box = {0, 0, 0, 0}; |
| 336 | app.has_init_box = false; |
| 337 | } |
| 338 | |
| 339 | static void clear_init_prompts(vapp_state& app) { |
| 340 | app.init_pos_points.clear(); |
no test coverage detected