/* -*- mode: c++; c-basic-offset: 3 -*-
 *
 * PANDORE (PANTHEON Project)
 *
 * GREYC IMAGE
 * 6 Boulevard Maréchal Juin
 * F-14050 Caen Cedex France
 *
 * This file is free software. You can use it, distribute it
 * and/or modify it. However, the entire risk to the quality
 * and performance of this program is with you.
 *
 * Please email any bugs, comments, and/or additions to this file to:
 * pandore@greyc.ensicaen.fr
 * http://www.greyc.ensicaen.fr/EquipeImage/Pandore/
 */

/**
 * @author Jalal Fadili - 02-02-2005
 * @author Christophe Glinel - 20-07-2005
 */

/**
 * @file ldctiv.cpp
 *
 * Local Discrete Cosine Transform IV
 * This LDCTIV is only implemented with 2D
 * gray images.
 *
 * Transformée discrète en cosinus locaux IV (LDCTIV)
 * (voir aussi les transformées en paquets de cosinus).
 * La LDCTIV implémentée ici ne traite que le cas des images
 * 2D de niveaux de gris.
 */

#include <pandore.h>
using namespace pandore;
#include "dctutils.cpp"


/**
 * LDCTIV
 * Integer 2D gray image (Img2duc)
 * Images MUST have their dimensions all powers of 2 -> reshape.
 * The dimensions of the input and output must be the same.
 * Inputs :
 *	ims : The input image.
 *	imd : The output image.
 *	ww  : The width of the window.
 */
Errc LDCTIV(Img2duc &ims,Img2dsf &imd,Ulong ww) {
   Long x,y;
   Long width   = imd.Width();
   Long height  = imd.Height();
   Double *data = new Double[MAX(width,height)];
   /* Go through rows. */
   for ( y = 0 ; y < height ; y++){
		
      for( x = 0 ; x < width ; x++)
	 data[x] = (Double)ims[y][x];
		
      ldct_iv1D(data, ww, width);
		
      for( x = 0 ; x < width ; x++)
	 imd[y][x] = (Img2dsf::ValueType)data[x];
   }
	
   /* Go through columns. */
   for ( x = 0 ; x < width ; x++){
		
      for( y = 0 ; y < height ; y++ )
	 data[y] = (Double)imd[y][x];
		
      ldct_iv1D(data, ww, height);
		
      for( y = 0 ; y < height ; y++ )
	 imd[y][x] = (Img2dsf::ValueType)data[y];
   }
   delete []data;
   return SUCCESS;
}

/**
 * LDCTIV
 * Integer 2D gray image (Img2dsl)
 * Images MUST have their dimensions all powers of 2 -> reshape.
 * The dimensions of the input and output must be the same.
 * Inputs :
 *	ims : The input image.
 *	imd : The output image.
 *	ww  : The width of the window.
 */
Errc LDCTIV(Img2dsl &ims,Img2dsf &imd,Ulong ww) {
   Long x,y;
   Long width   = imd.Width();
   Long height  = imd.Height();
   Double *data = new Double[MAX(width,height)];
   /* Go through rows. */
   for ( y = 0 ; y < height ; y++){
		
      for( x = 0 ; x < width ; x++)
	 data[x] = (Double)ims[y][x];
		
      ldct_iv1D(data, ww, width);
		
      for( x = 0 ; x < width ; x++)
	 imd[y][x] = (Img2dsf::ValueType)data[x];
   }
	
   /* Go through columns. */
   for ( x = 0 ; x < width ; x++){
		
      for( y = 0 ; y < height ; y++ )
	 data[y] = (Double)imd[y][x];
		
      ldct_iv1D(data, ww, height);
		
      for( y = 0 ; y < height ; y++ )
	 imd[y][x] = (Img2dsf::ValueType)data[y];
   }
   delete []data;
   return SUCCESS;
}

/**
 * LDCTIV
 * Integer 2D gray image (Img2dsf)
 * Images MUST have their dimensions all powers of 2 -> reshape.
 * The dimensions of the input and output must be the same.
 * Inputs :
 *	ims : The input image.
 *	imd : The output image.
 *	ww  : The width of the window.
 */
Errc LDCTIV(Img2dsf &ims,Img2dsf &imd,Ulong ww) {
   Long x,y;
   Long width   = imd.Width();
   Long height  = imd.Height();
   Double *data = new Double[MAX(width,height)];
   /* Go through rows. */
   for ( y = 0 ; y < height ; y++){
		
      for( x = 0 ; x < width ; x++)
	 data[x] = (Double)ims[y][x];
		
      ldct_iv1D(data, ww, width);
		
      for( x = 0 ; x < width ; x++)
	 imd[y][x] = (Img2dsf::ValueType)data[x];
   }
	
   /* Go through columns. */
   for ( x = 0 ; x < width ; x++){
		
      for( y = 0 ; y < height ; y++ )
	 data[y] = (Double)imd[y][x];
		
      ldct_iv1D(data, ww, height);
		
      for( y = 0 ; y < height ; y++ )
	 imd[y][x] = (Img2dsf::ValueType)data[y];
   }
   delete []data;
   return SUCCESS;
}

#ifdef MAIN
#define USAGE	"USAGE : %s window_width [im_in|-] [im_out|-]"
#define PARC	1
#define FINC	1
#define FOUTC	1
#define MASK	0
int main( int argc, char *argv[] ) {
   Errc result;              // The result code of the execution.
   Pobject* mask;            // The region map.
   Pobject* objin[FINC+1];   // The input objects;
   Pobject* objs[FINC+1];    // The source objects masked.
   Pobject* objout[FOUTC+1]; // The output object.
   Pobject* objd[FOUTC+1];   // The result object of the execution.
   char* parv[PARC+1];       // The input parameters.

   ReadArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,parv,USAGE,MASK);
if (objs[0]->Type() == Po_Img2duc) {
   Img2duc * const ims=(Img2duc*)objs[0];
   Check(*ims);
   objd[0] = new Img2dsf(ims->Size());
   Img2dsf * const imd = (Img2dsf*)objd[0];
   result = LDCTIV(*ims,*imd,atol(parv[0]));
   goto end;
   
}
else 
if (objs[0]->Type() == Po_Img2dsl) {
   Img2dsl * const ims=(Img2dsl*)objs[0];
   Check(*ims);
   objd[0] = new Img2dsf(ims->Size());
   Img2dsf * const imd = (Img2dsf*)objd[0];
   result = LDCTIV(*ims,*imd,atol(parv[0]));
   goto end;
   
}
else 
if (objs[0]->Type() == Po_Img2dsf) {
   Img2dsf * const ims=(Img2dsf*)objs[0];
   Check(*ims);
   objd[0] = new Img2dsf(ims->Size());
   Img2dsf * const imd = (Img2dsf*)objd[0];
   result = LDCTIV(*ims,*imd,atol(parv[0]));
   goto end;
   
}
else 
  {
     PrintErrorFormat(objin,FINC);
     result = FAILURE;
  }	

end:
  if (result)
	WriteArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,MASK);
  Exit(result);
  return 0;
}
#endif
