301 lines
9.2 KiB
C++
301 lines
9.2 KiB
C++
// Copyright (C) 2018-2024 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "utils/kuhn_munkres.hpp"
|
|
#include "cnn.hpp"
|
|
|
|
struct TrackedObject {
|
|
cv::Rect rect;
|
|
float confidence;
|
|
|
|
int object_id;
|
|
int label; // either id of a label, or UNKNOWN_LABEL_IDX
|
|
static const int UNKNOWN_LABEL_IDX; // the value (-1) for unknown label
|
|
|
|
size_t frame_idx; ///< Frame index where object was detected (-1 if N/A).
|
|
|
|
TrackedObject(const cv::Rect& rect = cv::Rect(), float conf = -1.0f,
|
|
int label = -1, int object_id = -1) :
|
|
rect(rect), confidence(conf), object_id(object_id), label(label), frame_idx(-1) {}
|
|
};
|
|
|
|
using TrackedObjects = std::vector<TrackedObject>;
|
|
|
|
///
|
|
/// \brief The Params struct stores parameters of Tracker.
|
|
///
|
|
struct TrackerParams {
|
|
size_t min_track_duration; ///< Min track duration in frames
|
|
|
|
size_t forget_delay; ///< Forget about track if the last bounding box in
|
|
/// track was detected more than specified number of
|
|
/// frames ago.
|
|
|
|
float affinity_thr; ///< Affinity threshold which is used to determine if
|
|
/// tracklet and detection should be combined.
|
|
|
|
float shape_affinity_w; ///< Shape affinity weight.
|
|
|
|
float motion_affinity_w; ///< Motion affinity weight.
|
|
|
|
float min_det_conf; ///< Min confidence of detection.
|
|
|
|
cv::Vec2f bbox_aspect_ratios_range; ///< Bounding box aspect ratios range.
|
|
|
|
cv::Vec2f bbox_heights_range; ///< Bounding box heights range.
|
|
|
|
bool drop_forgotten_tracks; ///< Drop forgotten tracks. If it's enabled it
|
|
/// disables an ability to get detection log.
|
|
|
|
int max_num_objects_in_track; ///< The number of objects in track is
|
|
/// restricted by this parameter. If it is negative or zero, the max number of
|
|
/// objects in track is not restricted.
|
|
|
|
int averaging_window_size_for_rects; ///< The number of objects in track for averaging rects of predictions.
|
|
int averaging_window_size_for_labels; ///< The number of objects in track for averaging labels of predictions.
|
|
|
|
std::string objects_type; ///< The type of boxes which will be grabbed from
|
|
/// detector. Boxes with other types are ignored.
|
|
|
|
///
|
|
/// Default constructor.
|
|
///
|
|
TrackerParams();
|
|
};
|
|
|
|
///
|
|
/// \brief The Track struct describes tracks.
|
|
///
|
|
struct Track {
|
|
///
|
|
/// \brief Track constructor.
|
|
/// \param objs Detected objects sequence.
|
|
///
|
|
explicit Track(const TrackedObjects& objs) : objects(objs), lost(0), length(1) {
|
|
CV_Assert(!objs.empty());
|
|
first_object = objs[0];
|
|
}
|
|
|
|
///
|
|
/// \brief empty returns if track does not contain objects.
|
|
/// \return true if track does not contain objects.
|
|
///
|
|
bool empty() const { return objects.empty(); }
|
|
|
|
///
|
|
/// \brief size returns number of detected objects in a track.
|
|
/// \return number of detected objects in a track.
|
|
///
|
|
size_t size() const { return objects.size(); }
|
|
|
|
///
|
|
/// \brief operator [] return const reference to detected object with
|
|
/// specified index.
|
|
/// \param i Index of object.
|
|
/// \return const reference to detected object with specified index.
|
|
///
|
|
const TrackedObject& operator[](size_t i) const { return objects[i]; }
|
|
|
|
///
|
|
/// \brief operator [] return non-const reference to detected object with
|
|
/// specified index.
|
|
/// \param i Index of object.
|
|
/// \return non-const reference to detected object with specified index.
|
|
///
|
|
TrackedObject& operator[](size_t i) { return objects[i]; }
|
|
|
|
///
|
|
/// \brief back returns const reference to last object in track.
|
|
/// \return const reference to last object in track.
|
|
///
|
|
const TrackedObject& back() const {
|
|
CV_Assert(!empty());
|
|
return objects.back();
|
|
}
|
|
|
|
///
|
|
/// \brief back returns non-const reference to last object in track.
|
|
/// \return non-const reference to last object in track.
|
|
///
|
|
TrackedObject& back() {
|
|
CV_Assert(!empty());
|
|
return objects.back();
|
|
}
|
|
|
|
TrackedObjects objects; ///< Detected objects;
|
|
size_t lost; ///< How many frames ago track has been lost.
|
|
|
|
TrackedObject first_object; ///< First object in track.
|
|
size_t length; ///< Length of a track including number of objects that were
|
|
/// removed from track in order to avoid memory usage growth.
|
|
};
|
|
|
|
///
|
|
/// \brief Simple Hungarian algorithm-based tracker.
|
|
///
|
|
class Tracker {
|
|
public:
|
|
///
|
|
/// \brief Constructor that creates an instance of Tracker with
|
|
/// parameters.
|
|
/// \param[in] params Tracker parameters.
|
|
///
|
|
explicit Tracker(const TrackerParams& params = TrackerParams()) :
|
|
m_params(params), m_tracks_counter(0), m_frame_size() {}
|
|
|
|
///
|
|
/// \brief Process given frame.
|
|
/// \param[in] frame Colored image (CV_8UC3).
|
|
/// \param[in] detections Detected objects on the frame.
|
|
/// \param[in] timestamp Timestamp must be positive and measured in
|
|
/// milliseconds
|
|
///
|
|
void Process(const cv::Mat& frame, const TrackedObjects& detections, int frame_idx);
|
|
|
|
///
|
|
/// \brief Pipeline parameters getter.
|
|
/// \return Parameters of pipeline.
|
|
///
|
|
const TrackerParams& params() const;
|
|
|
|
///
|
|
/// \brief Pipeline parameters setter.
|
|
/// \param[in] params Parameters of pipeline.
|
|
///
|
|
void set_params(const TrackerParams& params);
|
|
|
|
///
|
|
/// \brief Reset the pipeline.
|
|
///
|
|
void Reset();
|
|
|
|
///
|
|
/// \brief Returns recently detected objects.
|
|
/// \return recently detected objects.
|
|
///
|
|
const TrackedObjects& detections() const;
|
|
|
|
///
|
|
/// \brief Get active tracks to draw
|
|
/// \return Active tracks.
|
|
///
|
|
std::unordered_map<size_t, std::vector<cv::Point>> GetActiveTracks() const;
|
|
|
|
///
|
|
/// \brief Get tracked detections.
|
|
/// \return Tracked detections.
|
|
///
|
|
TrackedObjects TrackedDetections() const;
|
|
|
|
///
|
|
/// \brief Get tracked detections with labels.
|
|
/// \return Tracked detections.
|
|
///
|
|
TrackedObjects TrackedDetectionsWithLabels() const;
|
|
|
|
///
|
|
/// \brief IsTrackForgotten returns true if track is forgotten.
|
|
/// \param id Track ID.
|
|
/// \return true if track is forgotten.
|
|
///
|
|
bool IsTrackForgotten(size_t id) const;
|
|
|
|
///
|
|
/// \brief tracks Returns all tracks including forgotten (lost too many frames
|
|
/// ago).
|
|
/// \return Set of tracks {id, track}.
|
|
///
|
|
const std::unordered_map<size_t, Track>& tracks() const;
|
|
|
|
///
|
|
/// \brief tracks Returns all tracks including forgotten (lost too many frames
|
|
/// ago).
|
|
/// \return Vector of tracks
|
|
///
|
|
std::vector<Track> vector_tracks() const;
|
|
|
|
///
|
|
/// \brief IsTrackValid Checks whether track is valid (duration > threshold).
|
|
/// \param id Index of checked track.
|
|
/// \return True if track duration exceeds some predefined value.
|
|
///
|
|
bool IsTrackValid(size_t id) const;
|
|
|
|
///
|
|
/// \brief DropForgottenTracks Removes tracks from memory that were lost too
|
|
/// many frames ago.
|
|
///
|
|
void DropForgottenTracks();
|
|
|
|
private:
|
|
const std::set<size_t>& active_track_ids() const { return m_active_track_ids; }
|
|
|
|
float ShapeAffinity(const cv::Rect& trk, const cv::Rect& det);
|
|
float MotionAffinity(const cv::Rect& trk, const cv::Rect& det);
|
|
|
|
void SolveAssignmentProblem(
|
|
const std::set<size_t>& track_ids, const TrackedObjects& detections,
|
|
std::set<size_t>* unmatched_tracks,
|
|
std::set<size_t>* unmatched_detections,
|
|
std::set<std::tuple<size_t, size_t, float>>* matches);
|
|
void FilterDetectionsAndStore(const TrackedObjects& detected_objects);
|
|
|
|
void ComputeDissimilarityMatrix(const std::set<size_t>& active_track_ids,
|
|
const TrackedObjects& detections,
|
|
cv::Mat* dissimilarity_matrix);
|
|
|
|
std::vector<std::pair<size_t, size_t>> GetTrackToDetectionIds(
|
|
const std::set<std::tuple<size_t, size_t, float>>& matches);
|
|
|
|
float Distance(const TrackedObject& obj1, const TrackedObject& obj2);
|
|
|
|
void AddNewTrack(const TrackedObject& detection);
|
|
|
|
void AddNewTracks(const TrackedObjects& detections);
|
|
|
|
void AddNewTracks(const TrackedObjects& detections, const std::set<size_t>& ids);
|
|
|
|
void AppendToTrack(size_t track_id, const TrackedObject& detection);
|
|
|
|
bool EraseTrackIfBBoxIsOutOfFrame(size_t track_id);
|
|
|
|
bool EraseTrackIfItWasLostTooManyFramesAgo(size_t track_id);
|
|
|
|
bool UptateLostTrackAndEraseIfItsNeeded(size_t track_id);
|
|
|
|
void UpdateLostTracks(const std::set<size_t>& track_ids);
|
|
|
|
std::unordered_map<size_t, std::vector<cv::Point>> GetActiveTracks();
|
|
|
|
// Parameters of the pipeline.
|
|
TrackerParams m_params;
|
|
|
|
// Indexes of active tracks.
|
|
std::set<size_t> m_active_track_ids;
|
|
|
|
// All tracks.
|
|
std::unordered_map<size_t, Track> m_tracks;
|
|
|
|
// Recent detections.
|
|
TrackedObjects m_detections;
|
|
|
|
// Number of all current tracks.
|
|
size_t m_tracks_counter;
|
|
|
|
cv::Size m_frame_size;
|
|
};
|
|
|
|
int LabelWithMaxFrequencyInTrack(const Track& track, int window_size);
|
|
std::vector<Track> UpdateTrackLabelsToBestAndFilterOutUnknowns(const std::vector<Track>& tracks);
|