#include "EigenBoundingBoxTrackUtils.h" namespace ByteTrackEigen { /** * @brief Joins two lists of KalmanBBoxTrack pointers, ensuring unique track IDs. * * This function combines track lists A and B. If a track ID is present in both lists, * the track from list B is used in the final list. This ensures that each track ID is * unique in the resulting list. * * @param track_list_a First list of shared pointers to KalmanBBoxTrack objects. * @param track_list_b Second list of shared pointers to KalmanBBoxTrack objects. * @return std::vector> A list with unique tracks based on track IDs. */ std::vector> join_tracks( const std::vector> track_list_a, const std::vector> track_list_b) { std::map> unique_tracks; // Populate the map with tracks from track_list_a for (auto& track : track_list_a) { unique_tracks[track->get_track_id()] = track; } // Insert or overwrite with tracks from track_list_b for (auto& track : track_list_b) { unique_tracks[track->get_track_id()] = track; } // Convert the unique tracks in the map to a vector std::vector> result; for (auto [key, value] : unique_tracks) { result.push_back(value); } return result; } /** * @brief Subtracts tracks in track_list_b from track_list_a based on track IDs. * * This function creates a new list of tracks from track_list_a excluding those * tracks whose IDs are found in track_list_b, effectively performing a set subtraction. * * @param track_list_a First list of shared pointers to KalmanBBoxTrack objects. * @param track_list_b Second list of shared pointers to KalmanBBoxTrack objects. * @return std::vector> A list of tracks present in track_list_a but not in track_list_b. */ std::vector> sub_tracks( const std::vector>& track_list_a, const std::vector>& track_list_b) { std::unordered_set track_ids_b; // Populate set with track IDs from track_list_b for quick lookup for (const auto& track : track_list_b) { track_ids_b.insert(track->get_track_id()); } // Collect tracks from track_list_a not found in track_list_b std::vector> result; for (const auto& track : track_list_a) { if (track_ids_b.find(track->get_track_id()) == track_ids_b.end()) { result.push_back(track); } } return result; } /** * @brief Removes duplicate tracks from two lists based on IOU distance and track age. * * This function identifies and removes duplicate tracks between two lists based on the * Intersection Over Union (IOU) distance. If two tracks have an IOU distance less than * a threshold (0.15), the older track is retained. * * @param track_list_a First list of shared pointers to KalmanBBoxTrack objects. * @param track_list_b Second list of shared pointers to KalmanBBoxTrack objects. * @return Pair of vectors each containing unique tracks after removing duplicates. */ std::pair>, std::vector>> remove_duplicate_tracks(const std::vector> track_list_a, const std::vector> track_list_b) { // Creating instance vectors to store de-referenced shared pointers from the input lists. // This is necessary for the IOU distance calculation. std::vector s_tracks_a_instances; s_tracks_a_instances.reserve(track_list_a.size()); for (const auto& ptr : track_list_a) { s_tracks_a_instances.push_back(*ptr); } std::vector s_tracks_b_instances; s_tracks_b_instances.reserve(track_list_b.size()); for (const auto& ptr : track_list_b) { s_tracks_b_instances.push_back(*ptr); } // Calculating pairwise IOU distance between tracks in both lists. Eigen::MatrixXd pairwise_distance = iou_distance(s_tracks_a_instances, s_tracks_b_instances); // Sets to track indices of duplicates in both lists. std::unordered_set duplicates_a, duplicates_b; // Loop through the matrix of pairwise distances to identify duplicates. for (int i = 0; i < pairwise_distance.rows(); ++i) { for (int j = 0; j < pairwise_distance.cols(); ++j) { // If IOU distance is below the threshold, consider the tracks as duplicates. if (pairwise_distance(i, j) < 0.15) { // Calculate track age to determine which track to keep. int time_a = track_list_a[i]->get_frame_id() - track_list_a[i]->get_start_frame(); int time_b = track_list_b[j]->get_frame_id() - track_list_b[j]->get_start_frame(); // Retain the older track and mark the newer one as a duplicate. if (time_a > time_b) { duplicates_b.insert(j); } else { duplicates_a.insert(i); } } } } // Constructing the result lists, excluding the identified duplicates. std::vector> result_a, result_b; for (int i = 0; i < track_list_a.size(); ++i) { if (duplicates_a.find(i) == duplicates_a.end()) { result_a.push_back(track_list_a[i]); } } for (int j = 0; j < track_list_b.size(); ++j) { if (duplicates_b.find(j) == duplicates_b.end()) { result_b.push_back(track_list_b[j]); } } return { result_a, result_b }; } }