/*---------------------------------------------------------------
	FILE: CMRPTImage.h
	USE: See doc.

   Part of the MRPT Library
   ISA - Universidad de Malaga - http://www.isa.uma.es
  ---------------------------------------------------------------*/
#ifndef CMRPTImage_H
#define CMRPTImage_H

#include <MRPT/UTILS/utils_defs.h>
#include <MRPT/UTILS/CSerializable.h>
#include <MRPT/UTILS/CMatrix.h>
#include <MRPT/UTILS/CMRPTCanvas.h>
#include <MRPT/UTILS/CMRPTCanvas.h>
#include <MRPT/UTILS/MRPT_OS.h>
#include <MRPT/OTHERLIBS/OPENCV/cv.h>	// Include this although MRPT_HAS_OPENCV=0


namespace UTILS
{
	/** In this class an image can be stored. It supports any-size, 1 or 3 bands images, that is,
	 *     grayscale and RGB color images. File I/O is supported in these different ways:
	 *		- Binary dump using the CSerializable interface(<< and >> operators), just as most objects
	 *          in the MRPT library. This format is not compatible with any standarized image format.
	 *		- Saving/loading from bitmap files (.bmp), using the methods loadFromBMP, saveToBMP
	 * <br>
	 * Additional notes: <br>
	 *		- The "IplImage" format from OpenCV is used as representation format for an easy compatibility
	 *			with this library.
	 *		- Only interleaved RGB storage format is supported, the separated color channels is not.
	 *		- Only the unsigned 8-bit storage format for pixels (on each channel) is supported
	 *
	 * Additional implementated operators:
	 *		- getAsFloat
	 *		- getMaxAsFloat
	 *		- scaleHalf
	 *		- scaleDouble
	 *		- operators over images: * (Images multiplication)
	 *      - An assignment "=" operator for converting between the classes "CMRPTImage" and "CMRPTImageFloat".
     *
     *  From MRPT 0.4BETA (Sep 2007), this class becomes a wrapper class for OpenCV functions.
     *
	 * \sa CMRPTImage, CMRPTImageFloat, CSerializable
	 */
	class CMRPTImage : public CSerializable, public CMRPTCanvas
	{
		friend class CMRPTImageFloat;

		DEFINE_SERIALIZABLE( CMRPTImage )

	protected:
		/** Data members
		*/
		IplImage	*img;

		/**  Resize the buffers in "img" to accomodate a new image size and/or format.
		  */
		void  changeSize(
				unsigned int	width,
				unsigned int	height,
				unsigned int	nChannels,
				bool			originTopLeft );

	public:
		/** Changes the size of the image, erasing previous contents.
		  *  - nChannels: Can be 3 for RGB images or 1 for grayscale images.
		  *  - originTopLeft: Is true if the top-left corner is (0,0). In other case, the reference is the bottom-left corner.
		  */
		void  resize(
				unsigned int	width,
				unsigned int	height,
				unsigned int	nChannels,
				bool			originTopLeft )
		{
			ASSERT_(img!=NULL);
			changeSize(width,height,nChannels,originTopLeft);
		}

		/** Changes the value of the pixel (x,y).
		  *  Pixel coordinates starts at the left-top corner of the image, and start in (0,0).
		  *  The meaning of the parameter "color" depends on the implementation: it will usually
		  *   be a 24bit RGB value (0x00RRGGBB), but it can also be just a 8bit gray level.
		  *  This method must support (x,y) values OUT of the actual image size without neither
		  *   raising exceptions, nor leading to memory access errors.
		  */
		void  setPixel(int x, int y, unsigned int color);

		/** Default constructor:
		 */
		CMRPTImage( unsigned int	width = 1,
				unsigned int	height = 1,
				unsigned int	nChannels = 3,
				bool			originTopLeft = true
				);

		/** Copy constructor:
		 */
		CMRPTImage( const CMRPTImage &o );

		/** Copy constructor:
		 */
		CMRPTImage( const CMRPTImageFloat &o );

		/** Copy operator
		  */
		void  operator = (const CMRPTImage& o);

		/** Copy operator from a gray-scale, float image:
		  */
		void  operator = (const CMRPTImageFloat& o);

		/** Constructor from IplImage
		  */
		CMRPTImage( void *iplImage );

		/** Destructor:
		 */
		virtual ~CMRPTImage( );

		/** Returns a pointer to an "OpenCv" IplImage struct containing the image, which is linked to this class: free neigther that pointer nor this class until they are not required anymore, since this class is in charge of freeing the memory buffers inside of the returned image.
		 */
		void*  getAsIplImage() const;

		/** Returns the contents of a given pixel at the desired channel, in float format: [0,255]->[0,1]
		  *   The coordinate origin is pixel(0,0)=top-left corner of the image.
		  * \exception std::exception On pixel coordinates out of bounds
		  * \sa operator()
		  */
		float  getAsFloat(unsigned int col, unsigned int row, unsigned int channel) const;

		/** Returns the contents of a given pixel (for gray-scale images, in color images the gray scale equivalent is computed for the pixel), in float format: [0,255]->[0,1]
		  *   The coordinate origin is pixel(0,0)=top-left corner of the image.
		  * \exception std::exception On pixel coordinates out of bounds
		  * \sa operator()
		  */
		float  getAsFloat(unsigned int col, unsigned int row) const;

		/** Return the maximum pixel value of the image, as a float value.
		  * \sa getAsFloat
		  */
		float  getMaxAsFloat() const;

		/** Returns the width of the image in pixels
		  */
		unsigned int  getWidth() const;

		/** Returns the height of the image in pixels
		  */
		unsigned int  getHeight() const;

		/** Returns true if the image is RGB, false if it is gray scale
		  */
		bool  isColor() const;

		/** Returns true if the coordinates origin is top-left, or false if it is bottom-left
		  */
		bool  isOriginTopLeft() const;

		/** Changes the property of the image stating if the top-left corner (vs. bottom-left) is the coordinate reference.
		  */
		void  setOriginTopLeft(bool val);

		/** Reads the image from raw pixels buffer in memory.
		  */
		void  loadFromMemoryBuffer( unsigned int width, unsigned int height, bool color, unsigned char *rawpixels );

		/** Reads a color image from three raw pixels buffers in memory.
		  * bytesPerRow is the number of bytes per row per channel, i.e. the row increment.
		  */
		void  loadFromMemoryBuffer( unsigned int width, unsigned int height, unsigned int bytesPerRow, unsigned char *red, unsigned char *green, unsigned char *blue );

		/** Reads the image from a OpenCV IplImage object (making a copy).
		  */
		void  loadFromIplImage( void* iplImage );

		/** Load image from a bitmap file (.bmp) format, automatically determining if the file format is 8 or 24 bits/pixel.
		 * \return False on any error
		 * \deprecated{Use the generic loadFromFile instead}
		 */
		MRPT_DEPRECATED_PRE bool  loadFromBMP( const std::string& fileName  ) MRPT_DEPRECATED_POST;

		/** Load image from a JPEG file (.jpg).
		 * \return False on any error
		 * \deprecated{Use the generic loadFromFile instead}
		 */
		MRPT_DEPRECATED_PRE bool  loadFromJPEG( const std::string& fileName  ) MRPT_DEPRECATED_POST;

		/** Reads the image from a binary stream containing a binary jpeg file.
		 * \exception std::exception On pixel coordinates out of bounds
		  */
		void  loadFromStreamAsJPEG( CStream &in );

		/** Save image to a bitmap file (.bmp) format: Currently supported formats are 24-bit RGB bitmap for color images and 8-bit grayscale for grayscale images.
		 * \return False on any error
		 * \deprecated{Use the generic saveToFile instead}
		 */
		MRPT_DEPRECATED_PRE bool  saveToBMP( const std::string& fileName  )  const MRPT_DEPRECATED_POST;

		/** Save image to a JPEG file (.jpg) format
		 * \return False on any error
		 * \sa saveToStreamAsJPEG
		 * \deprecated{Use the generic saveToFile instead}
		 */
		MRPT_DEPRECATED_PRE bool  saveToJPEG( const std::string& fileName  )const MRPT_DEPRECATED_POST;

		/** Load image from a file, whose format is determined from the extension (internally uses OpenCV).
		 * \param fileName The file to read from.
		 * \param isColor Specifies colorness of the loaded image:
		 *  - if >0, the loaded image is forced to be color 3-channel image;
         *  - if 0, the loaded image is forced to be grayscale;
         *  - if <0, the loaded image will be loaded as is (with number of channels depends on the file).
		 * The supported formats are:
		 *
		 * - Windows bitmaps - BMP, DIB;
         * - JPEG files - JPEG, JPG, JPE;
         * - Portable Network Graphics - PNG;
         * - Portable image format - PBM, PGM, PPM;
         * - Sun rasters - SR, RAS;
         * - TIFF files - TIFF, TIF.
         *
		 * \return False on any error
		 */
		bool  loadFromFile( const std::string& fileName, int isColor = 1  );

		/** Save the image to a file, whose format is determined from the extension (internally uses OpenCV).
		 * \param fileName The file to write to.
		 *
		 * The supported formats are:
		 *
		 * - Windows bitmaps - BMP, DIB;
         * - JPEG files - JPEG, JPG, JPE;
         * - Portable Network Graphics - PNG;
         * - Portable image format - PBM, PGM, PPM;
         * - Sun rasters - SR, RAS;
         * - TIFF files - TIFF, TIF.
         *
		 * \return False on any error
		 */
		bool  saveToFile( const std::string& fileName ) const;

		/** Save image to binary stream as a JPEG (.jpg) compresed format.
		 * \exception std::exception On any error
		 * \sa saveToJPEG
		 */
		void  saveToStreamAsJPEG( CStream		&out  )const;

		/** Returns a pointer to a given pixel information.
		 *   The coordinate origin is pixel(0,0)=top-left corner of the image.
		 * \exception std::exception On pixel coordinates out of bounds
		 */
		unsigned char*  operator()(unsigned int col, unsigned int row, unsigned int channel = 0) const;

		/** Returns a grayscale version of the image, or itself if it is already a grayscale image.
		  */
		CMRPTImage  grayscale() const;

		/** Returns a new image scaled down to half its original size.
		  * \exception std::exception On odd size
		  * \sa scaleDouble
		  */
		CMRPTImage  scaleHalf()const;

		/** Returns a new image scaled up to double its original size.
		  * \exception std::exception On odd size
		  * \sa scaleHalf
		  */
		CMRPTImage  scaleDouble()const;


		/** Returns a string of the form "BGR" indicating the channels ordering.
		  */
		const char *  getChannelsOrder()const;

		/** Extracts a patch of this image into another image.
		  * (by AJOGD @ DEC-2006)
		  */
		void  extract_patch(
			CMRPTImage	&patch,
			const unsigned int	col_=0,
			const unsigned int	row_=0,
			const unsigned int	col_num=1,
			const unsigned int	row_num=1 ) const;

		/** Computes the correlation coefficient (returned as val), between two images
		*	This function use grayscale images only
		*	img1, img2 must be same size
		* (by AJOGD @ DEC-2006)
		*/
		float  correlate( const CMRPTImage &img2int, int width_init=0, int height_init=0 )const;

		/**	Computes the cross_correlation between two images and return a matrix of correlation coeficients
		*	This function use grayscale images only
		* (by AJOGD @ DEC-2006)
		* \sa cross_correlation_FFT
		*/
		void  cross_correlation(
			CMRPTImage &img2,
			CMatrixTemplateNumeric<float> &M,
            const int &u_search_ini, const int &v_search_ini,
			const int &u_search_size, const int &v_search_size)const;

		/**	Computes the correlation matrix between this image and another one.
		*   This implementation uses the 2D FFT for achieving reduced computation time.
		* \param in_img The "patch" image, which must be equal, or smaller than "this" image. This function supports gray-scale (1 channel only) images.
		* \param u_search_ini The "x" coordinate of the search window.
		* \param v_search_ini The "y" coordinate of the search window.
		* \param u_search_size The width of the search window.
		* \param v_search_size The height of the search window.
		* \param out_corr The output for the correlation matrix, which will be "u_search_size" x "v_search_size"
		* \param biasThisImg This optional parameter is a fixed "bias" value to be substracted to the pixels of "this" image before performing correlation.
		* \param biasInImg This optional parameter is a fixed "bias" value to be substracted to the pixels of "in_img" image before performing correlation.
		*  Note: By default, the search area is the whole (this) image.
		* (by JLBC @ JAN-2006)
		* \sa cross_correlation
		*/
		void  cross_correlation_FFT(
			const CMRPTImage	&in_img,
			CMatrix				&out_corr,
			int					u_search_ini=-1,
			int					v_search_ini=-1,
			int					u_search_size=-1,
			int					v_search_size=-1,
			float				biasThisImg = 0,
			float				biasInImg = 0
			) const;

		/**	Returns the image as a matrix with pixel grayscale values in the range [0,1]
		  *  \param doResize If set to true (default), the output matrix will be always the size of the image at output. If set to false, the matrix will be enlarged to the size of the image, but it will not be cropped if it has room enough (useful for FFT2D,...)
		  *  \param x_min The starting "x" coordinate to extract (default=0=the first column)
		  *  \param y_min The starting "y" coordinate to extract (default=0=the first row)
		  *  \param x_max The final "x" coordinate (inclusive) to extract (default=-1=the last column)
		  *  \param y_max The final "y" coordinate (inclusive) to extract (default=-1=the last row)
		  * (by JLBC @ JAN-2006)
		  */
		void  getAsMatrix(
			CMatrix		&outMatrix,
			bool		doResize = true,
			int			x_min = 0,
			int			y_min = 0,
			int			x_max = -1,
			int			y_max = -1
			)  const;

		/**	Returns the image as a matrix, where the image is "tiled" (repeated) the required number of times to fill the entire size of the matrix on input.
		  * (by JLBC @ JAN-2006)
		  */
		void  getAsMatrixTiled( CMatrix &outMatrix )  const;

		/** Optimize de brightness range of a image without using histogram
		* Only for one channel images.
		* (by AJOGD @ JAN-2007)
		*/
		void  normalize();

		/**	Computes the correlation between this image and another one, encapsulating the openCV function cvMatchTemplate
		*   This implementation reduced computation time.
		* \param patch_img The "patch" image, which must be equal, or smaller than "this" image. This function supports gray-scale (1 channel only) images.
		* \param u_search_ini The "x" coordinate of the search window.
		* \param v_search_ini The "y" coordinate of the search window.
		* \param u_search_size The width of the search window.
		* \param v_search_size The height of the search window.
		* \param u_max The u coordinate where find the maximun cross correlation value.
		* \param v_max The v coordinate where find the maximun cross correlation value
		* \param max_val The maximun value of cross correlation which we can find
		*  Note: By default, the search area is the whole (this) image.
		* (by AJOGD @ MAR-2007)
		* \sa cross_correlation
		*/
		void  openCV_cross_correlation(
												const CMRPTImage	&patch_img,
												int					&u_max,
												int					&v_max,
												double				&max_val,
												int					u_search_ini=-1,
												int					v_search_ini=-1,
												int					u_search_size=-1,
												int					v_search_size=-1)const;

	}; // End of class

} // end of namespace UTILS

#endif
