| 11748 | } |
| 11749 | |
| 11750 | sam3_result sam3_track_frame(sam3_tracker& tracker, sam3_state& state, |
| 11751 | const sam3_model& model, const sam3_image& frame) { |
| 11752 | if (model.hparams.visual_only) { |
| 11753 | fprintf(stderr, "%s: ERROR: track_frame not available on visual-only model " |
| 11754 | "(use sam3_propagate_frame instead)\n", __func__); |
| 11755 | return sam3_result{}; |
| 11756 | } |
| 11757 | |
| 11758 | sam3_result result; |
| 11759 | const int D = model.hparams.neck_dim; |
| 11760 | if (!sam3_encode_image(state, model, frame)) return result; |
| 11761 | int fi = tracker.frame_index; |
| 11762 | fprintf(stderr, "%s: frame %d (%zu active + %zu pending)\n", |
| 11763 | __func__, fi, tracker.masklets.size(), tracker.pending.size()); |
| 11764 | |
| 11765 | std::map<int, sam3_mask> pm; |
| 11766 | std::map<int, sam3_prop_output> po; |
| 11767 | for (auto& ml : tracker.masklets) { |
| 11768 | int id = ml.instance_id; |
| 11769 | auto im = tracker.mem_banks.find(id); |
| 11770 | if (im == tracker.mem_banks.end() || im->second.empty()) continue; |
| 11771 | po[id] = sam3_propagate_single(tracker, state, model, ml, im->second, tracker.ptr_banks[id]); |
| 11772 | if (po[id].mask_logits.empty()) continue; |
| 11773 | auto rs = sam3_bilinear_interpolate(po[id].mask_logits.data(), |
| 11774 | po[id].mask_w, po[id].mask_h, state.orig_width, state.orig_height); |
| 11775 | pm[id].width = state.orig_width; |
| 11776 | pm[id].height = state.orig_height; |
| 11777 | pm[id].data.resize(state.orig_width * state.orig_height); |
| 11778 | int fg = 0; |
| 11779 | for (int p = 0; p < (int)rs.size(); ++p) { |
| 11780 | bool f = rs[p] > 0.0f; |
| 11781 | pm[id].data[p] = f ? 255 : 0; |
| 11782 | if (f) fg++; |
| 11783 | } |
| 11784 | ml.last_score = po[id].iou_scores[0]; |
| 11785 | ml.last_seen = fi; |
| 11786 | float cov = (float)fg / (state.orig_width * state.orig_height); |
| 11787 | ml.mds_sum += (cov > 0.001f && po[id].obj_score > 0.0f) ? 1 : -1; |
| 11788 | } |
| 11789 | for (auto& ml : tracker.pending) { |
| 11790 | int id = ml.instance_id; |
| 11791 | auto im = tracker.mem_banks.find(id); |
| 11792 | if (im == tracker.mem_banks.end() || im->second.empty()) continue; |
| 11793 | auto p2 = sam3_propagate_single(tracker, state, model, ml, im->second, tracker.ptr_banks[id]); |
| 11794 | if (!p2.mask_logits.empty()) { |
| 11795 | ml.last_score = p2.iou_scores[0]; |
| 11796 | ml.last_seen = fi; |
| 11797 | auto r2 = sam3_bilinear_interpolate(p2.mask_logits.data(), |
| 11798 | p2.mask_w, p2.mask_h, state.orig_width, state.orig_height); |
| 11799 | int fg2 = 0; |
| 11800 | for (auto v : r2) |
| 11801 | if (v > 0.0f) fg2++; |
| 11802 | float c2 = (float)fg2 / (state.orig_width * state.orig_height); |
| 11803 | ml.mds_sum += (c2 > 0.001f && p2.obj_score > 0.0f) ? 1 : -1; |
| 11804 | sam3_encode_memory(tracker, state, model, id, |
| 11805 | p2.mask_logits.data(), p2.mask_h, p2.mask_w, fi, false, p2.obj_score); |
| 11806 | std::vector<float> op(D); |
| 11807 | sam3_extract_obj_ptr_cpu(model, p2.sam_token.data(), p2.obj_score, op.data()); |