#include <iostream>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>

//*********************************
#include "profiler.h"

TMARK MSTART("START");
TMARK MWIDTH("Width");
TMARK MHEIGHT("Height");
TMARK KERNEL("Kernel");


TCHAN CHAN1("ALG");
TMARK MINIT("Init",CHAN1);
TMARK MNONE("NONE",CHAN1);
TMARK MDFT("DFT",CHAN1);
TMARK MSMOOTH("SMOOTH",CHAN1);
TMARK MBILAT("Bilatelar",CHAN1);
TMARK MHIST("EqualizeHist",CHAN1);
TMARK MTHRESH("Threshold",CHAN1);
TMARK MSOBEL("Sobel",CHAN1);
TMARK MHOUGH("HoughLines",CHAN1);
TMARK MTRANS("Transform",CHAN1);
TMARK MHARIS("Haris",CHAN1);
TMARK MDETECT("Detector",CHAN1);

using namespace std;
using namespace cv;

#define TESTLOOP 1
#define MAX_KERNEL_LENGTH 31

String face_cascade_name = "haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;

Mat image[4];

TProfiler *ref;

//*****************************************************************************************
void t_DFT(Mat &I){	
	Mat padded;                            //expand input image to optimal size
    int m = getOptimalDFTSize( I.rows );
    int n = getOptimalDFTSize( I.cols ); // on the border add zero values
    copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));

    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexI;
    merge(planes, 2, complexI);         // Add to the expanded another plane with zeros

    dft(complexI, complexI);            // this way the result may fit in the source matrix	
}
//*****************************************************************************************
void t_Smooth(Mat &I){
	Mat dst;
	for ( int i = 1; i < MAX_KERNEL_LENGTH; i=i+2 ){
		ref->MARK(KERNEL,i);
		GaussianBlur( I, dst, Size( i, i ), 0, 0 );
	}
	ref->MARK(KERNEL,0);
}
//*****************************************************************************************
void t_BilateralFilter(Mat &I){
	Mat dst;
	ref->MARK(KERNEL,11);
    bilateralFilter ( I, dst, 11, 11*2, 11/2 );    
    ref->MARK(KERNEL,0);
}
//*****************************************************************************************
void t_EqualizeHist(Mat &I){
	Mat dst;
	equalizeHist( I, dst );
}
//*****************************************************************************************
void t_Threshold(Mat &I){
	Mat dst;
	threshold( I, dst, 127, 255,3 );
}
//*****************************************************************************************
void t_Sobel(Mat &I){
	Mat grad_x, grad_y;
  	Mat abs_grad_x, abs_grad_y;
  	Mat dst;
	Sobel( I, grad_x, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT );
	convertScaleAbs( grad_x, abs_grad_x );

	/// Gradient Y
	
	Sobel( I, grad_y, CV_16S, 0, 1, 3, 1, 0, BORDER_DEFAULT );
	convertScaleAbs( grad_y, abs_grad_y );

	/// Total Gradient (approximate)
	addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
 }
//*****************************************************************************************
void t_HoughLines(Mat &I){
	Mat dst;
	Canny(I, dst, 50, 200, 3);
	vector<Vec4i> lines;
  	HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
}
//*****************************************************************************************
void t_Transform(Mat &I){

   Point2f srcTri[3];
   Point2f dstTri[3];
   Mat warp_mat( 2, 3, CV_32FC1 );
   Mat dst = Mat::zeros( I.rows, I.cols, I.type() );
   
   srcTri[0] = Point2f( 0,0 );
   srcTri[1] = Point2f( I.cols - 1, 0 );
   srcTri[2] = Point2f( 0, I.rows - 1 );

   dstTri[0] = Point2f( I.cols*0.0, I.rows*0.33 );
   dstTri[1] = Point2f( I.cols*0.85, I.rows*0.25 );
   dstTri[2] = Point2f( I.cols*0.15, I.rows*0.7 );

   /// Get the Affine Transform
   warp_mat = getAffineTransform( srcTri, dstTri );

   /// Apply the Affine Transform just found to the src image
   warpAffine( I, dst, warp_mat, dst.size() );
}

//*****************************************************************************************
void t_Haris(Mat &I){
	Mat dst;
	cornerHarris( I, dst, 2, 3, 0.04, BORDER_DEFAULT );
}
//*****************************************************************************************
void t_FaceDetect(Mat &I){
	Mat dst;
	std::vector<Rect> faces;
	equalizeHist( I, dst );
	if( !face_cascade.load( face_cascade_name ) ){ 
    	cout<<"--(!)Error loading face cascade\n"; 
    	return; 
    }           
	face_cascade.detectMultiScale( dst, faces, 1.1, 2, 0|CASCADE_SCALE_IMAGE, Size(30, 30) );

}
//*****************************************************************************************
inline void test(void (*f) (Mat&),TMARK m){

	for(int i = 0;i<4;i++)
		for(int n = 0;n < TESTLOOP;n++){
		
			ref->MARK(MWIDTH,image[i].cols);
			ref->MARK(MHEIGHT,image[i].rows);
			ref->MARK(m);
			f(image[i]);
			ref->MARK(MNONE);
	}
}
//*****************************************************************************************
int TProfiler::main(int argc, char *argv[]){

	ref=this;
	MARK(MSTART);
	MARK(MINIT);
	
	image[0] = imread("0.1mpx.bmp",CV_LOAD_IMAGE_GRAYSCALE);
	image[1] = imread("0.25mpx.bmp",CV_LOAD_IMAGE_GRAYSCALE);
	image[2] = imread("1mpx.bmp",CV_LOAD_IMAGE_GRAYSCALE);
	image[3] = imread("6mpx.bmp",CV_LOAD_IMAGE_GRAYSCALE);
	
	
	test(t_DFT,MDFT);
	test(t_Smooth,MSMOOTH);	
	test(t_EqualizeHist,MHIST);
	test(t_Threshold,MTHRESH);
	test(t_Sobel,MSOBEL);	
	test(t_Transform,MTRANS);	
	test(t_HoughLines,MHOUGH);
	test(t_BilateralFilter,MBILAT); 
	test(t_Haris,MHARIS); 
	test(t_FaceDetect,MDETECT); 
return 0;
}
