Autonomy Software C++ 24.5.1
Welcome to the Autonomy Software repository of the Mars Rover Design Team (MRDT) at Missouri University of Science and Technology (Missouri S&T)! API reference contains the source code and other resources for the development of the autonomy software for our Mars rover. The Autonomy Software project aims to compete in the University Rover Challenge (URC) by demonstrating advanced autonomous capabilities and robust navigation algorithms.
Loading...
Searching...
No Matches
tracking::MultiTracker Class Reference

Class for tracking multiple bounding boxes in images using OpenCV. This class supports all OpenCV tracking algorithms and can be used to track multiple objects in a single image or video stream. More...

#include <BoundingBoxTracking.h>

Public Member Functions

 MultiTracker (const double dTrackingLostTimeout=1.0, const double dMaxTrackingTime=3.0, const double dIOUThreshold=0.3)
 Construct a new Multi Tracker object.
 
 ~MultiTracker ()
 Destroy the Multi Tracker object.
 
bool InitTracker (const cv::Mat &cvFrame, const std::shared_ptr< cv::Rect2d > cvBoundingBox, const TrackerType eTrackerType=TrackerType::eKCF)
 Add a new tracker for a given frame and bounding box.
 
void Update (const cv::Mat &cvFrame)
 Initialize the MultiTracker with a new frame and a vector of bounding boxes.
 
void ClearTrackers ()
 Clear all trackers and bounding boxes from the MultiTracker.
 
void SetTrackerLostTimeout (const double dTimeout)
 Set the timeout for when a tracker is considered lost.
 
void SetMaxTrackingTime (const double dMaxTime)
 Set the maximum tracking time for a tracker.
 
double GetTrackerLostTimeout () const
 Get the timeout for when a tracker is considered lost.
 
double GetMaxTrackingTime () const
 Get the maximum tracking time for a tracker.
 

Private Member Functions

double CalculateIOU (const cv::Rect2d &cvBoxA, const cv::Rect2d &cvBoxB)
 Calculate the Intersection over Union (IoU) of two bounding boxes.
 
cv::Ptr< cv::TrackerCreateTracker (const TrackerType eType)
 Create a tracker based on the specified type.
 

Private Attributes

std::map< int, cv::Ptr< cv::Tracker > > m_mTrackers
 
std::map< int, std::shared_ptr< cv::Rect2d > > m_mBoundingBoxes
 
std::map< int, std::chrono::system_clock::time_point > m_mLastUpdateTime
 
std::map< int, std::chrono::system_clock::time_point > m_mTimeSinceLastGroundTruthDetection
 
double m_dTrackingLostThreshold
 
double m_dMaxTrackingTime
 
double m_dIOUThreshold
 
int m_nNextId
 

Detailed Description

Class for tracking multiple bounding boxes in images using OpenCV. This class supports all OpenCV tracking algorithms and can be used to track multiple objects in a single image or video stream.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-14

Constructor & Destructor Documentation

◆ MultiTracker()

tracking::MultiTracker::MultiTracker ( const double  dTrackingLostThreshold = 1.0,
const double  dMaxTrackingTime = 3.0,
const double  dIOUThreshold = 0.3 
)

Construct a new Multi Tracker object.

Parameters
dTrackingLostThreshold- The time in seconds after which a tracker is considered lost (default is 1.0).
dMaxTrackingTime- The maximum time in seconds a tracker can be lost before being removed (default is 3.0).
dIOUThreshold- The minimum Intersection over Union (IoU) required to associate a new detection with an existing tracker (default is 0.3).
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-15
39 {
40 // Initialize member variables.
41 m_dTrackingLostThreshold = dTrackingLostThreshold;
42 m_dMaxTrackingTime = dMaxTrackingTime;
43 m_dIOUThreshold = dIOUThreshold;
44 m_nNextId = 0;
45 }

◆ ~MultiTracker()

tracking::MultiTracker::~MultiTracker ( )

Destroy the Multi Tracker object.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-15
55 {
56 // Nothing to do yet.
57 }

Member Function Documentation

◆ InitTracker()

bool tracking::MultiTracker::InitTracker ( const cv::Mat cvFrame,
const std::shared_ptr< cv::Rect2d cvBoundingBox,
const TrackerType  eTrackerType = TrackerType::eKCF 
)

Add a new tracker for a given frame and bounding box.

Parameters
cvFrame- The frame to initialize the tracker with.
cvBoundingBox- The bounding box (cv::Rect2d) for the object to track.
eTrackerType- The type of tracker to use (default is KCF).
Returns
true - The given bounding box was matched to an existing tracker and the tracker was updated.
false - The given bounding box was not matched to an existing tracker and a new tracker was created.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-15
72 {
73 // Create instance variables.
74 double dBestIOU = 0.0;
75 int nBestTrackerID = -1;
76 bool bMatchedOldTracker = false;
77
78 // Loop through the existing trackers to find the best match for the given bounding box.
79 for (const std::pair<int, std::shared_ptr<cv::Rect2d>>& stdEntry : m_mBoundingBoxes)
80 {
81 int nID = stdEntry.first;
82 double dIOU = this->CalculateIOU(*stdEntry.second, *cvBoundingBox);
83 if (dIOU > dBestIOU)
84 {
85 dBestIOU = dIOU;
86 nBestTrackerID = nID;
87 }
88 }
89
90 // Catch OpenCV exceptions.
91 try
92 {
93 // If the best IoU is above the threshold and a tracker was found, update the tracker.
94 if (dBestIOU > m_dIOUThreshold && nBestTrackerID != -1)
95 {
96 // Reinitialize the tracker with the new bounding box.
97 m_mBoundingBoxes[nBestTrackerID]->x = cvBoundingBox->x;
98 m_mBoundingBoxes[nBestTrackerID]->y = cvBoundingBox->y;
99 m_mBoundingBoxes[nBestTrackerID]->width = cvBoundingBox->width;
100 m_mBoundingBoxes[nBestTrackerID]->height = cvBoundingBox->height;
101 cv::Ptr<cv::Tracker> cvTracker = this->CreateTracker(eTrackerType);
102 cvTracker->init(cvFrame, *m_mBoundingBoxes[nBestTrackerID]);
103 // Update the tracker in the map.
104 m_mTrackers[nBestTrackerID] = cvTracker;
105 // Update the last update time for the tracker.
106 m_mLastUpdateTime[nBestTrackerID] = std::chrono::system_clock::now();
107 // Update the time since the last ground truth detection.
108 m_mTimeSinceLastGroundTruthDetection[nBestTrackerID] = std::chrono::system_clock::now();
109 // Set the matched tracker flag.
110 bMatchedOldTracker = true;
111 }
112 else
113 {
114 // Create a new tracker and initialize it with the given frame and bounding box.
115 cv::Ptr<cv::Tracker> cvTracker = this->CreateTracker(eTrackerType);
116 cvTracker->init(cvFrame, *cvBoundingBox);
117 // Add the new tracker to the maps.
118 m_mTrackers[m_nNextId] = cvTracker;
119 m_mBoundingBoxes[m_nNextId] = cvBoundingBox;
120 m_mLastUpdateTime[m_nNextId] = std::chrono::system_clock::now();
121 m_mTimeSinceLastGroundTruthDetection[m_nNextId] = std::chrono::system_clock::now();
122 m_nNextId++;
123 }
124 }
125 catch (const std::exception& stdException)
126 {
127 // Submit logger message if an exception occurs.
128 LOG_ERROR(logging::g_qSharedLogger, "Exception in tracker initialization: {}", stdException.what());
129 // Set the bounding box to 0,0,0,0.
130 cvBoundingBox->x = 0;
131 cvBoundingBox->y = 0;
132 cvBoundingBox->width = 0;
133 cvBoundingBox->height = 0;
134 }
135
136 return bMatchedOldTracker;
137 }
cv::Ptr< cv::Tracker > CreateTracker(const TrackerType eType)
Create a tracker based on the specified type.
Definition BoundingBoxTracking.cpp:326
double CalculateIOU(const cv::Rect2d &cvBoxA, const cv::Rect2d &cvBoxB)
Calculate the Intersection over Union (IoU) of two bounding boxes.
Definition BoundingBoxTracking.cpp:307
std::shared_ptr< _Tp > Ptr
Here is the call graph for this function:

◆ Update()

void tracking::MultiTracker::Update ( const cv::Mat cvFrame)

Initialize the MultiTracker with a new frame and a vector of bounding boxes.

Parameters
cvFrame- The initial frame to track objects in.
Note
If the tracking for a bounding box is lost, it will be set to 0,0,0,0 and removed from the tracker.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-15
150 {
151 // Create instance variables.
152 std::vector<int> vToRemove;
153 std::chrono::system_clock::time_point tmCurrentTime = std::chrono::system_clock::now();
154
155 // Loop through the existing trackers.
156 for (const std::pair<const int, cv::Ptr<cv::Tracker>>& stdEntry : m_mTrackers)
157 {
158 // Create instance variables.
159 int nID = stdEntry.first;
160 cv::Rect cvBoundingBox;
161
162 // Check if the tracker is valid
163 if (!stdEntry.second)
164 {
165 LOG_WARNING(logging::g_qSharedLogger, "Tracker is null for ID: {}", std::to_string(nID));
166 continue;
167 }
168
169 // OpenCV loves to throw exceptions, so we need to catch them.
170 try
171 {
172 // Try to update the tracker with the current frame.
173 if (stdEntry.second->update(cvFrame, cvBoundingBox))
174 {
175 // Update the bounding box
176 m_mBoundingBoxes[nID]->x = cvBoundingBox.x;
177 m_mBoundingBoxes[nID]->y = cvBoundingBox.y;
178 m_mBoundingBoxes[nID]->width = cvBoundingBox.width;
179 m_mBoundingBoxes[nID]->height = cvBoundingBox.height;
180 m_mLastUpdateTime[nID] = tmCurrentTime;
181 }
182
183 // If the tracker fails to update, we need to check if it has been lost for too long.
184 double dTimeElapsedSinceGoodTrack = std::chrono::duration_cast<std::chrono::milliseconds>(tmCurrentTime - m_mLastUpdateTime[nID]).count() / 1000.0;
185 double dTimeElapsedSinceLastDetection =
186 std::chrono::duration_cast<std::chrono::milliseconds>(tmCurrentTime - m_mTimeSinceLastGroundTruthDetection[nID]).count() / 1000.0;
187 if (dTimeElapsedSinceGoodTrack > m_dTrackingLostThreshold || dTimeElapsedSinceLastDetection > m_dMaxTrackingTime)
188 {
189 vToRemove.push_back(nID);
190 }
191 }
192 catch (const std::exception& stdException)
193 {
194 // Submit logger message if an exception occurs.
195 LOG_ERROR(logging::g_qSharedLogger, "Exception in tracker update for ID: {} Error {}", nID, stdException.what());
196 // Remove the problematic tracker.
197 vToRemove.push_back(nID);
198 }
199 }
200
201 // Remove trackers that have been lost for too long.
202 for (int nID : vToRemove)
203 {
204 // Remove the tracker and last update time from the maps.
205 m_mTrackers.erase(nID);
206 m_mLastUpdateTime.erase(nID);
207 m_mTimeSinceLastGroundTruthDetection.erase(nID);
208
209 // Set the bounding box to 0,0,0,0.
210 m_mBoundingBoxes[nID]->x = 0;
211 m_mBoundingBoxes[nID]->y = 0;
212 m_mBoundingBoxes[nID]->width = 0;
213 m_mBoundingBoxes[nID]->height = 0;
214 // Remove the bounding box from the map.
215 m_mBoundingBoxes.erase(nID);
216 }
217 }

◆ ClearTrackers()

void tracking::MultiTracker::ClearTrackers ( )

Clear all trackers and bounding boxes from the MultiTracker.

Note
This function will set all bounding boxes to 0,0,0,0 and remove all trackers.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-27
228 {
229 m_mTrackers.clear();
230 m_mLastUpdateTime.clear();
231 m_mTimeSinceLastGroundTruthDetection.clear();
232
233 // Set the bounding boxes to 0,0,0,0.
234 for (const std::pair<int, std::shared_ptr<cv::Rect2d>>& stdEntry : m_mBoundingBoxes)
235 {
236 stdEntry.second->x = 0;
237 stdEntry.second->y = 0;
238 stdEntry.second->width = 0;
239 stdEntry.second->height = 0;
240 }
241 // Clear the bounding boxes.
242 m_mBoundingBoxes.clear();
243 }

◆ SetTrackerLostTimeout()

void tracking::MultiTracker::SetTrackerLostTimeout ( const double  dTimeout)

Set the timeout for when a tracker is considered lost.

Parameters
dTimeout- The time in seconds after which a tracker is considered lost.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-29
254 {
255 m_dTrackingLostThreshold = dTimeout;
256 }

◆ SetMaxTrackingTime()

void tracking::MultiTracker::SetMaxTrackingTime ( const double  dMaxTime)

Set the maximum tracking time for a tracker.

Parameters
dMaxTime- The maximum time in seconds a tracker can be lost before being removed.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-04-15
267 {
268 m_dMaxTrackingTime = dMaxTime;
269 }

◆ GetTrackerLostTimeout()

double tracking::MultiTracker::GetTrackerLostTimeout ( ) const

Get the timeout for when a tracker is considered lost.

Returns
double - The time in seconds after which a tracker is considered lost.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-29
280 {
281 return m_dTrackingLostThreshold;
282 }

◆ GetMaxTrackingTime()

double tracking::MultiTracker::GetMaxTrackingTime ( ) const

Get the maximum tracking time for a tracker.

Returns
double - The maximum time in seconds a tracker can be lost before being removed.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-04-15
293 {
294 return m_dMaxTrackingTime;
295 }

◆ CalculateIOU()

double tracking::MultiTracker::CalculateIOU ( const cv::Rect2d cvBoxA,
const cv::Rect2d cvBoxB 
)
private

Calculate the Intersection over Union (IoU) of two bounding boxes.

Parameters
cvBoxA- The first bounding box (cv::Rect2d).
cvBoxB- The second bounding box (cv::Rect2d).
Returns
double - The IoU value between the two bounding boxes, ranging from 0.0 to 1.0.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-15
308 {
309 // Calculate the intersection area.
310 double dIntersectionArea = (cvBoxA & cvBoxB).area();
311 // Calculate the union area.
312 double dUnionArea = cvBoxA.area() + cvBoxB.area() - dIntersectionArea;
313 // Return the Intersection over Union (IoU).
314 return (dUnionArea > 0) ? (dIntersectionArea / dUnionArea) : 0.0;
315 }
_Tp area() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CreateTracker()

cv::Ptr< cv::Tracker > tracking::MultiTracker::CreateTracker ( const TrackerType  eType)
private

Create a tracker based on the specified type.

Parameters
eType- The type of tracker to create (eMIL, eKCF, eGOTURN, eCSRT).
Returns
cv::Ptr<cv::Tracker> - A pointer to the created tracker.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-03-29
327 {
328 // Catch OpenCV exceptions.
329 try
330 {
331 // Create a tracker based on the specified type.
332 switch (eType)
333 {
334 case TrackerType::eMIL: return cv::TrackerMIL::create(); break;
335 case TrackerType::eKCF: return cv::TrackerKCF::create(); break;
336 case TrackerType::eCSRT: return cv::TrackerCSRT::create(); break;
337 default:
338 // Submit a warning message if the tracker type is unknown.
339 LOG_WARNING(logging::g_qSharedLogger, "Unknown tracker type specified. Defaulting to KCF.");
340 // Return a default tracker (KCF) if the type is unknown.
341 return cv::TrackerKCF::create();
342 break;
343 }
344 }
345 catch (const std::exception& stdException)
346 {
347 // Submit a warning message if an exception occurs.
348 LOG_ERROR(logging::g_qSharedLogger, "Exception in tracker creation: {}", stdException.what());
349 // Return a default tracker (KCF) if an exception occurs.
350 return cv::TrackerKCF::create();
351 }
352 }
static Ptr< TrackerCSRT > create(const TrackerCSRT::Params &parameters=TrackerCSRT::Params())
static Ptr< TrackerKCF > create(const TrackerKCF::Params &parameters=TrackerKCF::Params())
static Ptr< TrackerMIL > create(const TrackerMIL::Params &parameters=TrackerMIL::Params())
Here is the caller graph for this function:

The documentation for this class was generated from the following files: