File size: 2,015 Bytes
d9ebe88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
"""
Lightweight speed estimation using pixel displacement between frames.

No camera calibration required — classifies vehicles into relative
speed categories (Slow/Normal/Fast) based on percentile ranking
of pixel-per-frame displacement within the video.
"""
import numpy as np


def estimate_speeds(track_positions):
    """Compute per-track speed category from centroid displacement history.

    Args:
        track_positions: dict {track_id: [(frame_idx, cx, cy), ...]}

    Returns:
        dict with per_track speeds and aggregate distribution
    """
    displacements = {}

    for tid, positions in track_positions.items():
        if len(positions) < 2:
            continue
        positions.sort(key=lambda x: x[0])
        total_disp = 0.0
        count = 0
        for i in range(1, len(positions)):
            dx = positions[i][1] - positions[i - 1][1]
            dy = positions[i][2] - positions[i - 1][2]
            total_disp += np.sqrt(dx * dx + dy * dy)
            count += 1
        displacements[tid] = total_disp / count if count > 0 else 0.0

    if not displacements:
        return {"per_track": {}, "distribution": {"slow": 0, "normal": 0, "fast": 0}}

    speeds = np.array(list(displacements.values()))
    p33 = np.percentile(speeds, 33)
    p66 = np.percentile(speeds, 66)

    per_track = {}
    counts = {"slow": 0, "normal": 0, "fast": 0}

    for tid, spd in displacements.items():
        if spd <= p33:
            cat = "slow"
        elif spd <= p66:
            cat = "normal"
        else:
            cat = "fast"
        per_track[int(tid)] = {"px_per_frame": round(spd, 1), "category": cat}
        counts[cat] += 1

    total = sum(counts.values())
    distribution = {
        "slow": round(counts["slow"] / total * 100, 1) if total else 0,
        "normal": round(counts["normal"] / total * 100, 1) if total else 0,
        "fast": round(counts["fast"] / total * 100, 1) if total else 0,
    }

    return {"per_track": per_track, "distribution": distribution}