/*!@file SIFT/VisualObject.H Header file for visual objects to be recognized */

// //////////////////////////////////////////////////////////////////// //
// The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
// University of Southern California (USC) and the iLab at USC.         //
// See http://iLab.usc.edu for information about this project.          //
// //////////////////////////////////////////////////////////////////// //
// Major portions of the iLab Neuromorphic Vision Toolkit are protected //
// under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
// in Visual Environments, and Applications'' by Christof Koch and      //
// Laurent Itti, California Institute of Technology, 2001 (patent       //
// pending; application number 09/912,225 filed July 23, 2001; see      //
// http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
// //////////////////////////////////////////////////////////////////// //
// This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
//                                                                      //
// The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
// redistribute it and/or modify it under the terms of the GNU General  //
// Public License as published by the Free Software Foundation; either  //
// version 2 of the License, or (at your option) any later version.     //
//                                                                      //
// The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
// that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
// PURPOSE.  See the GNU General Public License for more details.       //
//                                                                      //
// You should have received a copy of the GNU General Public License    //
// along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
// to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
// Boston, MA 02111-1307 USA.                                           //
// //////////////////////////////////////////////////////////////////// //
//
// Primary maintainer for this file: Laurent Itti <itti@usc.edu>
// $HeadURL: svn://iLab.usc.edu/trunk/saliency/src/SIFT/VisualObject.H $
// $Id: VisualObject.H 8207 2007-02-01 02:16:51Z siagian $
//

#ifndef MBARIVISUALOBJECT_H_DEFINED
#define MBARIVISUALOBJECT_H_DEFINED

#include "Image/Pixels.H"
#include "Image/Image.H"
#include "SIFT/Keypoint.H"
#include "rutz/shared_ptr.h"

#include <vector>
#include <iosfwd>
#include <string>

class Keypoint;

//! Describes name and attributes of a visual object
/*! A VisualObject is a visual view of a given real-world object. As
  such, it is described by a name, an Image representing the view, and
  possibly a preattentive feature vector (as obtained, for example,
  from VisualCortex::getFeatures() ), and a list of SIFT Keypoint
  objects. */
class MbariVisualObject
{
public:
  // ######################################################################
  //! @name Constructor, assigment and destructor
  //@{

  //! Constructor assuming precomputed keypoints
  /*! @param name the name of the object.
      @param imagefname the filename to store our image into; see operator<<
        and operator>> for details on how this will be used.
      @param image an image of the object. Also see operator<< and operator>>
        for details.
      @param salpt the salient point location of the object.
      @param preattfeatures preattentive features, as obtained, for example,
        from VisualCortex::getFeatures().
      @param keypoints a vector of SIFT Keypoint descriptors. If this is
        empty, then a ScaleSpace will be built from the image and the SIFT
        keypoints will be extracted from it. */
  MbariVisualObject(const std::string& name = "",
               const std::string& imagefname = "",
               const Image< PixRGB<byte> >& image = Image< PixRGB<byte> >(),
               const Point2D& salpt = Point2D(-1,-1),
               const std::vector<double>& preattfeatures =
               std::vector<double>(),
               const std::vector< rutz::shared_ptr<Keypoint> >& keypoints =
               std::vector< rutz::shared_ptr<Keypoint> >(),
                                        const bool useColor = false);

  //! Copy constructor
  MbariVisualObject(const MbariVisualObject& vo);

  //! Destructor
  ~MbariVisualObject();

  //! Assignment
  MbariVisualObject& operator=(const MbariVisualObject& vo);

  //@}

  // ######################################################################
  //! @name Access functions
  //@{

  //! name getter
  inline const std::string& getName() const;

  //! change the name, e.g., after we have recognized the object
  inline void setName(const std::string& name);

  //! image filename getter
  inline const std::string& getImageFname() const;

  //! change the image file name, e.g., after we have recognized the object
  inline void setImageFname(const std::string& fname);

  //! delete the image file from disk
  /*! This is useful if you want to make sure that the current image
    will be saved, as by default operator<< will not overwrite the
    image file. */
  void deleteImageFile() const;

  //! image getter
  inline const Image<PixRGB<byte> >& getImage() const;

  //! get the salient point location
  inline const Point2D& getSalPoint() const;

  //! get all preattentive features
  inline const std::vector<double>& getFeatures() const;

  //! get number of preattentive features
  inline uint numFeatures() const;

  //! get a given preattentive feature
  inline double getFeature(const uint index) const;

  //! get all SIFT keypoints
  inline const std::vector< rutz::shared_ptr<Keypoint> >& getKeypoints() const;

  //! get number of SIFT keypoints
  inline uint numKeypoints() const;

  //! get a given SIFT keypoint
  inline const rutz::shared_ptr<Keypoint>& getKeypoint(const uint index) const;
  //@}

  // ######################################################################
  //! @name Compute functions
  //@{

  //! Sort our Keypoints in ascending order of their DoG magnitude
  /*! We internally keep track of when we are sorted, so calling this
    multiple times will not impact performance. */
  void sortKeypoints();

  //! get squared distance between our and obj's pre-attentive features
  double getFeatureDistSq(const rutz::shared_ptr<MbariVisualObject>& obj) const;

  //! Get an image that shows our SIFT keypoints
  /*! This returns our internal image onto which our keypoints are
    drawn as little vectors.
    @param scale optional scale factor to apply to the image, default
      is to zoom in by a factor 4, which makes the keypoints more visible.
    @param vmag magnitute factor for the length of the scale vectors.
    @param col color of the vectors. */
  Image<PixRGB<byte> > getKeypointImage(const float scale = 2.0F,
                                        const float vmag = 5.0F,
                                        const PixRGB<byte> col =
                                        PixRGB<byte>(255, 0, 0)) const;
  //@}


  void createMbariVisualObject(std::istream& is, MbariVisualObject &v,
                          std::string filepath = "");
                          
  void createMbariVO(std::istream& is, MbariVisualObject &v,
                          std::string filepath = "");


private:
  std::string itsName;                             // name of this object
  std::string itsFilePath;                         // filepath of the image
  std::string itsImageFname;                       // filename of our image
  Image<PixRGB<byte> > itsImage;                   // object image
  std::vector< rutz::shared_ptr<Keypoint> > itsKeypoints; // keypoints
  Point2D itsSalPoint;                             // the salient point location
  std::vector<double> itsFeatures;                 // pre-attentive features
  bool itsIsSorted;                                // are our Keypoints sorted?
  bool itsUseColor;                                // should we add color

  friend std::istream& operator>>(std::istream& is, MbariVisualObject& v);
  friend std::ostream& operator<<(std::ostream& os, const MbariVisualObject& v);
};

// ######################################################################
// MbariVisualObject I/O:
// ######################################################################

//! Load a MbariVisualObject from an istream
std::istream& operator>>(std::istream& is, MbariVisualObject& v);

//! Save a MbariVisualObject to an ostream
/*! If our image file name is known also save the image, but only if
  there is not already a file by than name. You should delete the file
  first if you want to ensure that the image will be saved. You can
  use MbariVisualObject::deleteImageFile() for that. */
std::ostream& operator<<(std::ostream& os, const MbariVisualObject& v);


// ######################################################################
// Implementation for MbariVisualObject inline functions
// ######################################################################
inline const std::string& MbariVisualObject::getName() const
{ return itsName; }

inline void MbariVisualObject::setName(const std::string& name)
{ itsName = name; }

inline const std::string& MbariVisualObject::getImageFname() const
{ return itsImageFname; }

inline void MbariVisualObject::setImageFname(const std::string& fname)
{ itsImageFname = fname; }

inline const Image<PixRGB<byte> >& MbariVisualObject::getImage() const
{ return itsImage; }

inline const Point2D& MbariVisualObject::getSalPoint() const
{ return itsSalPoint; }

inline const std::vector<double>& MbariVisualObject::getFeatures() const
{ return itsFeatures; }

inline uint MbariVisualObject::numFeatures() const
{ return itsFeatures.size(); }

inline double MbariVisualObject::getFeature(const uint index) const
{
  ASSERT(index < itsFeatures.size());
  return itsFeatures[index];
}

inline const std::vector< rutz::shared_ptr<Keypoint> >&
MbariVisualObject::getKeypoints() const
{ return itsKeypoints; }

inline uint MbariVisualObject::numKeypoints() const
{ return itsKeypoints.size(); }

inline const rutz::shared_ptr<Keypoint>&
MbariVisualObject::getKeypoint(const uint index) const
{
  ASSERT(index < itsKeypoints.size());
  return itsKeypoints[index];
}

#endif

// ######################################################################
/* So things look consistent in everyone's emacs... */
/* Local Variables: */
/* indent-tabs-mode: nil */
/* End: */
