// Copyright (C) 2018-2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // #pragma once #include #include #include #include #include #include #include #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; /// /// \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> 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& tracks() const; /// /// \brief tracks Returns all tracks including forgotten (lost too many frames /// ago). /// \return Vector of tracks /// std::vector 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& 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& track_ids, const TrackedObjects& detections, std::set* unmatched_tracks, std::set* unmatched_detections, std::set>* matches); void FilterDetectionsAndStore(const TrackedObjects& detected_objects); void ComputeDissimilarityMatrix(const std::set& active_track_ids, const TrackedObjects& detections, cv::Mat* dissimilarity_matrix); std::vector> GetTrackToDetectionIds( const std::set>& 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& 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& track_ids); std::unordered_map> GetActiveTracks(); // Parameters of the pipeline. TrackerParams m_params; // Indexes of active tracks. std::set m_active_track_ids; // All tracks. std::unordered_map 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 UpdateTrackLabelsToBestAndFilterOutUnknowns(const std::vector& tracks);