/**
* @file LocalFeatureSift.h
* @brief local feature with sift
* @author Erik Rodner, Alexander Freytag
* @date 03/10/2012 (Eric Bach)
* @note some notes to the use of siftGPU (added by Eric Bach)
*  - install cudaSift & siftGPU (see Makefile.config)
*  - add to libdepend.inc: $(call PKG_DEPEND_EXT, CUDASIFT) to specify: -DNICE_USELIB_CUDASIFT as compilerflag
*  - add to section [LFSiftPP] use_siftgpu=true (or 'false' to disable the gpu-support)
*
*  If you use the gpu-support just one device is supported until now.
*  If your device do not support the siftGPU completly the class switch to "normal" sift.
*  It is possible to compile this class without siftGPU, but then you must not specify the flag: -DNICE_USELIB_CUDASIFT.
*/
#ifndef LOCALFEATURESIFTINCLUDE
#define LOCALFEATURESIFTINCLUDE


// STL includes
#include <iostream>
#include <string>
#include <stdexcept>

// nice-core includes
#include <core/basics/Config.h>
#include <core/basics/StringTools.h>
// 
#include <core/image/ImageT.h>
#include <core/imagedisplay/ImageDisplay.h>
// 
#include <core/vector/VectorT.h>
#include <core/vector/MatrixT.h>

// nice-vislearning includes
#include "LocalFeature.h"



// SiftGPU & GL
#ifdef NICE_USELIB_CUDASIFT
#include <src/SiftGPU.h>
#include <GL/gl.h>
#endif


namespace OBJREC {

/** local feature with sift */
class LocalFeatureSift : public LocalFeature
{

  protected:
    
    /////////////////////////
    /////////////////////////
    // PROTECTED VARIABLES //
    /////////////////////////
    /////////////////////////    
    
    int octaves;
    
    int levels;
    
    bool normalizeFeature;
    
    int first_octave;
    
    double magnif;
    
    bool deletemode;
    
    bool integerValues;

    // for SiftGPU
    bool usegpu;

    float threshold;
    
    float edgeThreshold;
    
    /////////////////////////
    /////////////////////////
    //  PROTECTED METHODS  //
    /////////////////////////
    /////////////////////////      

    void withPP ( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors ) const;
#ifdef NICE_USELIB_CUDASIFT
    void withGPU ( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors ) const;
#endif

  public:
    
    ///////////////////// ///////////////////// /////////////////////
    //                   CONSTRUCTORS / DESTRUCTORS
    ///////////////////// ///////////////////// /////////////////////       

    /** 
     * @brief default constructor
     * @date 09-02-2014 (dd-mm-yyyy )
     * @author Alexander Freytag
     */
    LocalFeatureSift ( );    
    
    /**
     * @brief recommended constructor, calls initFromConfig
     * @date 09-02-2014 (dd-mm-yyyy )
     * @author Alexander Freytag
     */
    LocalFeatureSift ( const NICE::Config * _conf );

    /**
     * @brief simple destructor
     */
    virtual ~LocalFeatureSift();
    
    /** 
     * @brief Jobs previously performed in the config-version of the constructor, read settings etc.
     * @author Alexander Freytag
     * @date 09-02-2014 ( dd-mm-yyyy )
     */    
    void initFromConfig ( const NICE::Config * _conf, const std::string & _confSection = "LocalFeatureSift");    
    
    ///////////////////// ///////////////////// /////////////////////
    //                      FEATURE STUFF
    ///////////////////// ///////////////////// //////////////////        

    /**
     * returns the size of each the SIFT-Feature
     * @return 128
     */
    int getDescSize() const {
      return 128;
    };


    //! returns true if gpu is used
    bool isGpuUsed() const {
#ifdef NICE_USELIB_CUDASIFT
      return usegpu;
#else
      return false;
#endif
    };

    /**
     * get the descriptor
     * @param img input image
     * @param positions positions for the SIFT features
     * @param descriptors output
     * @return 0
     */
    virtual int getDescriptors ( const NICE::Image & img,
                                 NICE::VVector & positions,
                                 NICE::VVector & descriptors ) const;

    /**
     * computes the descriptor for a single image
     * @param img
     * @param positions
     * @param descriptors
     */
    void computeDesc ( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors ) const;

    /**
     * sort positions by scales for faster computing of the Keypoint orientation
     * @param positions
     */
    void sortPositions ( NICE::VVector & positions ) const;

    virtual void visualizeFeatures ( NICE::Image & mark, const NICE::VVector & positions, size_t color ) const;


    ///////////////////// INTERFACE PERSISTENT /////////////////////
    // interface specific methods for store and restore
    ///////////////////// INTERFACE PERSISTENT /////////////////////   
    
    /** 
     * @brief Load object from external file (stream)
     * @author Alexander Freytag
     * @date 09-02-2014 ( dd-mmyyyy)
     */     
    virtual void restore ( std::istream & is, int format = 0 );
    
    /** 
     * @brief Save object to external file (stream)
     * @author Alexander Freytag
     * @date 09-02-2014 ( dd-mmyyyy)
     */       
    virtual void store( std::ostream & os, int format = 0 ) const;
    
    /** 
     * @brief Clear  object
     * @author Alexander Freytag
     * @date 09-02-2014 ( dd-mmyyyy)
     */    
    virtual void clear ();  

};


} // namespace

#endif