-
Notifications
You must be signed in to change notification settings - Fork 61
fix: batch 1 fixes - various improvements #204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,122 +122,108 @@ def update( | |
| continue | ||
|
|
||
| tid = int(t.track_id) | ||
| # ── ReID matching ───────────────────────────────────── | ||
| # ── ReID matching ───────────────────────────────────── | ||
| if hasattr(t, "features") and t.features: | ||
|
|
||
| new_embedding = t.features[-1] | ||
|
|
||
| for lost_id, data in list(self._lost_embeddings.items()): | ||
|
|
||
| age = self._frame_id - data["last_seen"] | ||
|
|
||
| if age > self.max_age: | ||
| continue | ||
|
|
||
| similarity = self._cosine_similarity( | ||
| new_embedding, | ||
| data["embedding"], | ||
| # ── ReID matching ───────────────────────────────────── | ||
| if hasattr(t, "features") and t.features: | ||
| new_embedding = t.features[-1] | ||
| for lost_id, data in list(self._lost_embeddings.items()): | ||
| age = self._frame_id - data["last_seen"] | ||
| if age > self.max_age: | ||
| continue | ||
| similarity = self._cosine_similarity( | ||
| new_embedding, | ||
| data["embedding"], | ||
| ) | ||
| if similarity > self.REID_SIMILARITY_THRESHOLD: | ||
| tid = lost_id | ||
| t.track_id = lost_id | ||
| del self._lost_embeddings[lost_id] | ||
| logger.info(f"ReID matched: restored track #{lost_id}") | ||
| break | ||
|
|
||
| ltwh = t.to_ltwh() | ||
| x1 = float(ltwh[0]) | ||
| y1 = float(ltwh[1]) | ||
| x2 = x1 + float(ltwh[2]) | ||
| y2 = y1 + float(ltwh[3]) | ||
| cx, cy = (x1 + x2) / 2, (y1 + y2) / 2 | ||
|
|
||
| zones = [z.name for z in get_zones_for_point(cx, cy)] | ||
|
|
||
| # ── Lifecycle: BORN ─────────────────────────────────────────── | ||
| if tid not in self._known_ids: | ||
| self._known_ids.add(tid) | ||
| self._emit_lifecycle(TrackState.BORN, tid, zones, 0.0) | ||
| logger.info(f"Track BORN: #{tid} in zones={zones}") | ||
|
|
||
| # ── Dwell time ──────────────────────────────────────────────── | ||
| prev = self._active_tracks.get(tid) | ||
| dwell_frames = (prev.dwell_time_frames + 1) if prev else 1 | ||
| dwell_secs = dwell_frames / self.fps | ||
|
|
||
| # ── Trajectory ──────────────────────────────────────────────── | ||
| prev_traj = prev.trajectory if prev else [] | ||
| new_point = TrajectoryPoint(x=cx, y=cy, frame_id=self._frame_id) | ||
| trajectory = (prev_traj + [new_point])[-self.MAX_TRAJECTORY_LEN:] | ||
|
|
||
| obj = TrackedObject( | ||
| track_id = tid, | ||
| label = "person", | ||
| bbox = [x1, y1, x2, y2], | ||
| confidence = float(t.det_conf or 0.0), | ||
| center = (cx, cy), | ||
| dwell_time_frames = dwell_frames, | ||
| dwell_time_seconds = round(dwell_secs, 2), | ||
| state = TrackState.ACTIVE, | ||
| trajectory = trajectory, | ||
| zones_present = zones, | ||
| last_seen_frame = self._frame_id, | ||
| ) | ||
|
|
||
| if similarity > self.REID_SIMILARITY_THRESHOLD: | ||
|
|
||
| # Restore original ID | ||
| tid = lost_id | ||
| t.track_id = lost_id | ||
|
|
||
| del self._lost_embeddings[lost_id] | ||
|
|
||
| logger.info( | ||
| f"ReID matched: restored track #{lost_id}" | ||
| ) | ||
|
|
||
| break | ||
|
|
||
| ltwh = t.to_ltwh() | ||
| x1 = float(ltwh[0]) | ||
| y1 = float(ltwh[1]) | ||
| x2 = x1 + float(ltwh[2]) | ||
| y2 = y1 + float(ltwh[3]) | ||
| cx, cy = (x1 + x2) / 2, (y1 + y2) / 2 | ||
|
|
||
| zones = [z.name for z in get_zones_for_point(cx, cy)] | ||
|
|
||
| # ── Lifecycle: BORN ─────────────────────────────────────────── | ||
| if tid not in self._known_ids: | ||
| self._known_ids.add(tid) | ||
| self._emit_lifecycle(TrackState.BORN, tid, zones, 0.0) | ||
| logger.info(f"Track BORN: #{tid} in zones={zones}") | ||
|
|
||
| # ── Dwell time ──────────────────────────────────────────────── | ||
| prev = self._active_tracks.get(tid) | ||
| dwell_frames = (prev.dwell_time_frames + 1) if prev else 1 | ||
| dwell_secs = dwell_frames / self.fps | ||
|
|
||
| # ── Trajectory ──────────────────────────────────────────────── | ||
| prev_traj = prev.trajectory if prev else [] | ||
| new_point = TrajectoryPoint(x=cx, y=cy, frame_id=self._frame_id) | ||
| trajectory = (prev_traj + [new_point])[-self.MAX_TRAJECTORY_LEN:] | ||
|
|
||
| obj = TrackedObject( | ||
| track_id = tid, | ||
| label = "person", | ||
| bbox = [x1, y1, x2, y2], | ||
| confidence = float(t.det_conf or 0.0), | ||
| center = (cx, cy), | ||
| dwell_time_frames = dwell_frames, | ||
| dwell_time_seconds = round(dwell_secs, 2), | ||
| state = TrackState.ACTIVE, | ||
| trajectory = trajectory, | ||
| zones_present = zones, | ||
| last_seen_frame = self._frame_id, | ||
| ) | ||
| self._active_tracks[tid] = obj | ||
| current_ids.add(tid) | ||
| tracked_objects.append(obj) | ||
|
|
||
| # ── Lifecycle: LOST for tracks that disappeared ──────────────────── | ||
| for tid, prev_obj in list(self._active_tracks.items()): | ||
| if tid not in current_ids: | ||
| frames_since = self._frame_id - prev_obj.last_seen_frame | ||
| if frames_since == 1: | ||
| track = next((t for t in raw_tracks if int(t.track_id) == tid), None) | ||
|
|
||
| if track is not None and hasattr(track, "features") and track.features: | ||
| self._lost_embeddings[tid] = { | ||
| "embedding": track.features[-1], | ||
| "last_seen": self._frame_id, | ||
| self._active_tracks[tid] = obj | ||
| current_ids.add(tid) | ||
| tracked_objects.append(obj) | ||
|
|
||
| # ── Lifecycle: LOST for tracks that disappeared ──────────────────── | ||
| for tid, prev_obj in list(self._active_tracks.items()): | ||
| if tid not in current_ids: | ||
| frames_since = self._frame_id - prev_obj.last_seen_frame | ||
| track = next((t for t in raw_tracks if int(t.track_id) == tid), None) if frames_since == 1 else None | ||
|
|
||
| if track is not None and hasattr(track, "features") and track.features: | ||
| self._lost_embeddings[tid] = { | ||
| "embedding": track.features[-1], | ||
| "last_seen": self._frame_id, | ||
| } | ||
|
Comment on lines
+186
to
196
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
# Inspect the repository's declared DeepSort version and existing Track API usage.
rg -n -C2 'deep-sort|deep_sort|deep-sort-realtime' \
--glob 'pyproject.toml' --glob 'requirements*.txt' --glob 'poetry.lock' --glob 'uv.lock' .
rg -n -C3 '\b(update_tracks|time_since_update|track_id)\b' services/tracking/tracker.pyRepository: Devnil434/Eagle Length of output: 3057 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo "== tracker.py outline =="
ast-grep outline services/tracking/tracker.py --view compact || true
echo "== tracker.py relevant section =="
sed -n '80,210p' services/tracking/tracker.py
echo "== dependency version/manifest =="
cat services/tracking/requirements.txtRepository: Devnil434/Eagle Length of output: 6229 🌐 Web query:
💡 Result: In the deep-sort-realtime library (including version 1.3.2), Citations:
🌐 Web query:
💡 Result: In the deep_sort_realtime library, the status and lifecycle of tracked objects are managed through the Track class and the update process [1][2]. While filter_confirmed and time_since_update are key internal attributes used to manage track state, they are typically accessed via helper methods rather than direct parameters in the update_tracks function [1][2]. 1. filter_confirmed (is_confirmed): Tracks are initialized as tentative and must achieve a certain number of consecutive detections (defined by the n_init parameter during DeepSort initialization) to become confirmed [1][2]. The is_confirmed method is the standard way to check this status [3][2]. It is commonly used in implementation loops to filter out unstable or false-positive detections, for example: if not track.is_confirmed: continue 2. time_since_update: This attribute tracks how many consecutive frames have passed since a track was last matched with a detection [1][4]. It is a critical internal component of the tracker's logic for determining when a track should be marked as missed or deleted [1][4]. When a track's time_since_update exceeds the max_age parameter (set during DeepSort instantiation), the track is typically deleted [1][5]. In summary, users typically do not pass these as arguments to update_tracks. Instead, you interact with them by: - Filtering results using track.is_confirmed to ensure you are only processing stable tracks [3][2]. - Relying on the internal max_age parameter to automatically prune old, unmatched tracks [5]. Citations:
🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo "== deep_sort_realtime installed package files =="
python3 - <<'PY'
import importlib.util, os
spec = importlib.util.find_spec("deep_sort_realtime")
print(f"deep_sort_realtime found: {spec is not None}")
print(f"origin: {spec.origin}")
PY
if python3 - <<'PY'
import importlib.util
print(importlib.util.find_spec("deep_sort_realtime") is not None)
PY
then
python3 - <<'PY'
import deep_sort_realtime.deep_sort as ds
import inspect
print(inspect.getfile(ds))
PY
echo "== deepsortracker source =="
python3 - <<'PY'
import deep_sort_realtime.deep_sort.tracker as tracker_module
print(inspect.getsource(tracker_module.DeepSortTracker))
PY
fi
echo "== local deepsort init in repo =="
rg -n -C4 'DeepSort\(|deep_sort_realtime|tracker' . \
--glob '!**/*.png' '--glob !**/*.lock'Repository: Devnil434/Eagle Length of output: 367 🌐 Web query:
💡 Result: In the levan92/deep_sort_realtime library, the update_tracks method is the primary interface for processing detections and updating the internal state of tracked objects [1][2]. update_tracks This method is called on the DeepSort object to perform both prediction (Kalman filter propagation) and measurement updates (matching detections to tracks) for every frame [3][4]. It accepts a list of detections and returns a list of track objects [1][5]. time_since_update This property represents the number of frames that have passed since a track was last successfully matched with a detection [6]. A value of 0 indicates that the track was matched with a detection in the current frame [6]. is_confirmed This method returns a boolean indicating the lifecycle state of a track [6]. A track is considered confirmed once it has achieved a sufficient number of consecutive hits (initialization matches) as defined by the tracker configuration [6]. Tracks that are not yet confirmed are typically referred to as tentative or provisional [6]. Usage in tracker.py The tracker.py module manages the collection of tracks, performing the matching cascade and updating track states [3]. During iteration over the output of update_tracks, it is standard practice to filter out unconfirmed tracks if you only wish to process objects that have been reliably identified [1][2][6]. Example usage: for track in tracks: if not track.is_confirmed: continue # Process confirmed track track_id = track.track_id ltrb = track.to_ltrb Citations:
🌐 Web query:
💡 Result: In the deep-sort-realtime library, the update_tracks method is the primary API used to process detections and update track states for a given frame [1][2]. While there is a tracker.py file located within the deep_sort/ directory of the repository, this file contains the internal multi-target tracker logic (such as the predict and update methods) used by the library [3]. The end-user API, which is commonly called in implementation scripts, is defined in the DeepSort class within deepsort_tracker.py [4][1]. The update_tracks method in deepsort_tracker.py performs the following high-level operations: 1. Receives raw detections (expected as a list of tuples in ( [left, top, w, h], confidence, detection_class) format) and an optional frame for embedding [1][2]. 2. Optionally computes appearance embeddings for the detections if they are not pre-computed [1][2]. 3. Passes these detections to the internal tracker (the one defined in tracker.py) to perform Kalman filter prediction and data association [3]. 4. Returns a list of active Track objects, which can be queried for information like track IDs and bounding box coordinates [1][2]. For implementation, users typically import and use it as follows: from deep_sort_realtime.deepsort_tracker import DeepSort tracker = DeepSort(max_age=5) tracks = tracker.update_tracks(bbs, frame=frame) Citations:
🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
import tarfile
import urllib.request
url = "https://files.pythonhosted.org/packages/9b/25/aa3e3e1822c010a92c916f1a0e50057667c6b156296a235d65ec36069bb/deep-sort-realtime-1.3.2.tar.gz"
tmp = "/tmp/deep_sort_realtime-1.3.2.tar.gz"
print("Downloading", url)
urllib.request.urlretrieve(url, tmp)
print("Downloaded", tmp)
with tarfile.open(tmp, "r:gz") as tf:
names = [n for n in tf.getnames() if n.endswith(".py")]
for n in names:
if "deepsort" in n or "tracker.py" in n:
print(n)
# Read only the relevant source text.
for n in [
"deep-sort-realtime-1.3.2/deep_sort_realtime/deepsort_tracker.py",
"deep-sort-realtime-1.3.2/deep_sort_realtime/deep_sort/tracker.py",
]:
print("\n==", n, "==")
try:
source = tf.extractfile(n).read().decode("utf-8")
except KeyError:
continue
for needle in ["def update_tracks", "time_since_update", "return self.tracks"]:
try:
idx = source.index(needle)
before = max(0, source.rindex("\n", 0, idx - 1) if idx > 0 else 0)
after = source.index("\n", source.index("\n", idx) + 1 if idx < len(source) - 1 else idx)
window = source[before:after]
except ValueError:
window = None
print(f"*** {needle} ***")
print("\n".join(f"{i+1}: {line}" for i,line in enumerate(window.splitlines(), start=1)))
# Also print methods around update_tracks with line numbers.
lines = source.splitlines()
start, end = None, None
for i,l in enumerate(lines):
if "def update_tracks" in l or "def __init__" in l and start is None:
start = i
if start is not None and i > start and l.startswith((" def ", "class ")):
end = i; break
if start:
if not end: end = min(len(lines), start+120)
print(f"\n== source lines {start+1}-{end} ==")
for i in range(start, end):
print(f"{i+1}: {lines[i]}")
PYRepository: Devnil434/Eagle Length of output: 3072 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
# Pin the dependency, then inspect the exact source text from the PyPI wheel/tarball.
python3 - <<'PY'
import hashlib, tarfile, urllib.request
url = "https://files.pythonhosted.org/packages/9b/25/aa3e3e1822c010a92c916f1a0e50057667c6b156296a235d65ec36069bb/deep-sort-realtime-1.3.2.tar.gz"
dest = "/tmp/deep-sort-realtime-1.3.2.tar.gz"
req = urllib.request.Request(url)
req.add_header("User-Agent", "CodeRabbit-verification")
try:
with urllib.request.urlopen(req, timeout=20, cafile=None) as resp:
data = resp.read()
except Exception as e:
# Fallback to self-signed-cert-aware fetch only if needed; print cause.
print("FALLBACK_FETCH", type(e).__name__, e)
import ssl
ctx = ssl._create_unverified_context()
with urllib.request.urlopen(url, timeout=20, context=ctx) as resp:
data = resp.read()
print("sha256", hashlib.sha256(data).hexdigest())
with open(dest, "wb") as f:
f.write(data)
with tarfile.open(dest, "r:gz") as tf:
for n in [
"deep-sort-realtime-1.3.2/deep_sort_realtime/deepsort_tracker.py",
"deep-sort-realtime-1.3.2/deep_sort_realtime/deep_sort/tracker.py",
]:
print(f"\n===== {n} =====")
try:
src = tf.extractfile(n).read().decode("utf-8")
except KeyError:
print("MISSING")
continue
lines = src.splitlines()
print("total", len(lines))
for keyword in ["def update_tracks", "def __init__", "class DeepSort"]:
print(f"\n--- matches for {keyword} ---")
for i,l in enumerate(lines):
if keyword in l:
start=max(1,i-12); end=min(len(lines),i+50)
for j in range(start,end+1):
print(f"{j}: {lines[j-1]}")
print("\n===== exact update_tracks substring (with context) =====")
with tarfile.open(dest, "r:gz") as tf:
try:
src = tf.extractfile("deep-sort-realtime-1.3.2/deep_sort_realtime/deepsort_tracker.py").read().decode("utf-8")
except KeyError:
raise SystemExit
for needle in ["def update_tracks"]:
idx = src.index(needle)
start = src.rfind("\n", 0, idx)
end = src.index("\n", src.index("\n", idx) + 1) if idx < len(src)-1 else len(src)
print(f"--- {needle} ---")
print(src[start:end])
print("--- line count of this class block ---")
lines = src[start:end+1].splitlines()
print(len(lines))
print("\n".join(f"{i+1}: {lines[i]}" for i in range(len(lines))))
PYRepository: Devnil434/Eagle Length of output: 3928 🌐 Web query:
💡 Result: The Citations:
🌐 Web query:
💡 Result: The file deepsort_tracker.py is a core component of the deep-sort-realtime library, a Python package maintained by levan92 that provides a real-time adaptation of the Deep SORT multi-object tracking algorithm [1][2]. Key information regarding this file and library: Purpose: The deep-sort-realtime library is designed to facilitate real-time object tracking by integrating directly with object detection outputs [2][3]. It improves upon the original academic implementation of Deep SORT by optimizing it for real-time processing and providing flexible options for appearance feature extraction (embeddings) [2][3]. Role of deepsort_tracker.py: This file contains the DeepSort class, which is the primary interface for users [4][5]. When a user initializes the tracker or calls its update_tracks method, they are interacting with the logic defined in this file [5]. Key Features: - Multiple Embedder Options: The library supports various appearance embedders, including built-in MobileNet, CLIP, and TorchReID models [2][3][6]. - Flexible Input: It accepts raw detection data (typically [left, top, width, height] bounding boxes, confidence, and detection class) and a frame for processing [7][5]. - Hyperparameter Tuning: Users can adjust parameters such as max_age, max_iou_distance, and nms_max_overlap directly through the DeepSort constructor in deepsort_tracker.py to suit specific use cases [4][5]. - Real-time Optimization: The implementation includes optimizations like skipping non-maximum suppression (NMS) when unnecessary and allowing for pre-computed embeddings to reduce latency [2][3]. Installation and Usage: The library is available on PyPI and can be installed via pip [1][3]: pip install deep-sort-realtime Example usage typically involves initializing the tracker, obtaining detections from a model (e.g., YOLO), and updating the tracker with those detections [8][5]. For further technical details, including the specific implementations of Kalman filtering, linear assignment, and matching metrics used by the tracker, the library's source code documentation and the original Deep SORT paper (Wojke et al.) are recommended as primary references [2][3]. Citations:
🌐 Web query:
💡 Result: The Citations:
🌐 Web query:
💡 Result: I couldn’t find an indexed result for that exact raw GitHub path/snippet. The repo If you want, I can help you construct the exact raw file URL or locate the line in the repo. Citations: 🌐 Web query:
💡 Result:
If you want, I can also try to pull the exact raw GitHub line for Citations: 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo "== repository DeepSort construction =="
rg -n -C4 'DeepSort\(' .
echo "== exact tracker implementation from PyPI via wheel lookup =="
python3 - <<'PY'
import tarfile, textwrap, xml.etree.ElementTree as ET, urllib.request
metadata_url = "https://files.pythonhosted.org/packages/9b/25/aa3e3e1822c010a92c916f1a0e50057667c6b156296a235d65ec36069bb/deep-sort-realtime-1.3.2.tar.gz.metadata"
try:
req = urllib.request.Request(metadata_url)
req.add_header("User-Agent", "CodeRabbit-verification")
metadata = urllib.request.urlopen(req, timeout=20).read().decode("utf-8")
print(metadata)
except Exception as e:
print("metadata fetch failed", e)
pypi_repo = "https://pypi.org/pypi/deep-sort-realtime/json"
try:
data = ET.XML(urllib.request.urlopen(pypi_repo, timeout=20).read()).attrib
except Exception as e:
data = None
print("\n== release urls (sample) ==")
import xml.etree.ElementTree as ET
try:
root = ET.XML(urllib.request.urlopen(pypi_repo, timeout=20).read())
releases = root.find('releases')
if releases is not None:
for rel in releases.findall('release'):
if rel.attrib.get('name') == 'deep-sort-realtime' and rel.attrib.get('version') == '1.3.2':
for f in rel.findall('file'):
print(f.attrib.get('url'), f.attrib.get('packagetype'), f.attrib.get('filename'))
except Exception as e:
print("release list fetch failed", e)
print("\n== raw github file (no version pin) ==")
try:
data = urllib.request.urlopen(
urllib.request.Request(
"https://raw.githubusercontent.com/levan92/deep-sort-realtime/master/deep_sort_realtime/deepsort_tracker.py",
headers={"User-Agent": "CodeRabbit-verification"},
timeout=20,
),
timeout=20,
).read().decode("utf-8")
lines = data.splitlines()
for i,l in enumerate(lines):
if "def update_tracks" in l or "return self.tracks" in l:
print(f"## {i+1}: {l}")
start=max(0,i-20); end=min(len(lines),i+35)
for j in range(start,end):
print(f"{j+1}: {lines[j]}")
except Exception as e:
print("raw github fetch failed", e)
PYRepository: Devnil434/Eagle Length of output: 1397 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
import ssl, urllib.request
url = "https://raw.githubusercontent.com/levan92/deep-sort-realtime/master/deep_sort_realtime/deepsort_tracker.py"
with urllib.request.urlopen(url, context=ssl._create_unverified_context(), timeout=20) as resp:
src = resp.read().decode("utf-8")
lines = src.splitlines()
print("source length", len(lines))
for mark in ["def update_tracks", "def _update_tracker_with_embeddings", "return self.tracks"]:
print(f"\n--- matches for {mark} ---")
for i,l in enumerate(lines):
if mark in l:
print(f"{i+1}: {l}")
for j in range(max(0,i-25), min(len(lines), i+45)):
print(f"{j+1}: {lines[j]}")
PYRepository: Devnil434/Eagle Length of output: 1105 🌐 Web query:
💡 Result: The release version 1.3.2 of the levan92/deep_sort_realtime repository was published on February 11, 2023 [1][2]. This release introduced several updates to the library, including the addition of background masking functionality, fixes for NumPy deprecations regarding np.float, and the exposure of new arguments in the DeepSort object [1]. Specifically, in the deepsort_tracker.py file, the max_iou_distance argument was exposed to the DeepSort class, and a gating_only_position argument was added to the tracker to allow gating based solely on x and y coordinates rather than the default of x, y, aspect ratio, and height [1][3]. The library is available for installation via PyPI, and source/wheel files for version 1.3.2 can be found on the project's official GitHub releases page [1][2][4]. Citations:
🌐 Web query:
💡 Result: In the levan92/deep_sort_realtime library, particularly around version 1.3.2, the update_tracks method is the primary API call for multi-object tracking [1][2]. It is located within the DeepSort class in deep_sort_realtime/deepsort_tracker.py [3][1]. Usage and Functionality: The update_tracks method processes a new set of detections and the current video frame to update the state of all tracked objects [2]. Signature and Inputs: The standard usage pattern is: tracks = tracker.update_tracks(bbs, frame=frame) [1][2] bbs: A list of detections, where each detection is a tuple containing ([left, top, w, h], confidence, detection_class) [1][2]. frame (optional): A numpy array of shape (Height, Width, Channels) with pixel values in [4]. If provided, the library uses its internal embedder to calculate appearance features [4][2]. If you have pre-computed appearance features, you can pass them via an embeds argument instead, making the frame input unnecessary [5][2]. Advanced Options: Masks: You can pass instance segmentation masks using the masks argument (e.g., masks=[mask]) to be associated with detections [1][2]. Polygon Detection: When using polygon-based detections, the polygon argument should be set to True during DeepSort instantiation [1]. The original coordinates are then passed to the track via supplementary information [1]. Return Value: The method returns a list of active Track objects [2]. You can iterate through these to retrieve information such as track IDs and bounding boxes using methods like track.track_id and track.to_ltrb [1][6][7]. It is recommended to check track.is_confirmed to ensure only stable tracks are processed [4][2]. Citations:
Use stale raw tracks for LOST ReID embedding capture.
🤖 Prompt for AI Agents |
||
|
|
||
| self._emit_lifecycle( | ||
| TrackState.LOST, tid, | ||
| prev_obj.zones_present, | ||
| prev_obj.dwell_time_seconds, | ||
| ) | ||
| if frames_since > self._tracker.max_age: | ||
| self._emit_lifecycle( | ||
| TrackState.LOST, tid, | ||
| TrackState.DEAD, tid, | ||
| prev_obj.zones_present, | ||
| prev_obj.dwell_time_seconds, | ||
| ) | ||
| if frames_since > self._tracker.max_age: | ||
| self._emit_lifecycle( | ||
| TrackState.DEAD, tid, | ||
| prev_obj.zones_present, | ||
| prev_obj.dwell_time_seconds, | ||
| ) | ||
| del self._active_tracks[tid] | ||
| logger.info(f"Track DEAD: #{tid} after {prev_obj.dwell_time_seconds:.1f}s") | ||
| # ── Cleanup expired ReID embeddings ────────────────── | ||
| expired_ids = [ | ||
| tid for tid, data in self._lost_embeddings.items() | ||
| if self._frame_id - data["last_seen"] > self.max_age | ||
| ] | ||
|
|
||
| for tid in expired_ids: | ||
| del self._lost_embeddings[tid] | ||
|
|
||
| return TrackedFrame( | ||
| frame_id = self._frame_id, | ||
| camera_id = self.camera_id, | ||
| tracks = tracked_objects, | ||
| timestamp_ms = time.time() * 1000, | ||
| fps = self.fps, | ||
| ) | ||
| del self._active_tracks[tid] | ||
| logger.info(f"Track DEAD: #{tid} after {prev_obj.dwell_time_seconds:.1f}s") | ||
|
|
||
| # ── Cleanup expired ReID embeddings ────────────────── | ||
| expired_ids = [ | ||
| tid for tid, data in self._lost_embeddings.items() | ||
| if self._frame_id - data["last_seen"] > self.max_age | ||
| ] | ||
| for tid in expired_ids: | ||
| del self._lost_embeddings[tid] | ||
|
|
||
| return TrackedFrame( | ||
| frame_id = self._frame_id, | ||
| camera_id = self.camera_id, | ||
| tracks = tracked_objects, | ||
| timestamp_ms = time.time() * 1000, | ||
| fps = self.fps, | ||
| ) | ||
|
|
||
| def drain_lifecycle_events(self) -> list[TrackLifecycleEvent]: | ||
| """ | ||
|
|
@@ -269,20 +255,20 @@ def _emit_lifecycle( | |
| self._lifecycle_queue.append(event) | ||
| if self._event_logger is not None: | ||
| self._event_logger.log_event(event) | ||
| def _cosine_similarity( | ||
| self, | ||
| a: np.ndarray, | ||
| b: np.ndarray, | ||
| ) -> float: | ||
| def _cosine_similarity( | ||
| self, | ||
| a: np.ndarray, | ||
| b: np.ndarray, | ||
| ) -> float: | ||
|
|
||
| norm_product = np.linalg.norm(a) * np.linalg.norm(b) | ||
| norm_product = np.linalg.norm(a) * np.linalg.norm(b) | ||
|
|
||
| if norm_product == 0: | ||
| return 0.0 | ||
| if norm_product == 0: | ||
| return 0.0 | ||
|
|
||
| return float( | ||
| np.dot(a, b) / norm_product | ||
| ) | ||
| return float( | ||
| np.dot(a, b) / norm_product | ||
| ) | ||
|
|
||
| # ─── CLI Demo ──────────────────────────────────────────────────────────────── | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🌐 Web query:
For the deep-sort-realtime version declared by this repository: doesupdate_tracks()retain lost tracks untilmax_age, and isTrack.track_idsupported as a mutable application-owned field?💡 Result:
In the deep-sort-realtime repository, the
update_tracks()method does retain tracks that have lost their association with detections until they exceed themax_agethreshold, at which point they are deleted [1][2]. During this period, confirmed tracks continue to perform Kalman filter predictions on their bounding box states [2]. RegardingTrack.track_id, it is not intended to be a mutable, application-owned field. Thetrack_idis managed internally by the tracker to ensure uniqueness across the sequence (or daily, if thetodayparameter is used) [1][3]. While you can accesstrack.track_idas a string, it is dynamically generated by the library [3]. If you require custom track-related metadata or application-specific identifiers, the recommended approach is to subclass theTrackclass and pass it to theDeepSortconstructor via theoverride_track_classargument [4][5]. This allows you to include your own mutable fields or logic within your custom track implementation [4][5].Citations:
🏁 Script executed:
Repository: Devnil434/Eagle
Length of output: 16555
🏁 Script executed:
Repository: Devnil434/Eagle
Length of output: 381
🌐 Web query:
deep-sort-realtime 1.3.2 deep_sort_realtime/deepsort_tracker.py update_tracks Track track_id💡 Result:
In the deep-sort-realtime library (including version 1.3.2), the update_tracks method is the primary API call used to process object detections for a given frame [1][2][3]. When you call tracker.update_tracks(detections, frame=frame), it returns a list of active Track objects [1][3]. To access the unique identifier for a specific track, you iterate through this list of returned track objects and access the track_id attribute [1][3][4]. The standard usage pattern is as follows: tracks = tracker.update_tracks(bbs, frame=frame) for track in tracks: if not track.is_confirmed: continue # Access the unique track ID here track_id = track.track_id # You can also retrieve bounding box coordinates, e.g., ltrb = track.to_ltrb The track_id is typically a unique string (e.g., "1" or "2024-06-01_3") assigned to each object being tracked [3]. Only tracks that have passed the confirmation threshold (typically determined by consecutive detections) are usually processed, which is why it is standard practice to check if track.is_confirmed before using the track_id [1][3][5].
Citations:
🌐 Web query:
github.com levan92 deep_sort_realtime deepsort_tracker.py 1.3.2 update_tracks max_age delete💡 Result:
In the levan92/deep_sort_realtime library, specifically in the context of
deepsort_tracker.pyand theTrackerclass,max_ageis a parameter used to control how long a track persists without a corresponding detection [1]. Key details regardingmax_ageand track deletion include: - Purpose:max_agedefines the maximum number of consecutive frames (or missed detections) allowed before a track is considered lost and is deleted from the tracker [1]. - Configuration: You can set this value when instantiating theDeepSortobject [2][3]. For example,tracker = DeepSort(max_age=5)sets the tracker to allow 5 consecutive missed detections before deleting a track [2][4]. - Behavior: When a track does not receive a matching detection in a frame, the library performs a Kalman prediction to estimate the object's position [3]. The track remains in the tracker's list as long as the number of consecutive missed updates is less than or equal tomax_age[1][3]. - Filtering: If you want to exclude tracks that are currently relying on Kalman predictions (i.e., not matched to a raw detection in the current frame), you can filter them by checking iftrack.time_since_update > 0[3]. Additionally, it is standard practice to usetrack.is_confirmed()to ignore tentative tracks that have not yet reached the required number of consecutive detections to be considered stable [2][3]. The v1.3.2 release (published February 2023) maintained these fundamental tracking mechanics while introducing features such as background masking, updated numpy compatibility, and exposed hyperparameters likemax_iou_distance[5].Citations:
🌐 Web query:
site:github.com/levan92/deep_sort_realtime "class Track" "track_id" "deep_sort_realtime"💡 Result:
In the deep_sort_realtime library, the Track class represents an individual object being tracked [1][2]. You access the unique identifier for a tracked object through the track_id attribute of a Track instance [1][3]. When you call tracker.update_tracks(bbs, frame=frame), it returns a list of Track objects [1][2]. You can iterate through this list to access the track_id for each active track: for track in tracks: if not track.is_confirmed: continue track_id = track.track_id # Additional processing, e.g., using track.to_ltrb Key details regarding the Track class and track_id include: 1. Tracking Lifecycle: A track is typically considered active once it reaches the confirmed state, which occurs after being associated with detections for n_init consecutive frames (default is 3) [4][5][3]. 2. ID Generation: The track_id is managed by the Tracker class [5]. If a today argument is provided during the initialization of the DeepSort tracker, the track_id is formatted as {today}_{_next_id}; otherwise, it is simply the string representation of the incremental _next_id [5]. This date-based formatting helps prevent ID overflow and reset IDs for long-running systems [2]. 3. Customization: You can implement custom logic within the track object by creating a subclass of the Track class and passing it to the DeepSort constructor using the override_track_class argument [1][2]. Sources: [1][4][2][5][3]
Citations:
🌐 Web query:
raw.githubusercontent.com levan92 deep_sort_realtime v1.3.2 deep_sort_realtime/deep_sort/tracker.py "delete" "max_age"💡 Result:
In the
levan92/deep_sort_realtimerepository (version 1.3.2), themax_ageparameter is a configurable integer that defines the maximum number of consecutive frames a track can remain active without being associated with a new detection before it is marked asDeleted[1][2]. It is defined in theTrackerclass withindeep_sort_realtime/deep_sort/tracker.py[1]. While the source code provides the parameter as an argument to theTrackerconstructor (defaulting to 30) [1], users typically interact with it through theDeepSortclass constructor indeep_sort_realtime/deepsort_tracker.py, which passes themax_agevalue down to the underlyingTrackerinstance [3][2]. To modify themax_agevalue, you do not "delete" the parameter; rather, you specify a new integer value when initializing theDeepSortobject in your code [3][2]:python from deep_sort_realtime.deepsort_tracker import DeepSort # Set max_age to your desired number of frames (e.g., 5) tracker = DeepSort(max_age=5)Themax_ageparameter is used by the tracker's internal logic to determine the lifespan of tracks that are not matched during the detection association process [1][2]. There is no requirement or functionality to remove or "delete" this parameter from the source code to use the library; it is designed to be tuned by the user to suit specific tracking requirements [3][2].Citations:
🌐 Web query:
deep-sort-realtime source "delete_tracks" "max_age" "time_since_update"💡 Result:
In the deep-sort-realtime library, max_age, time_since_update, and track deletion work together to manage the lifecycle of tracked objects [1][2]. max_age This is a hyperparameter initialized when creating the DeepSort tracker (e.g., DeepSort(max_age=30)) [3][4]. It defines the maximum number of consecutive frames a track can remain in the system without being associated with a new detection before it is deleted [1][2]. time_since_update This is a property of a Track object that indicates the number of frames elapsed since the track was last successfully matched with a detection [2]. - When a track is matched to a detection in the current frame, its time_since_update is reset to 0 [2]. - If a track is not matched in a frame, the tracker uses Kalman filtering to predict its state, and the time_since_update increments [2][4]. - A track is deleted once its time_since_update exceeds the max_age threshold [1][2]. Manual Deletion To manually clear all active tracks and reset the tracker's internal ID counter to 1, you can use the delete_all_tracks method [1][2]: tracker.delete_all_tracks Additional Filtering If you wish to ignore "ghost" tracks (tracks that exist only via Kalman prediction and haven't been updated by a recent detection), you can manually filter tracks in your processing loop using time_since_update [4]: for track in tracks: if not track.is_confirmed or track.time_since_update > 0: continue
Citations:
Do not mutate the DeepSort-managed track ID.
max_agetracks can remain in DeepSort’s active state while missing detections, so reassigningt.track_id = lost_idcan overwrite DeepSort’s tracking metadata for the lost ID and corrupt the_active_tracksentry/trajectory for that persistent ID. Keep DeepSort IDs separate from re-ID persistent IDs, or use a customoverride_track_classfor application-owned track data.🤖 Prompt for AI Agents