/*********************************************************** 
*  --- OpenSURF ---                                        *
*  This library is distributed under the GNU GPL. Please   *
*  contact chris.evans@irisys.co.uk for more information.  *
*                                                          *
*  C. Evans, Research Into Robust Visual Features,         *
*  MSc University of Bristol, 2008.                        *
*                                                          *
************************************************************/

// OpenGSURF
// Author: Pablo F. Alcantarilla
// Date: 11/11/2011
// Email: pablofdezalc@gmail.com
//**************************************************************************************
//**************************************************************************************

#ifndef SURF_H
#define SURF_H

//**************************************************************************************
//**************************************************************************************

#include <sys/time.h>
#include <vector>
#include <iostream>
#include "cv.h"
#include "ipoint.h"
#include "integral.h"
#include "utils.h"

using namespace std;

//**************************************************************************************
//**************************************************************************************

class Surf {
  
  public:
    
    //! Standard Constructor (img is an integral image)
    Surf(IplImage *img, std::vector<Ipoint> &ipts);

    //! Describe all features in the supplied vector
    void getDescriptors(unsigned char mode = 1, bool bUpright = false, bool bExtended = false);
  
  private:
    
    //---------------- Private Functions -----------------//

    //! Assign the current Ipoint an orientation
    void getOrientation();
    
    //**********************************************************

    //! Get default OpenSURF descriptor with Gaussian Weighting
    //! MODE = 0
	void getDescriptor_64();
	void getUprightDescriptor_64();
	void getExtendedDescriptor_128();
	void getUprightExtendedDescriptor_128();

    //**********************************************************

    //! Get the modified descriptor. See Agrawal ECCV 08
    //! MODE = 1
    void getMDescriptor_64();
    void getMUprightDescriptor_64();
    void getMExtendedDescriptor_128();
    void getMUprightExtendedDescriptor_128();

    //**********************************************************

    //! Get the Gauge Descriptor
    //! MODE = 2
    void getGaugeDescriptor_16();
    void getGaugeUprightDescriptor_16();
    void getGaugeExtendedDescriptor_32();
    void getGaugeUprightExtendedDescriptor_32();
	
	//**********************************************************

    //! Get the Gauge Descriptor
    //! MODE = 3
    void getGaugeDescriptor_36();
    void getGaugeUprightDescriptor_36();
    void getGaugeExtendedDescriptor_72();
    void getGaugeUprightExtendedDescriptor_72();
	
    //**********************************************************

    //! Get the Gauge Descriptor
    //! MODE = 4
    void getGaugeDescriptor_64();
    void getGaugeUprightDescriptor_64();
    void getGaugeExtendedDescriptor_128();
    void getGaugeUprightExtendedDescriptor_128();

	//**********************************************************

    //! Get the Gauge Descriptor
    //! MODE = 5
    void getGaugeDescriptor_100();
    void getGaugeUprightDescriptor_100();
    void getGaugeExtendedDescriptor_200();
    void getGaugeUprightExtendedDescriptor_200();

	//**********************************************************

    //! Get the Gauge Descriptor
    //! MODE = 6
    void getGaugeDescriptor_144();
    void getGaugeUprightDescriptor_144();
    void getGaugeExtendedDescriptor_288();
    void getGaugeUprightExtendedDescriptor_288();
	
    //**********************************************************

    //! Get the SURF Descriptor Without Gaussian Weighting
    //! MODE = 7
    void getDescriptor_NW_16();
    void getUprightDescriptor_NW_16();
    void getExtendedDescriptor_NW_32();
    void getUprightExtendedDescriptor_NW_32();
	
	//**********************************************************

    //! Get the SURF Descriptor Without Gaussian Weighting
    //! MODE = 8
    void getDescriptor_NW_36();
    void getUprightDescriptor_NW_36();
    void getExtendedDescriptor_NW_72();
    void getUprightExtendedDescriptor_NW_72();
	
	//**********************************************************

    //! Get the SURF Descriptor Without Gaussian Weighting
    //! MODE = 9
    void getDescriptor_NW_64();
    void getUprightDescriptor_NW_64();
    void getExtendedDescriptor_NW_128();
    void getUprightExtendedDescriptor_NW_128();
	
	//**********************************************************

    //! Get the SURF Descriptor Without Gaussian Weighting
    //! MODE = 10
    void getDescriptor_NW_100();
    void getUprightDescriptor_NW_100();
    void getExtendedDescriptor_NW_200();
    void getUprightExtendedDescriptor_NW_200();
	
	//**********************************************************

    //! Get the SURF Descriptor Without Gaussian Weighting
    //! MODE = 11
    void getDescriptor_NW_144();
    void getUprightDescriptor_NW_144();
    void getExtendedDescriptor_NW_288();
    void getUprightExtendedDescriptor_NW_288();
	
	//**********************************************************

    //! Get the MG-SURF Descriptor
    //! MODE = 12
	void getMGaugeDescriptor_64();
	void getMGaugeUprightDescriptor_64();
	void getMGaugeExtendedDescriptor_128();
    void getMGaugeUprightExtendedDescriptor_128();
	
    //**********************************************************
	
    //! Calculate the value of the 2d gaussian at x,y
    inline float gaussian(int x, int y, float sig);
    inline float gaussian(float x, float y, float sig);

    //! Calculate Haar wavelet responses in x and y directions
    inline float haarX(int row, int column, int size);
    inline float haarY(int row, int column, int size);
    inline float haarXY(int row, int column, int s);
    inline float haarXX(int row, int column, int s);
    inline float haarYY(int row, int column, int s);

    //! Get the angle from the +ve x-axis of the vector given by [X Y]
    float getAngle(float X, float Y);

	//! Function for clipping normalization 
	void clippingDescriptor(int niter, float ratio);

    //---------------- Private Variables -----------------//

    //! Integral image where Ipoints have been detected
    IplImage *img;

    //! Ipoints vector
    IpVec &ipts;

    //! Index of current Ipoint in the vector
    int index;
};

//**************************************************************************************
//**************************************************************************************

#endif
