// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TRACK_ASSOCiATION_FUNCTION_ABSTRACT_H__
#ifdef DLIB_TRACK_ASSOCiATION_FUNCTION_ABSTRACT_H__

#include <vector>
#include "assignment_function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class example_detection
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a detection must implement if it is to be
                used with the track_association_function defined at the bottom of this
                file.  In this case, the interface is very simple.  A detection object is
                only required to define the track_type typedef and it must also be possible
                to store detection objects in a std::vector.
        !*/

    public:
        // Each detection object should be designed to work with a specific track object.
        // This typedef lets us determine which track type is meant for use with this
        // detection object.
        typedef struct example_track track_type;

    };

// ----------------------------------------------------------------------------------------

    class example_track
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a track must implement if it is to be
                used with the track_association_function defined at the bottom of this
                file.   
        !*/

    public:
        // This type should be a dlib::matrix capable of storing column vectors or an
        // unsorted sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.
        typedef matrix_or_sparse_vector_type feature_vector_type;

        example_track(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void get_similarity_features (
            const example_detection& det,
            feature_vector_type& feats
        ) const;
        /*!
            ensures
                - #feats == A feature vector that contains information describing how
                  likely it is that det is a detection from the object corresponding to
                  this track.  That is, the feature vector should contain information that
                  lets someone decide if det should be associated to this track.
        !*/

        void update_track (
            const example_detection& det
        );
        /*!
            ensures
                - Updates this track with the given detection assuming that det is the most
                  current observation of the object under track. 
        !*/

        void propagate_track (
        );
        /*!
            ensures
                - propagates this track forward in time one time step.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename detection_type
        > 
    class feature_extractor_track_association
    {
        /*!
            REQUIREMENTS ON detection_type
                It must be an object that implements an interface compatible with the
                example_detection discussed above.  This also means that detection_type::track_type 
                must be an object that implements an interface compatible with example_track 
                defined above.

            WHAT THIS OBJECT REPRESENTS 
                This object is an adapter that converts from the detection/track style
                interface defined above to the feature extraction interface required by the
                association rule learning tools in dlib.  Specifically, it converts the
                detection/track interface into a form usable by the assignment_function and
                its trainer object structural_assignment_trainer.
        !*/

    public:
        typedef typename detection_type::track_type track_type;
        typedef typename track_type::feature_vector_type feature_vector_type;
        typedef detection_type lhs_element;
        typedef track_type rhs_element;

        unsigned long num_features(
        ) const; 
        /*!
            ensures
                - returns the dimensionality of the feature vectors produced by get_features().
        !*/

        void get_features (
            const detection_type& det,
            const track_type& track,
            feature_vector_type& feats
        ) const;
        /*!
            ensures
                - performs: track.get_similarity_features(det, feats);
        !*/
    };

    template <
        typename detection_type
        > 
    void serialize (
        const feature_extractor_track_association<detection_type>& item, 
        std::ostream& out
    );
    /*!
        Provides serialization support.
    !*/

    template <
        typename detection_type
        > 
    void deserialize (
        feature_extractor_track_association<detection_type>& item,
        std::istream& in
    );
    /*!
        Provides deserialization support.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type_
        >
    class track_association_function
    {
        /*!
            REQUIREMENTS ON detection_type
                It must be an object that implements an interface compatible with the
                example_detection discussed above.  This also means that detection_type::track_type 
                must be an object that implements an interface compatible with example_track 
                defined above.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool that helps you implement an object tracker.  So for
                example, if you wanted to track people moving around in a video then this
                object can help.  In particular, imagine you have a tool for detecting the
                positions of each person in an image.  Then you can run this person
                detector on the video and at each time step, i.e. at each frame, you get a
                set of person detections.  However, that by itself doesn't tell you how
                many people there are in the video and where they are moving to and from.
                To get that information you need to figure out which detections match each
                other from frame to frame.  This is where the track_association_function
                comes in.  It performs the detection to track association.  It will also do
                some of the track management tasks like creating a new track when a
                detection doesn't match any of the existing tracks.

                Internally, this object is implemented using the assignment_function object.  
                In fact, it's really just a thin wrapper around assignment_function and
                exists just to provide a more convenient interface to users doing detection
                to track association.   
        !*/
    public:

        typedef detection_type_ detection_type;
        typedef typename detection_type::track_type track_type;
        typedef assignment_function<feature_extractor_track_association<detection_type> > association_function_type;

        track_association_function(
        );
        /*!
            ensures
                - #get_assignment_function() will be default initialized.
        !*/

        track_association_function (
            const association_function_type& assoc
        ); 
        /*!
            ensures
                - #get_assignment_function() == assoc
        !*/

        const association_function_type& get_assignment_function (
        ) const;
        /*!
            ensures
                - returns the assignment_function used by this object to assign detections
                  to tracks.
        !*/

        void operator() (
            std::vector<track_type>& tracks,
            const std::vector<detection_type>& dets
        ) const;
        /*!
            ensures
                - This function uses get_assignment_function() to assign all the detections
                  in dets to their appropriate track in tracks.  Then each track which
                  associates to a detection is updated by calling update_track() with the
                  associated detection.  
                - Detections that don't associate with any of the elements of tracks will
                  spawn new tracks.  For each unassociated detection, this is done by
                  creating a new track_type object, calling update_track() on it with the
                  new detection, and then adding the new track into tracks.
                - Tracks that don't have a detection associate to them are propagated
                  forward in time by calling propagate_track() on them.  That is, we call
                  propagate_track() only on tracks that do not get associated with a
                  detection.
        !*/
    };

    template <
        typename detection_type
        > 
    void serialize (
        const track_association_function<detection_type>& item,
        std::ostream& out
    );
    /*!
        Provides serialization support.
    !*/

    template <
        typename detection_type
        > 
    void deserialize (
        track_association_function<detection_type>& item, 
        std::istream& in
    );
    /*!
        Provides deserialization support.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TRACK_ASSOCiATION_FUNCTION_ABSTRACT_H__


