Skip to content

Commit dcc03c6

Browse files
committed
Fix merging errors and set proper default based on metric chosen
1 parent 2421e6b commit dcc03c6

5 files changed

Lines changed: 69 additions & 22 deletions

File tree

controller/src/controller/uuid_manager.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
from scene_common.timestamp import get_epoch_time
1515

1616
DEFAULT_DATABASE = "VDMS"
17-
DEFAULT_SIMILARITY_THRESHOLD = 0.5
17+
DEFAULT_SIMILARITY_THRESHOLD_L2 = 40.0
18+
DEFAULT_SIMILARITY_THRESHOLD_COSINE = 0.5
1819
DEFAULT_MINIMUM_BBOX_AREA = 5000
1920
DEFAULT_MINIMUM_FEATURE_COUNT = 12
2021
DEFAULT_FEATURE_SLICE_SIZE = 10
@@ -46,6 +47,12 @@ def _resolveDatabaseSimilarityMetric(self, configured_metric):
4647
return "IP"
4748
return metric
4849

50+
def _resolveDefaultSimilarityThreshold(self, similarity_metric):
51+
"""Return the default threshold for the configured similarity metric."""
52+
if self._normalizeSimilarityMetric(similarity_metric) == "COSINE":
53+
return DEFAULT_SIMILARITY_THRESHOLD_COSINE
54+
return DEFAULT_SIMILARITY_THRESHOLD_L2
55+
4956
def __init__(self, database=DEFAULT_DATABASE, reid_config_data=None):
5057
self.active_ids = {}
5158
self.active_ids_lock = threading.Lock()
@@ -99,10 +106,13 @@ def _applyReidConfig(self, reid_config_data=None):
99106
'stale_feature_check_interval_secs', DEFAULT_STALE_FEATURE_CHECK_INTERVAL_SECS)
100107
self.minimum_feature_count = reid_config_data.get(
101108
'feature_accumulation_threshold', DEFAULT_MINIMUM_FEATURE_COUNT)
102-
self.similarity_threshold = reid_config_data.get(
103-
'similarity_threshold', DEFAULT_SIMILARITY_THRESHOLD)
104109
self.similarity_metric = self._normalizeSimilarityMetric(reid_config_data.get(
105110
'similarity_metric', DEFAULT_SIMILARITY_METRIC))
111+
configured_similarity_threshold = reid_config_data.get('similarity_threshold')
112+
if configured_similarity_threshold is None:
113+
configured_similarity_threshold = self._resolveDefaultSimilarityThreshold(
114+
self.similarity_metric)
115+
self.similarity_threshold = configured_similarity_threshold
106116
self.minimum_bbox_area = reid_config_data.get(
107117
'minimum_bbox_area', DEFAULT_MINIMUM_BBOX_AREA)
108118
self.feature_slice_size = reid_config_data.get(
@@ -473,8 +483,9 @@ def parseQueryResults(self, similarity_scores, threshold=None):
473483
"""
474484
Check database for any similar objects and return an ID and similarity score.
475485
Uses a majority-vote strategy: a candidate UUID must appear in at least half of the
476-
per-vector best matches whose distance is below the threshold to be accepted.
477-
When multiple candidates qualify, the one with the lowest distance is returned.
486+
per-vector best matches that pass the metric-specific threshold test to be accepted.
487+
When multiple candidates qualify, the one with the best metric value is returned
488+
according to descriptor semantics (highest for IP/COSINE, lowest for L2).
478489
479490
@param similarity_scores The similarity scores obtained from the database query
480491
@param threshold Similarity threshold interpreted according to metric semantics:

docs/user-guide/microservices/controller/Extended-ReID.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,21 +171,21 @@ controller/config/reid-config.json
171171
"feature_accumulation_threshold": 12,
172172
"minimum_bbox_area": 5000,
173173
"feature_slice_size": 10,
174-
"similarity_threshold": 0.3
174+
"similarity_threshold": 40.0
175175
}
176176
```
177177

178178
### Configuration Parameters
179179

180-
| Parameter | Type | Default | Description |
181-
| ----------------------------------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
182-
| `similarity_metric` | string | `L2` | Similarity metric for ReID matching. `L2` is the default distance-style metric (lower-is-better). `COSINE` is implemented using normalized vectors with VDMS `IP` (higher-is-better). |
183-
| `stale_feature_timeout_secs` | float | 5.0 | How long (seconds) to accumulate features in memory before flushing to VDMS. Features older than this threshold are persisted to the database for long-term storage. |
184-
| `stale_feature_check_interval_secs` | float | 1.0 | How frequently (seconds) the background timer checks for stale features and flushes them to VDMS. More frequent checks ensure timely database updates. |
185-
| `feature_accumulation_threshold` | int | 12 | Minimum number of quality features required before initiating a similarity query against the database. More features = higher statistical confidence in matching. |
186-
| `minimum_bbox_area` | int | 5000 | Minimum bounding-box area in pixels required before a detected object contributes a ReID embedding to quality feature accumulation. |
187-
| `feature_slice_size` | int | 10 | When persisting features to VDMS, sample every Nth feature vector from the accumulated set to reduce database bloat. Example: slice_size=10 stores every 10th vector. |
188-
| `similarity_threshold` | float | 0.3 | Match acceptance threshold interpreted using the configured metric semantics: for `COSINE`, candidates **above** the threshold match; for `L2`-style distance metrics, candidates **below** the threshold match. |
180+
| Parameter | Type | Default | Description |
181+
| ----------------------------------- | ------ | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
182+
| `similarity_metric` | string | `L2` | Similarity metric for ReID matching. `L2` is the default distance-style metric (lower-is-better). `COSINE` is implemented using normalized vectors with VDMS `IP` (higher-is-better). |
183+
| `stale_feature_timeout_secs` | float | 5.0 | How long (seconds) to accumulate features in memory before flushing to VDMS. Features older than this threshold are persisted to the database for long-term storage. |
184+
| `stale_feature_check_interval_secs` | float | 1.0 | How frequently (seconds) the background timer checks for stale features and flushes them to VDMS. More frequent checks ensure timely database updates. |
185+
| `feature_accumulation_threshold` | int | 12 | Minimum number of quality features required before initiating a similarity query against the database. More features = higher statistical confidence in matching. |
186+
| `minimum_bbox_area` | int | 5000 | Minimum bounding-box area in pixels required before a detected object contributes a ReID embedding to quality feature accumulation. |
187+
| `feature_slice_size` | int | 10 | When persisting features to VDMS, sample every Nth feature vector from the accumulated set to reduce database bloat. Example: slice_size=10 stores every 10th vector. |
188+
| `similarity_threshold` | float | metric-dependent (`40.0` for `L2`, `0.5` for `COSINE`) | Match acceptance threshold interpreted using the configured metric semantics: for `COSINE`, candidates **above** the threshold match; for `L2`-style distance metrics, candidates **below** the threshold match. |
189189

190190
**Similarity range note**: For `COSINE` (implemented via VDMS `IP`), scores are validated against `[-1, 1]` because embeddings are normalized before storage and query. This range check is metric-specific and is not applied to non-cosine distance metrics.
191191

docs/user-guide/other-topics/how-to-enable-reidentification.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,12 @@ The scene output includes `reid_state` for each tracked object. For canonical st
149149

150150
## Configuration Options
151151

152-
| Parameter | Purpose | Expected Value/Range |
153-
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
154-
| `DEFAULT_SIMILARITY_THRESHOLD` | Match-acceptance threshold. Interpretation depends on `similarity_metric`: for `COSINE` (mapped to VDMS `IP`), higher values are stricter; for `L2`, lower values are stricter. | Float; tune per metric. For `COSINE`/`IP`, values such as `0.2–0.8` may be used. For `L2`, use a distance threshold appropriate to the embedding/model. |
155-
| `DEFAULT_MINIMUM_BBOX_AREA` | Minimum bounding box size to consider a valid feature. | Pixel area (e.g., 400–1600) |
156-
| `DEFAULT_MINIMUM_FEATURE_COUNT` | Minimum features needed before querying DB. | Integer (e.g., 5–20) |
157-
| `DEFAULT_MAX_FEATURE_SLICE_SIZE` | Proportion of features stored to improve DB performance. | Float (e.g., 0.1–1.0) |
152+
| Parameter | Purpose | Expected Value/Range |
153+
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
154+
| `DEFAULT_SIMILARITY_THRESHOLD_L2` / `DEFAULT_SIMILARITY_THRESHOLD_COSINE` | Match-acceptance threshold defaults selected by `similarity_metric`: `L2` uses `DEFAULT_SIMILARITY_THRESHOLD_L2`, and `COSINE` (mapped to VDMS `IP`) uses `DEFAULT_SIMILARITY_THRESHOLD_COSINE`. | Float; tune per metric. For `COSINE`/`IP`, values such as `0.2–0.8` may be used. For `L2`, use a distance threshold appropriate to the embedding/model. |
155+
| `DEFAULT_MINIMUM_BBOX_AREA` | Minimum bounding box size to consider a valid feature. | Pixel area (e.g., 400–1600) |
156+
| `DEFAULT_MINIMUM_FEATURE_COUNT` | Minimum features needed before querying DB. | Integer (e.g., 5–20) |
157+
| `DEFAULT_MAX_FEATURE_SLICE_SIZE` | Proportion of features stored to improve DB performance. | Float (e.g., 0.1–1.0) |
158158

159159
To apply changes (include `--profile vdms` if ReID is enabled; see [Docker Compose Profiles](../get-started.md#docker-compose-profiles)):
160160

tests/Makefile.sscape

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,16 @@ django-integration-unit:
5252
$(MAKE) -Otarget -j $(NPROCS) _$@ SECRETSDIR=$(SECRETSDIR) SUPASS=$(SUPASS) -k
5353
$(eval SECRETSDIR := $(OLDSECRETSDIR))
5454

55+
_django-integration-unit: \
56+
account-security-unit \
57+
cam-unit \
58+
scene-django-unit \
59+
singleton-sensor-unit \
60+
views-unit \
61+
5562
logic-unit-tests:
5663
$(MAKE) -Otarget -j $(NPROCS) _$@ SUPASS=$(SUPASS) -k
64+
5765
_logic-unit-tests: \
5866
autocamcalib-unit \
5967
geometry-unit \

tests/sscape_tests/uuid_manager/test_uuid_manager.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313

1414
import pytest
1515

16-
from controller.uuid_manager import UUIDManager
16+
from controller.uuid_manager import (
17+
UUIDManager,
18+
DEFAULT_SIMILARITY_THRESHOLD_L2,
19+
DEFAULT_SIMILARITY_THRESHOLD_COSINE,
20+
)
1721

1822

1923
def call_update_active_dict_locked(manager, sscape_object, database_id, similarity, query_timestamp=None):
@@ -77,6 +81,30 @@ def test_active_ids_tracking_initialized(self, mock_vdms_db):
7781
assert isinstance(manager.active_ids, dict)
7882
assert len(manager.active_ids) == 0
7983

84+
def test_default_similarity_threshold_uses_l2_value_when_metric_is_l2(self, mock_vdms_db):
85+
"""L2 metric should use the L2-specific default threshold when not configured."""
86+
87+
manager = UUIDManager(reid_config_data={'similarity_metric': 'L2'})
88+
89+
assert manager.similarity_metric == 'L2'
90+
assert manager.similarity_threshold == DEFAULT_SIMILARITY_THRESHOLD_L2
91+
92+
def test_default_similarity_threshold_uses_cosine_value_when_metric_is_cosine(self, mock_vdms_db):
93+
"""COSINE metric should use the cosine-specific default threshold when not configured."""
94+
95+
manager = UUIDManager(reid_config_data={'similarity_metric': 'COSINE'})
96+
97+
assert manager.similarity_metric == 'COSINE'
98+
assert manager.similarity_threshold == DEFAULT_SIMILARITY_THRESHOLD_COSINE
99+
100+
def test_similarity_threshold_explicit_value_overrides_metric_default(self, mock_vdms_db):
101+
"""Explicit similarity_threshold should take precedence over metric-specific defaults."""
102+
103+
manager = UUIDManager(reid_config_data={'similarity_metric': 'COSINE', 'similarity_threshold': 0.77})
104+
105+
assert manager.similarity_metric == 'COSINE'
106+
assert manager.similarity_threshold == 0.77
107+
80108

81109
class TestExtractReidEmbedding:
82110
"""Test Re-ID embedding extraction from detection objects."""

0 commit comments

Comments
 (0)