feat: add simulation for LineCrossCounter and WindowIdentityResolver to validate same-person deduplication

This commit is contained in:
2026-05-12 16:29:36 +08:00
parent 454b716f89
commit e2409d4ebe
2 changed files with 70 additions and 22 deletions

View File

@@ -0,0 +1,52 @@
import numpy as np
from people_flow.counting import LineCrossCounter
from people_flow.window_identity import WindowIdentityResolver
def simulate():
# Setup
line = [(0, 5), (10, 5)] # y=5 from x=0 to x=10
resolver = WindowIdentityResolver(similarity_threshold=0.9)
counter = LineCrossCounter(counting_lines=[line], window_identity_resolver=resolver)
# Constant visual signature (color frame)
dummy_frame = np.zeros((100, 100, 3), dtype=np.uint8)
dummy_frame[40:60, 40:60] = [255, 0, 0] # Add some color to ensure signature is not just zeros
# LineCrossCounter.update(track_id, center_xy, frame)
# Track 1: y=2 -> y=8
track1_id = 1
counter.update(track1_id, (5, 2), dummy_frame)
keys_at_start = list(counter.track_to_identity.values())
counter.update(track1_id, (5, 8), dummy_frame)
events1 = counter.new_events
# Simulate first track disappearing (resolver handles pausing)
# The counter doesn't have an explicit 'disappear' method, but WindowIdentityResolver
# typically handles mapping. Realistically, we just start track 2.
# Track 2: y=2 -> y=8
track2_id = 2
counter.update(track2_id, (5, 2), dummy_frame)
keys_at_second_start = list(counter.track_to_identity.values())
counter.update(track2_id, (5, 8), dummy_frame)
events2 = counter.new_events
# Results
print(f"first_keys: {keys_at_start}")
print(f"second_keys: {keys_at_second_start}")
print(f"first_events: {events1}")
print(f"second_events: {events2}")
print(f"total_people: {counter.total_people()}")
print(f"crossings: {len(events1) + len(events2)}")
payload = {
"total_people": counter.total_people(),
"tracks": list(counter.track_to_identity.keys())
}
print(f"payload: {payload}")
if __name__ == '__main__':
simulate()