Skip to content

ITEP-93534: Multi-camera object metadata fusion in time-chunking#1636

Open
MikolajKasprzak wants to merge 16 commits into
mainfrom
ITEP-93534
Open

ITEP-93534: Multi-camera object metadata fusion in time-chunking#1636
MikolajKasprzak wants to merge 16 commits into
mainfrom
ITEP-93534

Conversation

@MikolajKasprzak

Copy link
Copy Markdown
Contributor

📝 Description

Adds deterministic multi-camera metadata fusion to RobotVision. Metadata is merged per field, preferring the highest confidence or the latest camera when confidence is unavailable. Includes legacy and tracker-service support with unit and end-to-end coverage.

✨ Type of Change

Select the type of change your PR introduces:

  • 🐞 Bug fix – Non-breaking change which fixes an issue
  • 🚀 New feature – Non-breaking change which adds functionality
  • 🔨 Refactor – Non-breaking change which refactors the code base
  • 💥 Breaking change – Changes that break existing functionality
  • 📚 Documentation update
  • 🔒 Security update
  • 🧪 Tests
  • 🚂 CI

🧪 Testing Scenarios

Describe how the changes were tested and how reviewers can test them too:

  • ✅ Tested manually
  • 🤖 Ran automated end-to-end tests

✅ Checklist

Before submitting the PR, ensure the following:

  • 🔍 PR title is clear and descriptive
  • 📝 For internal contributors: If applicable, include the JIRA ticket number (e.g., ITEP-123456) in the PR title. Do not include full URLs
  • 💬 I have commented my code, especially in hard-to-understand areas
  • 📄 I have made corresponding changes to the documentation
  • ✅ I have added tests that prove my fix is effective or my feature works

const std::string field = key.substr(std::char_traits<char>::length(MetadataPrefix));
const auto confidence = metadataConfidence(object, field);
const auto winner = winners.find(field);
const bool replace = winner == winners.end() || (confidence && !winner->second.confidence)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confidence && !winner->second.confidence
This scenario is also not covered in the controller/src/robot_vision/test/MetadataFusionTests.cpp

const bool replace = winner == winners.end() || (confidence && !winner->second.confidence)
|| (confidence && winner->second.confidence
&& (*confidence > *winner->second.confidence
|| (*confidence == *winner->second.confidence && cameraIndex > winner->second.cameraIndex)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*confidence == *winner->second.confidence && cameraIndex > winner->second.cameraIndex
This scenario is also not covered in the controller/src/robot_vision/test/MetadataFusionTests.cpp

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that all possible cases in this expression must be covered with unit tests.


const auto InitialTimestamp = std::chrono::system_clock::time_point(std::chrono::milliseconds(10));

TEST(MetadataFusionTest, HighestConfidenceWinsPerField)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two tests missing -

  1. current object has confidence && winner does not have confidence
  2. both objects have the same confidence

assert metadata["gender"]["label"] == "female"
assert metadata["age"]["label"] == "senior"

validate_scene_output({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This validate_scene_output call wraps the candidate_track with a fabricated envelope, so the only meaningful thing we validate is the candidate_track's payload.
My suggestion is to pass the actual received message that contained candidate_track so that the envelope schema drift is also caught here.

@tdorauintc tdorauintc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed partially, I still need to look into fusion logic more carefully.

Comment thread controller/src/controller/ilabs_tracking.py Outdated
Comment thread tests/sscape_tests/scene_pytest/test_ilabs_metadata_fusion.py
Comment thread controller/src/robot_vision/src/rv/tracking/MultipleObjectTracker.cpp Outdated
Comment thread controller/src/robot_vision/src/rv/tracking/MultipleObjectTracker.cpp Outdated
const bool replace = winner == winners.end() || (confidence && !winner->second.confidence)
|| (confidence && winner->second.confidence
&& (*confidence > *winner->second.confidence
|| (*confidence == *winner->second.confidence && cameraIndex > winner->second.cameraIndex)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that all possible cases in this expression must be covered with unit tests.

client.disconnect()


TEST_NAME = "NEX-T25896"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The variable is never referenced

res2.wait_for_publish()

if i < 19:
import time

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I suggest to do the import once at the top

candidate_track = None
for msg in received_messages:
for obj in msg.get("objects", []):
metadata = obj.get("metadata")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make this null-safe the same way as above: use obj.get("metadata", {}) here too. Otherwise metadata can be None and metadata.get(...) can raise AttributeError, causing flaky E2E failures unrelated to fusion logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants