/*

Trabalho 1 : Visao Computacional e Realidade Aumentada
Aluno: Gustavo Costa Gomes Moreira Mat. 0821404

Este programa detecta características da imagem usando o algoritmo SIFT. 
São utilizadas as bibliotecas OpenCV (Intel) e IUP (Tecgraf - PUC Rio).

*/

#include "..\sift.h"
#include "..\imgfeatures.h"
#include "..\utils.h"

#include <highgui.h>
#include <stdio.h>
#include <iup.h>
#include <iupcontrols.h>
#include <iupgl.h>

/******************************** Globals ************************************/

char* img_file_name = "..\\beaver.png";
char* out_file_name  = "..\\beaver.sift";;
char* out_img_name = NULL;
int display = 1;
int intvls = SIFT_INTVLS;
double sigma = SIFT_SIGMA;
double contr_thr = SIFT_CONTR_THR;
int curv_thr = SIFT_CURV_THR;
int img_dbl = SIFT_IMG_DBL;
int descr_width = SIFT_DESCR_WIDTH;
int descr_hist_bins = SIFT_DESCR_HIST_BINS;


int GUI_StartSIFTCb(Ihandle *self)
{
	//get user input	
	IplImage* img;
	IplImage* frame, *frame_copy=0;
	CvCapture* capture = 0;
	struct feature* features;
	int n = 0;
	double t;
	char* input;

	intvls = atoi(IupGetAttribute(IupGetHandle("txtintvls"),"VALUE"));
    sigma = (float)atof(IupGetAttribute(IupGetHandle("txtsigma"),"VALUE"));
    contr_thr = (float)atof(IupGetAttribute(IupGetHandle("txtcontr_thr"),"VALUE"));
	curv_thr = atoi(IupGetAttribute(IupGetHandle("txtcurv_thr"),"VALUE"));
    img_dbl = atoi(IupGetAttribute(IupGetHandle("txtimg_dbl"),"VALUE"));
	descr_width = atoi(IupGetAttribute(IupGetHandle("txtdescr_width"),"VALUE"));
	descr_hist_bins = atoi(IupGetAttribute(IupGetHandle("txtdescr_hist_bins"),"VALUE"));

	input = IupGetAttribute(IupGetHandle("txtInputFile"),"VALUE");
		
	capture = cvCaptureFromFile(input);

	if( capture )
	{
		cvNamedWindow("sift_image",1);
		cvMoveWindow("sift_image", 600, 0);

		cvNamedWindow("video",1);

		for(;;)
		{            
			if( !cvGrabFrame( capture ))
				break;		

			frame = cvRetrieveFrame( capture );			
			
			if( !frame )
				break;

			if( !frame_copy )
				frame_copy = cvCreateImage( cvSize(frame->width,frame->height),
											IPL_DEPTH_8U, frame->nChannels );
			
			if( frame->origin == IPL_ORIGIN_TL )
				cvCopy( frame, frame_copy, 0 );
			else
				cvFlip( frame, frame_copy, 0 );


			fprintf( stderr, "Finding VIDEO FRAME SIFT features...\n" );

			t = (double)cvGetTickCount();

			n = _sift_features( frame_copy, &features, intvls, sigma, contr_thr, curv_thr,
								img_dbl, descr_width, descr_hist_bins );

			t = (double)cvGetTickCount() - t;
			printf( "Detection time = %gms Found %d features.\n", t/((double)cvGetTickFrequency()*1000.),n );			
			

			if( display )
			{
				draw_features( frame_copy, features, n );
				cvShowImage( "video", frame );
				cvShowImage( "sift_image", frame_copy );
			}


			if( cvWaitKey( 10 ) >= 0 )
			{
				break;			
			}
			
		}
		
		/* release alocated results */		
		cvReleaseCapture( &capture );
		//cvReleaseImage(&frame_copy);
		//cvReleaseImage(&frame);

	}
	else
	{
		fprintf( stderr, "Finding IMAGE SIFT features...\n" );
		img = cvLoadImage( input, 1 );
		if( ! img )
		{
			fprintf( stderr, "Unable to load video/image from %s", img_file_name );
			exit( 1 );
		}
		
		t = (double)cvGetTickCount();
		n = _sift_features( img, &features, intvls, sigma, contr_thr, curv_thr,
							img_dbl, descr_width, descr_hist_bins );
		
		t = (double)cvGetTickCount() - t;
		printf( "Detection time = %gms Found %d features.\n", t/((double)cvGetTickFrequency()*1000.),n );			

		if( display )
		{
			draw_features( img, features, n );
			cvNamedWindow( img_file_name, 1 );
			cvShowImage( img_file_name, img );
		}	
	}

	return IUP_DEFAULT;
}


int GUI_exitCb(Ihandle *self)
{

  /* destroy buffers, disconnect devices, close files */
  return IUP_CLOSE;
}

int GUI_openCb(Ihandle* self)
{  
	
	Ihandle *ndir, *filedlg;
	
	char filename[1024] = ".\\*.*";

	ndir = IupGetHandle("txtInputFile");	
	filedlg = IupFileDlg();
	IupSetAttributes(filedlg, "DIALOGTYPE = OPEN, TITLE = \"Choose File\"");

	IupPopup(filedlg, IUP_CENTER, IUP_CENTER); 
		
	if (IupGetInt(filedlg, IUP_STATUS) == -1)
	{
		return IUP_DEFAULT;			  
	}		
	IupSetAttribute(ndir,"VALUE",IupGetAttribute(filedlg, IUP_VALUE));
	IupDestroy(filedlg);

    return IUP_DEFAULT;
}


Ihandle* GUI_mainToolbarCreate( ) 
{
  Ihandle *toolbar, *open, *exit, *frInput, *txtInputFile, *btnGo;
  
  /*SIFT parameters*/
  Ihandle *frOptions, *txtintvls, *txtsigma, *txtcontr_thr, *txtcurv_thr, *txtimg_dbl;
  Ihandle *txtdescr_width, *txtdescr_hist_bins;
  
  txtintvls = IupText(NULL);
  IupSetAttribute(txtintvls,"SIZE","30");
  IupSetAttribute(txtintvls,"VALUE","3");
  IupSetHandle("txtintvls",txtintvls);

  txtsigma = IupText(NULL);
  IupSetAttribute(txtsigma,"SIZE","30");
  IupSetAttribute(txtsigma,"VALUE","1.6");
  IupSetHandle("txtsigma",txtsigma);

  txtcontr_thr = IupText(NULL);
  IupSetAttribute(txtcontr_thr,"SIZE","30");
  IupSetAttribute(txtcontr_thr,"VALUE","0.04");
  IupSetHandle("txtcontr_thr",txtcontr_thr);

  txtcurv_thr = IupText(NULL);
  IupSetAttribute(txtcurv_thr,"SIZE","30");
  IupSetAttribute(txtcurv_thr,"VALUE","10");
  IupSetHandle("txtcurv_thr",txtcurv_thr);

  txtimg_dbl = IupText(NULL);
  IupSetAttribute(txtimg_dbl,"SIZE","30");
  IupSetAttribute(txtimg_dbl,"VALUE","1");
  IupSetHandle("txtimg_dbl",txtimg_dbl);

  txtdescr_width = IupText(NULL);
  IupSetAttribute(txtdescr_width,"SIZE","40");
  IupSetAttribute(txtdescr_width,"VALUE","4");
  IupSetHandle("txtdescr_width",txtdescr_width);

  txtdescr_hist_bins = IupText(NULL);
  IupSetAttribute(txtdescr_hist_bins,"SIZE","40");
  IupSetAttribute(txtdescr_hist_bins,"VALUE","8");
  IupSetHandle("txtdescr_hist_bins",txtdescr_hist_bins);

  frOptions = IupFrame( 
	  IupVbox(
		IupHbox(
				txtintvls,
				IupLabel(" Number of intervals sampled "),
				IupFill(),
				NULL),
		IupHbox(
				txtsigma,
				IupLabel(" Amount of Gaussian smoothing "),
				IupFill(),
				NULL),
		IupHbox(
				txtcontr_thr,
				IupLabel(" Threshold of the scale space function "),
				IupFill(),
				NULL),		
		IupHbox(
				txtcurv_thr,
				IupLabel(" Threshold on a feature's ratio of principle curvatures"),
				IupFill(),
				NULL),		
		IupHbox(
				txtimg_dbl,
				IupLabel(" 1 if image doubling prior to scale space construction is desired "),
				IupFill(),
				NULL),
		IupHbox(
				txtdescr_width,
				IupLabel(" Width, of the n x n array of orientation histograms "),
				IupFill(),
				NULL),
		IupHbox(
				txtdescr_hist_bins,
				IupLabel(" Number of orientations in each of the histograms "),
				IupFill(),
				NULL),
						
		IupFill(),
		NULL
		)
	   );
  
  IupSetAttribute(frOptions,"TITLE","SIFT Parameters");
  IupSetAttribute(frOptions,"MARGIN","5x5");

  
  /* creates the toolbar and its buttons */
  txtInputFile = IupText(NULL);
  IupSetAttribute(txtInputFile,"SIZE","160");
  IupSetHandle("txtInputFile",txtInputFile);  

  btnGo = IupButton("Start SIFT","btnStart_cb");
  
  open = IupButton("", "open_cb");
  IupSetAttribute(open,"TIP","Opens image file.");
  IupSetAttribute(open,"IMAGE","IUP_IMGBUT_OPEN");
  IupSetFunction("open_cb", (Icallback)GUI_openCb);

  exit = IupButton("exit", "exit_cb");
  IupSetAttribute(exit,"TIP","Exits the program.");
  IupSetFunction("exit_cb", (Icallback)GUI_exitCb);

  IupSetFunction("btnStart_cb",(Icallback)GUI_StartSIFTCb);

  frInput = IupFrame( IupHbox(txtInputFile,open,NULL)
							);

  IupSetAttribute(frInput,"TITLE","Choose Input File (Video or Image)");


  toolbar = 
	  IupVbox(
		 IupHbox(
			IupVbox(		
					frInput,
					frOptions,
					NULL
				),
			IupVbox(
				IupFill(),
				btnGo,
			    exit,
				NULL
			),
			IupFill(),
		 NULL),
			
	   NULL);

  IupSetAttribute(toolbar, "ALIGNMENT", "ACENTER");
  IupSetAttribute(toolbar, "MARGIN", "2x2");
  IupSetAttribute(toolbar, "ACTIVE", "YES");
  
  return toolbar;
}



void GUI_createMainDialog(void)
{
  Ihandle *dialog, *statusbar, *toolbar, *box,
          *label;


  /* initialize interface */
  toolbar = GUI_mainToolbarCreate( );

  /* the status bar is just a label to put some usefull information in run time */
  label = IupLabel("status");
  IupSetAttribute(label, "EXPAND", "HORIZONTAL");
  IupSetAttribute(label, "FONT", "COURIER_NORMAL_10");

  statusbar = IupSetAttributes(IupHbox(
                IupFrame(IupHbox(label, NULL)), 
                NULL), "MARGIN=5x5");      


  /* this is the most external box that puts together
     the toolbar, the two canvas and the status bar */
  box = IupVbox(
          toolbar,
		  IupFill(),
          statusbar, 
          NULL);

  /* create the dialog and set its attributes */

  //GUI_mainMenuCreate( );

  dialog = IupDialog(box);
  IupSetAttribute(dialog, "MENU", "menu");     /* configure the menu */
  IupSetAttribute(dialog, "CLOSE_CB", "exit_cb");
  IupSetAttribute(dialog, "TITLE", "Lowe's SIFT - Scale-Invariant Feature Transform");
  IupSetAttribute(dialog, "RASTERSIZE", NULL); /* initial size */
  IupSetHandle("dialog", dialog);
  IupSetGlobal(IUP_PARENTDIALOG, "dialog");     /* to be used by the idle callback */

  IupShowXY(dialog, IUP_CENTER, IUP_CENTER);
}


/********************************** Main *************************************/

int main( int argc, char** argv )
{

	 /* IUP initialization */
	  IupOpen();
	  IupControlsOpen();
	  IupGLCanvasOpen();
	  IupImageLibOpen();

	  /* Create and Show the main dialog */
	  GUI_createMainDialog();

	  /* IUP event loop */
	  IupMainLoop();

	  /* IUP closing */
	  IupControlsClose();
	  IupImageLibClose();
	  IupClose();

	  return 0;
}
