如果新的raw id和旧的sid特别像,优先不创建,可能是track错误

This commit is contained in:
hjy
2026-04-20 16:11:50 +08:00
parent 06bf6ee43e
commit efb46ec8b4
2 changed files with 59 additions and 1 deletions
+1 -1
View File
@@ -124,7 +124,7 @@ register_keys:
target_reid_gap_threshold: 0.10
target_reid_min_crop_area: 2000.0
target_reid_max_crop_aspect_ratio: 0.90
target_reid_feature_update_interval: 5
target_reid_feature_update_interval: 3
target_reid_lost_timeout_frames: 150
target_reid_gallery_size: 8
target_reid_input_height: 256
+58
View File
@@ -748,6 +748,7 @@ std::vector<int> TargetObservationProcessor::bind_and_update_tracks(
// Only brand-new unmatched rows go through the consecutive-hit gate in
// Phase 4 before receiving a fresh stable_id.
bool reid_recovery_attempted = false;
std::vector<bool> suppress_new_sid(static_cast<size_t>(row_count), false);
for (int i = 0; i < row_count; ++i) {
if (stable_ids[static_cast<size_t>(i)] >= 0) {
continue;
@@ -855,6 +856,60 @@ std::vector<int> TargetObservationProcessor::bind_and_update_tracks(
}
}
// Phase 3.75: duplicate suppression. If an unbound row strongly matches
// an already claimed stable_id, treat it as a duplicate ByteTrack split
// of an existing person instead of allocating a new stable_id.
//
// Typical failure mode:
// raw 1 -> sid0, raw 2 -> sid1, then ByteTrack temporarily emits raw 3
// for the same person as sid0 while raw 1 is still alive.
// Without this guard, raw 3 would stay unbound, accumulate pending hits,
// and eventually get promoted to a brand-new sid2 even though its ReID
// is almost identical to sid0. Here we suppress that path.
for (int i = 0; i < row_count; ++i) {
if (stable_ids[static_cast<size_t>(i)] >= 0) {
continue;
}
const ReIDFeature& feature = features_by_row[static_cast<size_t>(i)];
if (feature.empty()) {
continue;
}
int best_sid = -1;
float top1 = -1.0f;
float top2 = -1.0f;
for (const auto& kv : tracks_) {
if (kv.second.gallery.empty()) {
continue;
}
const float sim = kv.second.gallery.best_similarity(feature);
if (sim > top1) {
top2 = top1;
top1 = sim;
best_sid = kv.first;
} else if (sim > top2) {
top2 = sim;
}
}
if (best_sid < 0) {
continue;
}
if (!taken_sids.count(best_sid)) {
continue; // free sids are handled by Phase 3 ReID recovery
}
if (top1 < config_.reid_match_threshold) {
continue;
}
if (top2 >= 0.0f && (top1 - top2) < config_.reid_gap_threshold) {
continue;
}
const int raw_id = static_cast<int>(tracks(i, 4));
pending_raw_ids_.erase(raw_id);
suppress_new_sid[static_cast<size_t>(i)] = true;
}
// Phase 4: allocate a fresh stable_id for rows that still have no match.
// Apply the confirmed-track gate: a ByteTrack raw_id must show up for
// `reid_confirm_hits_before_allocate` consecutive frames before getting
@@ -866,6 +921,9 @@ std::vector<int> TargetObservationProcessor::bind_and_update_tracks(
if (stable_ids[static_cast<size_t>(i)] >= 0) {
continue;
}
if (suppress_new_sid[static_cast<size_t>(i)]) {
continue;
}
const int raw_id = static_cast<int>(tracks(i, 4));
auto [pit, inserted] = pending_raw_ids_.try_emplace(raw_id);
PendingRaw& pending = pit->second;