| 12130 | } |
| 12131 | |
| 12132 | sam3_result sam3_propagate_frame( |
| 12133 | sam3_tracker& tracker, sam3_state& state, |
| 12134 | const sam3_model& model, const sam3_image& frame) { |
| 12135 | sam3_result result; |
| 12136 | const int D = model.hparams.neck_dim; |
| 12137 | if (!sam3_encode_image(state, model, frame)) return result; |
| 12138 | int fi = tracker.frame_index; |
| 12139 | fprintf(stderr, "%s: frame %d (%zu active + %zu pending)\n", |
| 12140 | __func__, fi, tracker.masklets.size(), tracker.pending.size()); |
| 12141 | |
| 12142 | // ── Propagate active masklets ──────────────────────────────────────── |
| 12143 | std::map<int, sam3_mask> pm; |
| 12144 | std::map<int, sam3_prop_output> po; |
| 12145 | for (auto& ml : tracker.masklets) { |
| 12146 | int id = ml.instance_id; |
| 12147 | auto im = tracker.mem_banks.find(id); |
| 12148 | if (im == tracker.mem_banks.end() || im->second.empty()) continue; |
| 12149 | po[id] = sam3_propagate_single(tracker, state, model, ml, im->second, tracker.ptr_banks[id]); |
| 12150 | if (po[id].mask_logits.empty()) continue; |
| 12151 | auto rs = sam3_bilinear_interpolate(po[id].mask_logits.data(), |
| 12152 | po[id].mask_w, po[id].mask_h, |
| 12153 | state.orig_width, state.orig_height); |
| 12154 | pm[id].width = state.orig_width; |
| 12155 | pm[id].height = state.orig_height; |
| 12156 | pm[id].data.resize(state.orig_width * state.orig_height); |
| 12157 | int fg = 0; |
| 12158 | for (int p = 0; p < (int)rs.size(); ++p) { |
| 12159 | bool f = rs[p] > 0.0f; |
| 12160 | pm[id].data[p] = f ? 255 : 0; |
| 12161 | if (f) fg++; |
| 12162 | } |
| 12163 | ml.last_score = po[id].iou_scores[0]; |
| 12164 | ml.last_seen = fi; |
| 12165 | float cov = (float)fg / (state.orig_width * state.orig_height); |
| 12166 | ml.mds_sum += (cov > 0.001f && po[id].obj_score > 0.0f) ? 1 : -1; |
| 12167 | } |
| 12168 | |
| 12169 | // ── Propagate pending masklets ─────────────────────────────────────── |
| 12170 | for (auto& ml : tracker.pending) { |
| 12171 | int id = ml.instance_id; |
| 12172 | auto im = tracker.mem_banks.find(id); |
| 12173 | if (im == tracker.mem_banks.end() || im->second.empty()) continue; |
| 12174 | auto p2 = sam3_propagate_single(tracker, state, model, ml, im->second, tracker.ptr_banks[id]); |
| 12175 | if (!p2.mask_logits.empty()) { |
| 12176 | ml.last_score = p2.iou_scores[0]; |
| 12177 | ml.last_seen = fi; |
| 12178 | auto r2 = sam3_bilinear_interpolate(p2.mask_logits.data(), |
| 12179 | p2.mask_w, p2.mask_h, |
| 12180 | state.orig_width, state.orig_height); |
| 12181 | int fg2 = 0; |
| 12182 | for (auto v : r2) |
| 12183 | if (v > 0.0f) fg2++; |
| 12184 | float c2 = (float)fg2 / (state.orig_width * state.orig_height); |
| 12185 | ml.mds_sum += (c2 > 0.001f && p2.obj_score > 0.0f) ? 1 : -1; |
| 12186 | pm[id].width = state.orig_width; |
| 12187 | pm[id].height = state.orig_height; |
| 12188 | pm[id].data.resize(state.orig_width * state.orig_height); |
| 12189 | for (int p = 0; p < (int)r2.size(); ++p) |