/* ImLib3D
 * Copyright (c) 2001, ULP-IPB Strasbourg.
 *
 * This program 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.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*! \file   ConvenienceProcessors.hpp */


#ifndef _ConvenienceProcessors_hpp
#define _ConvenienceProcessors_hpp

#include<ImLib3D/ImageProcessor.hpp>

namespace IP3D
{
/*! #&ImageTypeConversion&#     Converts one image type to another.
        The conversion must be valid (ie. a conversion operator must exist for the 
        contaned types). Examples use: converting a mask into a floating point 
        image.
     <UL>Args:
      <LI>Source image     type:ImageType
      <LI>Result image     type:ImageType
      <LI>Result typename  type:ImageTypeName
     </UL>
~*/
	template <class ImageType1,class ImageType2>
	void ImageTypeConversion(const ImageType1& src,ImageType2& res){res=src;}
};

namespace IP3D
{
/*! #&Crop&#     Extract part of an image.
        (x0,y0,z0) and (x1,y1,z1) Are the bounding boints of the subimage. Both are 
        included. Properties are copied and mask is croped too.
     <UL>Args:
      <LI>Source image  type:ImageType
      <LI>zone          type:RectZone3Di
      <LI>Result image  type:ImageType
     </UL>
~*/
	template <class ImageType>
	void Crop(const ImageType& src,const RectZone3Di &zone,ImageType& res0);
};


namespace IP3D
{
/*! #&FindFirstDifference&#     Compares two images til it finds a difference, and returns position.
        Images must have same size. Ignores masks.
     <UL>Args:
      <LI>Source image1     type:ImageType
      <LI>Source image2     type:ImageType
      <LI>found difference  type:bool
      <LI>position          type:Vect3Di
     </UL>
~*/
	template <class ImageType>
	void FindFirstDifference(const ImageType& src1,const ImageType& src2,bool &found,Vect3Di &pos)
	{
		if(src1.Size()!=src2.Size()){ThrowError("CFindFirstDifference images size differ");}
		typename ImageType::const_iterator p=mismatch(src1.begin(),src1.end(),src2.begin()).first;
		if(p!=src1.end()){found=true;pos=p.ComputePosition();}
		else{found=false;}
	}
};


namespace IP3D
{
/*! #&FindFirstDifference&#     Compares two images til it finds a difference, and returns position.
        Images must have same size. Ignores masks.
     <UL>Args:
      <LI>Source image1     type:ImageType
      <LI>Source image2     type:ImageType
      <LI>found difference  type:bool
      <LI>position          type:Vect3Di
     </UL>
~*/
	template <class ImageType>
	void FindMinMax(const ImageType& src,
					  typename ImageType::value_type& vmin,
					  typename ImageType::value_type& vmax,
					  Vect3Di *posMin=NULL,
					  Vect3Di *posMax=NULL)
	{
		typename ImageType::const_iterator p;
		typename ImageType::const_iterator pmin=src.begin();
		typename ImageType::const_iterator pmax=src.begin();
		vmin=src(0,0,0);
		vmax=src(0,0,0);
		for(p=src.begin();p!=src.end();++p)
		{
			if(*p<vmin){pmin=p;vmin=*p;}
			if(*p>vmax){pmax=p;vmax=*p;}
		}
		if(posMin){*posMin=pmin.ComputePosition();}
		if(posMax){*posMax=pmax.ComputePosition();}
	}
};

namespace IP3D
{
/*! #&L2Norm&#     
 ~*/
	template <class ImageType>
	void L2Norm(const ImageType& src, double& energy)
	{
		energy = src.L2Norm();
	}
};

namespace IP3D
{
/*! #&SetAllVoxels&#     Sets all voxels of image to a specified value.
        Value is constructed from string argument using the FromString overloaded 
        template.
     <UL>Args:
      <LI>Source image  type:ImageType
      <LI>v             type:Im3DValue
      <LI>Result image  type:ImageType
     </UL>
~*/
	template <class ImageType>
	void SetAllVoxels(const ImageType& src, const typename ImageType::value_type& v,ImageType& res)
	{
		if(&res!=&src){res=src;}
		res.Fill(v);
	}
};

namespace IP3D
{
/*! #&AddMask&#     Adds a mask to an image.
        Mask image can be specified by an optional third argument. Otherwise mask is 
        intialized to 1. If image already contains a mask, this mask will be 
        assigned the optional argument or will be left untouched.
     <UL>Args:
      <LI>Source image  type:ImageType
      <LI>Result image  type:ImageType
      <LI>Mask          type:Mask3D
     </UL>
~*/
	template <class ImageType>
	void AddMask(const ImageType& src,ImageType& res, const Mask3D *mask=NULL)
	{
		if(&res!=&src){res=src;}
		res.AddMask();
		if(mask)
		{
			if(mask->Size()!=res.Size()){ThrowError("CAddMask: mask size does not mathc with images size");}
			res.Mask()=*mask;
		}
	}
};
namespace IP3D
{
/*! #&GetMask&#     Gets the mask of an image.
        .
     <UL>Args:
      <LI>Source image  type:ImageType
      <LI>Result Mask   type:Mask3D
     </UL>
~*/
	template <class ImageType>
	void GetMask(const ImageType& src,Mask3D& res)
	{
		if(!src.HasMask()){ThrowError("GetMask: no mask");}
		res=src.Mask();
	}
};

namespace IP3D
{
/*! #&ApplyMask&#     Applies a mask on an image. For maskvalue=0, image will be masked for all 
    non-zero mask values. For maskvalues > 0, the mask will be first thresholded so 
    that a mask corresponding to the label maskvalue will be used for masking. If 
    no mask is provided the mask of the source will be used.
        .
     <UL>Args:
      <LI>Source image  type:ImageType
      <LI>Result image  type:ImageType
      <LI>Mask value    type:byte
      <LI>Mask          type:Mask3D
     </UL>
~*/
	template<class ImageType>
	void ApplyMask(const ImageType& src, ImageType& res, byte maskvalue=0, const Mask3D* optmask=NULL);
};

namespace IP3D
{
/*! #&SetDefaultInterpolator&#     Sets the default interpolator type name.
        By default spline degree 5 interpolation is used (this can be slow).
     <UL>Args:
      <LI>Source image            type:ImageType
      <LI>Interpolator type name  type:string
      <LI>Result image            type:ImageType
     </UL>
~*/
	template <class ImageType>
	void SetDefaultInterpolator(const ImageType& src,const string&name,ImageType &res)
	{
		res=src;
		res.SetProperty("DefaultInterpolatorName",name);
	}
};

namespace IP3D
{
/*! #&ExtractFromComplexImage&#     Extracts Imag, Real, Norm2 or Module from a complex valued image into a Image3Df.
        No masks
     <UL>Args:
      <LI>Source image  type:Image3Dcomplex
      <LI>result type   type:string
      <LI>Result image  type:Image3Df
     </UL>
~*/
		void ExtractFromComplexImage(const Image3Dcomplex& src,const string&type,Image3Df &res);
};

#include<ImLib3D/ConvenienceProcessors.hxx>

#endif// _ConvenienceProcessors_hpp
