/*
ImageDatabase
Represents a database of images and an associated
image description
*/
#ifdef _CH_
#pragma package <opencv>
#endif

#ifndef _EiC
#include "cv.h"
#include "cvaux.h"
#include "highgui.h"
#endif

#include <stdio.h>
#include <string.h>
//#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
//#include <time.h>
#include <ctype.h>
#include <vector>
#include "ImageDatabase.h"
//#include "Histogram.h"
#include "feature.h"
#include "edgeFeature.h"
#include "redFeature.h"

#define histsize 64
#define PI 3.141516
#define eohbins 6

//************************ CImageDatabase methods **************************
CImageDatabase::CImageDatabase()
{	
	m_nEntries = 0;		//number of entries in database
	num_positives = 0;	//number of positives in the database
	num_negatives = 0;	//number of negatives in the database
	num_features = 0;	//number of features in the database
	numSubs=0;
	alpha1= 0.8;		//weighted value of gradients/opponent
	integralBins=16;	//number of bins for integral images
	//EOHbins=NULL;
	numEOHbins=eohbins;
	violafeatures=0;
	edgefeatures=0;
	redfeatures=0;
}

CImageDatabase::~CImageDatabase()
{
	destroy();
	for (int di=0; di<positiveIntegrals.size(); ++di){			
		IplImage *e = (IplImage*) positiveIntegrals[di];
		cvReleaseImage(&e);
		delete e;
	}

	for (di=0; di<negativeIntegrals.size(); ++di){			
		IplImage *e = (IplImage*) negativeIntegrals[di];
		cvReleaseImage(&e);
		delete e;
	}

	for (di=0; di<redIntegrals.size(); ++di){			
		IplImage *e = (IplImage*) redIntegrals[di];
		cvReleaseImage(&e);
		delete e;
	}

	if (EOHbins!=NULL) {
		for (int y=0; y< num_positives + num_negatives; y++) {
			for (int z=0; z<numEOHbins; z++) {
				//IplImage *e= (IplImage*) EOHbins[y][z];
				cvReleaseImage(&EOHbins[y][z]);
			}
			//delete [] EOHbins[y];
		}
		//delete [] EOHbins;
	}
}

int CImageDatabase::getPosAndNeg() {
	return (num_positives + num_negatives);
}

// Load up the database file
// Return true on success, false otherwise

bool CImageDatabase::loadSubImages(const char *pstrFilename) {
	FILE *pInFile = fopen(pstrFilename, "rt");
	if(!pInFile)
		return false;

	while(true) {
		char strLine[256];
		// Read a line from the file
		if(fgets(strLine, 256, pInFile) == NULL)
			break;

		char strImageName[256];

		sscanf(strLine, "%s", strImageName);
		//printf("working : %s\n",strImageName);
		// Load the image file
		subs[numSubs] = cvLoadImage(strImageName,1);
		numSubs++;
	}

	fclose(pInFile);
	return true;
}

bool CImageDatabase::load1(const char *pstrFilename)
{
// Clean up any previous database
	destroy();
	
	// Load up the specified database file
	FILE *pInFile = fopen(pstrFilename, "rt");
	if(!pInFile)
		return false;

	bool bReadingFilename = true;

	while(true)
	{
		char strLine[256];
		// Read a line from the file
		if(fgets(strLine, 256, pInFile) == NULL)
			break;

		// If we find a '#' character, set it to NULL (since its a comment)
		int nStrLength= strlen(strLine);
		strLine[nStrLength-1]=strLine[nStrLength];

		// Only process the line if we have some valid information
		//nStrLength = strlen(strLine);
		if(nStrLength > 0)
		{   
			if(bReadingFilename)
			{
				//char strImageName[256];
				//sscanf(strLine, "%s", strImageName);
				//int strlength = strlen(strImageName);
				
				// Load the image file
				m_arrImage1[m_nEntries] = cvLoadImage(strLine,1);
				
				if(m_arrImage1[m_nEntries] == NULL)
				{
					printf("Cannot load \"%s\" image for database\n", strLine);
					fclose(pInFile);
					return false;
				}
				
				// Store the image name
				m_arrstrImageName[m_nEntries] = allocateString(strLine);
				if(m_arrstrImageName[m_nEntries] == NULL)
				{
					printf("Cannot store \"%s\" image name for database\n", strLine);
					fclose(pInFile);
					return false;
				}
				//bReadingFilename = false;
				m_arrstrDescription[m_nEntries] = allocateString(strLine);
				//m_arrstrDescription[m_nEntries] ="baba";
				m_nEntries++;
			}
		}
	}
	//printf("before close \n");
	fclose(pInFile);

	return true;
}
//pn=0 for load positives, 1 for load negatives
bool CImageDatabase::loadTraining(const char *pstrFilename, int pn) {

	// Load the specified database file
	FILE *pInFile = fopen(pstrFilename, "rt");
	if(!pInFile)
		return false;

	while(true)
	{
		char strLine[256];
		// Read a line from the file
		if(fgets(strLine, 256, pInFile) == NULL)
			break;

		// If we find a '#' character, set it to NULL (since its a comment)
		int nStrLength= strlen(strLine);
		strLine[nStrLength-1]=strLine[nStrLength];

		// Only process the line if we have some valid information
		if(nStrLength > 0) {  
			// Load the image file
			if (pn==0)
				positives[num_positives] = cvLoadImage(strLine,1);
			else
				negatives[num_negatives] = cvLoadImage(strLine,1);
			
			if((pn==0)&&(positives[num_positives] == NULL)) {
				printf("Cannot load \"%s\" image for database\n", strLine);
				fclose(pInFile);
				return false;
			}
			if((pn==1)&&(negatives[num_negatives] == NULL)) {
				printf("Cannot load \"%s\" image for database\n", strLine);
				fclose(pInFile);
				return false;
			}
			
			if (pn==0)
				num_positives++;
			else
				num_negatives++;
		}
	}
	fclose(pInFile);
	if (pn==0)
		printf("number of positives loaded is %i\n", num_positives);
	else 
		printf("number of negatives loaded is %i\n", num_negatives);
	return true;
}

bool CImageDatabase::loadFeatures(const char *pstrFilename, const char *featdesc, const char *edgefeat,
								  const char *redfeat, std::vector<feature*>& featureList) {
	// Load the specified database file of feature jpegs
	FILE *pInFile = fopen(pstrFilename, "rt");
	if(!pInFile)
		return false;
	// Load feature description file. should be same size (line count) as above file
	FILE *descfile = fopen(featdesc, "rt");
	if(!descfile)
		return false;

	while(true)//for every shape (basic feature)
	{
		char strLine[256];
		char featdescLine[256];	//line from desc file
		char featxfilelines[256];	//concrete feature desc files that need to be opened
		// Read a line from feature list file
		if(fgets(strLine, 256, pInFile) == NULL)	//if there are no more features: exit loop
			break;

		//printf("starting file %s \n\n", strLine);
		
		//remove unnecessary /n at end of line
		int nStrLength= strlen(strLine);
		strLine[nStrLength-1]=strLine[nStrLength];

		// Only process the line if we have some valid information
		if(nStrLength > 0) {  
			//try to load rectangle information from featdesc file

			fgets(featdescLine, 256, descfile);	//get line

			//remove unnecessary /n at end of line
			int nStrLength= strlen(featdescLine);	
			featdescLine[nStrLength-1]=featdescLine[nStrLength];

			//open coresponding feat rectangle descrition file
			FILE *featx = fopen(featdescLine, "rt");

			IplImage *e = cvLoadImage(strLine,1);
			feature *f= new feature(e);

			while (true) {
				if(!featx) {
					printf("could not find %s \n", featdescLine);
					break;
				}
				bool b=true;
				while (b) {
					if(fgets(featxfilelines, 256, featx) == NULL) {	//if no more lines
						//break;
						b=false;
					} else {
						char colour[10];	//white or black rectangles
						int x1=0;
						int y1=0;
						int x2=0;
						int y2=0;
						sscanf(featxfilelines, "%s%i%i%i%i", colour, &x1, &y1, &x2, &y2);
						int rectangle_colour=0;
						if (colour[0]=='w')
							rectangle_colour=0;
						if (colour[0]=='b')
							rectangle_colour=1;
						
						f->addRect2(x1, y1, x2, y2, rectangle_colour);
						//printf("printing rectangle points after they have been inserted into features\n");
						//f->printRectangles();
					}
				}
				f->findWH();
				featureList.push_back(f);
				break;
			}
			if (featx)
				fclose(featx);
			
			if(e == NULL) {
				printf("Cannot load \"%s\" image for database\n", strLine);
				fclose(pInFile);
				return false;
			}
		}
	}
	violafeatures=featureList.size();
	//feature *t=new edgeFeature();	//OK
	//featureList.push_back(t);		//OK
	fclose(pInFile);
	fclose(descfile);
	printf("number of violafeatures loaded is %i\n", featureList.size());

	// Load the specified database file of edge features
	FILE *edgelist = fopen(edgefeat, "rt");
	if(!edgefeat)
		return false;

	while(true) {//for every edge feature
		char strLine[256];
		char featdescLine[256];	//line from desc file
		// Read a line from feature list file
		if(fgets(strLine, 256, edgelist) == NULL)	//if there are no more features: exit loop
			break;

		//remove unnecessary /n at end of line
		int nStrLength= strlen(strLine);
		strLine[nStrLength-1]=strLine[nStrLength];

		if(nStrLength > 0) {  
			//try to load dominant edge information from featdesc file
			FILE *concEdgeFile = fopen(strLine, "rt");
			if(!concEdgeFile) {
				printf("could not find %s \n", strLine);
				break;
			}

			fgets(featdescLine, 256, concEdgeFile);	//get line

			//remove unnecessary /n at end of line
			int nStrLength= strlen(featdescLine);	
			featdescLine[nStrLength-1]=featdescLine[nStrLength];
			char colour[10];
			int x1=0;
			sscanf(featdescLine, "%s%i", colour, &x1);

			int x2=-1;
			if(fgets(featdescLine, 256, concEdgeFile) != NULL) {
				sscanf(featdescLine, "%s%i", colour, &x2);
			}

			//IplImage *e = cvLoadImage(strLine,1);
			feature *f= new edgeFeature(x1, x2);
			f->width=2;
			f->height=2;
			featureList.push_back(f);
			
			if (concEdgeFile)
				fclose(concEdgeFile);
			
		}
	}
	edgefeatures=featureList.size()-violafeatures;
	printf("number of edgefeatures loaded is %i\n", edgefeatures);

	fclose(edgelist);

	// Load the specified database file of red features
	FILE *redlist = fopen(redfeat, "rt");
	if(!redfeat)
		return false;

	while(true) {//for every red feature
		char strLine[256];
		char featdescLine[256];	//line from desc file
		// Read a line from feature list file
		if(fgets(strLine, 256, redlist) == NULL)	//if there are no more features: exit loop
			break;

		//remove unnecessary /n at end of line
		int nStrLength= strlen(strLine);
		strLine[nStrLength-1]=strLine[nStrLength];

		if(nStrLength > 0) {  
			//try to load dominant edge information from featdesc file
			FILE *concRedFile = fopen(strLine, "rt");
			if(!concRedFile) {
				printf("could not find %s \n", strLine);
				break;
			}

			fgets(featdescLine, 256, concRedFile);	//get line

			//remove unnecessary /n at end of line
			int nStrLength= strlen(featdescLine);	
			featdescLine[nStrLength-1]=featdescLine[nStrLength];
			char colour[10];
			int x1=0;
			sscanf(featdescLine, "%s%i", colour, &x1);

			//IplImage *e = cvLoadImage(strLine,1);
			feature *f= new redFeature(x1);
			f->width=2;
			f->height=2;
			featureList.push_back(f);
			
			if (concRedFile)
				fclose(concRedFile);
			
		}
	}
	redfeatures=featureList.size()-violafeatures-edgefeatures;
	printf("number of redfeatures loaded is %i\n", redfeatures);

	fclose(redlist);

	return true;
}

bool CImageDatabase::createIntegrals() {
	for (int i=0; i<num_positives; i++) {
		//IplImage *integi;
		if (positives[i]->nChannels>1) {	//if positives[i] not greyscale
			IplImage *testImage;	
			CvSize subsize = cvGetSize(positives[i]);
			testImage=cvCreateImage(subsize, IPL_DEPTH_8U, 1);
			cvCvtColor( positives[i], testImage, CV_BGR2GRAY);
			IplImage *integi=CVIntegral(testImage);
			positiveIntegrals.push_back(integi);
			cvReleaseImage(&testImage);
		} else{
			//cvReleaseImage(&t1);
			IplImage *integi=CVIntegral(positives[i]);
			positiveIntegrals.push_back(integi);
		}
		//positiveIntegrals.push_back(integi);
	}
	
	for (i=0; i<num_negatives; i++) {
		//IplImage *integi;
		if (negatives[i]->nChannels>1) {	//if negatives[i] not greyscale
			IplImage *testImage;	
			CvSize subsize = cvGetSize(negatives[i]);
			testImage=cvCreateImage(subsize, IPL_DEPTH_8U, 1);
			cvCvtColor( negatives[i], testImage, CV_BGR2GRAY);
			IplImage *integi=CVIntegral(testImage);
			negativeIntegrals.push_back(integi);
			cvReleaseImage(&testImage);
		} else{
			//cvReleaseImage(&t1);
			IplImage *integi=CVIntegral(negatives[i]);
			negativeIntegrals.push_back(integi);
		}
		//negativeIntegrals.push_back(integi);
	}
	return true;
}

bool CImageDatabase::createEOHIntegrals() {
	
	CvSize size;
	size = cvSize(positives[0]->width,positives[0]->height);
	//for (int y=0; y<num_positives + num_negatives; y++) {
	//	EOHbins[y]= IplImage* [eohbins];
	//}
	for (int mloop=0; mloop<num_positives + num_negatives; mloop++) {
		IplImage *temp, *dx_image, *dy_image;
		if (mloop<num_positives)
			temp=positives[mloop];
		else 
			temp=negatives[mloop-num_positives];

		IplImage *process;
		
		int dms = temp->nChannels;	
		if (dms>1) {				//if not grayscale
			process = cvCreateImage( size, IPL_DEPTH_8U, 1);
			cvCvtColor( temp, process, CV_BGR2GRAY);
		} else {
			process=cvCloneImage(temp);
		}
		//cvReleaseImage(&temp);

		//now we have a greyscale image to work with
		dx_image = cvCreateImage( size, IPL_DEPTH_16S, 1 );
		dy_image = cvCreateImage( size, IPL_DEPTH_16S, 1 );
		//dest = cvCreateImage( size, IPL_DEPTH_16S, 1 );
		
		cvSobel( process, dx_image, 0, 1, 3 );
		cvSobel( process, dy_image, 1, 0, 3 );

		cvReleaseImage(&process);
		/*cvNamedWindow("best", 1);
		cvShowImage( "best", dx_image);
		cvWaitKey(0);
		cvDestroyWindow("best");*/

		float binsize=(180.0)/(float)numEOHbins;	//physical size of each bin
		IplImage *EObins[eohbins];
		for (int m=0; m<eohbins; m++) {
			EObins[m]=cvCreateImage( size, IPL_DEPTH_16S, 1 );
			cvSetZero(EObins[m]);
		}
		
		for (int i = 0; i < dx_image->width; i++) {
			for (int j = 0; j < dx_image->height; j++) {
				float dx = ((short*)(dx_image->imageData + dx_image->widthStep*j))[i];
				float dy = ((short*)(dy_image->imageData + dy_image->widthStep*j))[i];

				float angle = (float)(180.0/PI)*(atan2(dy,dx));
				if (angle<0) angle +=180.0;
				if (angle > 180.0) angle -= 180.0;

				int index = (int)(angle / binsize);	//index is from 0..8;

				float value = sqrt(dx * dx + dy * dy);
				if (value<30)		//threshold
					value=0;

				((short*)(EObins[index]->imageData + EObins[index]->widthStep*j))[i]=value;
				//((short*)(dest->imageData + dest->widthStep*j))[i]=value;
			}
		}

		cvReleaseImage(&dx_image);
		cvReleaseImage(&dy_image);

		IplImage *EOintegrals[eohbins];	//list of integral images for orientations
		for (m=0; m<eohbins; m++) {
			EOintegrals[m]=EOHIntegral(EObins[m]);
			cvReleaseImage(&EObins[m]);
		}

		for (int mil=0; mil< eohbins; mil++) {
			EOHbins[mloop][mil]=EOintegrals[mil];
		}

		/*cvNamedWindow("best", 1);
		cvShowImage( "best", EObins[3]);
		cvWaitKey(0);
		cvDestroyWindow("best");*/

	}

	return true;
}

bool CImageDatabase::createRedIntegrals() {
	CvSize size;
	size = cvSize(positives[0]->width,positives[0]->height);

	for (int mloop=0; mloop<num_positives + num_negatives; mloop++) {
		IplImage *temp;
		if (mloop<num_positives)
			temp=positives[mloop];
		else 
			temp=negatives[mloop-num_positives];

		IplImage* r_plane = cvCreateImage( size, 8, 1 );
		IplImage* g_plane = cvCreateImage( size, 8, 1 );
		IplImage* b_plane = cvCreateImage( size, 8, 1 );
		
		cvCvtPixToPlane( temp, b_plane, g_plane, r_plane, NULL );
		
		IplImage* redspace = cvCreateImage(size, IPL_DEPTH_16S, 1);	//4R - 3G + B image

		for (int i = 0; i < temp->width; i++) {
			for (int j = 0; j < temp->height; j++) {
				float r = ((uchar*)(r_plane->imageData + r_plane->widthStep*j))[i];
				float g = ((uchar*)(g_plane->imageData + g_plane->widthStep*j))[i];
				float b = ((uchar*)(b_plane->imageData + b_plane->widthStep*j))[i];

				float value=4*r - 3*g + b;

				((short*)(redspace->imageData + redspace->widthStep*j))[i]=value;
			}
		}

		IplImage *integ=EOHIntegral(redspace);
		redIntegrals.push_back(integ);
		cvReleaseImage(&redspace);

		cvReleaseImage(&r_plane);
		cvReleaseImage(&g_plane);
		cvReleaseImage(&b_plane);
		/*cvNamedWindow("best", 1);
		cvShowImage( "best", EObins[2]);
		cvWaitKey(0);
		cvDestroyWindow("best");*/
	}
	return true;
}

IplImage* CImageDatabase::createRedIntegral(IplImage *in) {
	CvSize size;
	size = cvSize(in->width,in->height);
	
	IplImage* r_plane = cvCreateImage( size, 8, 1 );
	IplImage* g_plane = cvCreateImage( size, 8, 1 );
	IplImage* b_plane = cvCreateImage( size, 8, 1 );
	
	cvCvtPixToPlane( in, b_plane, g_plane, r_plane, NULL );
	
	IplImage* redspace = cvCreateImage(size, IPL_DEPTH_16S, 1);	//4R - 3G + B image
	
	for (int i = 0; i < in->width; i++) {
		for (int j = 0; j < in->height; j++) {
			float r = ((uchar*)(r_plane->imageData + r_plane->widthStep*j))[i];
			float g = ((uchar*)(g_plane->imageData + g_plane->widthStep*j))[i];
			float b = ((uchar*)(b_plane->imageData + b_plane->widthStep*j))[i];
			
			float value=4*r - 3*g + b;
			
			((short*)(redspace->imageData + redspace->widthStep*j))[i]=value;
		}
	}
	
	IplImage *integ=EOHIntegral(redspace);

	cvReleaseImage(&redspace);
	cvReleaseImage(&r_plane);
	cvReleaseImage(&g_plane);
	cvReleaseImage(&b_plane);


	return integ;
}

void CImageDatabase::createEOHIntegral(IplImage *in, IplImage **outs, IplImage *CumulativeIntensities) {
	CvSize size;
	size = cvSize(in->width,in->height);
	
	IplImage *dx_image, *dy_image;
	
	IplImage *process;
	
	int dms = in->nChannels;	
	if (dms>1) {				//if not grayscale
		process = cvCreateImage( size, IPL_DEPTH_8U, 1);
		cvCvtColor( in, process, CV_BGR2GRAY);
	} else {
		process=cvCloneImage(in);
	}

	//now we have a greyscale image to work with
	dx_image = cvCreateImage( size, IPL_DEPTH_16S, 1 );
	dy_image = cvCreateImage( size, IPL_DEPTH_16S, 1 );
	//dest = cvCreateImage( size, IPL_DEPTH_16S, 1 );
	
	cvSobel( process, dx_image, 0, 1, 3 );
	cvSobel( process, dy_image, 1, 0, 3 );
	
	cvReleaseImage(&process);
	
	float binsize=(180.0)/(float)numEOHbins;	//physical size of each bin
	IplImage *EObins[eohbins];
	for (int m=0; m<eohbins; m++) {
		EObins[m]=cvCreateImage( size, IPL_DEPTH_16S, 1 );
		cvSetZero(EObins[m]);
	}

	IplImage *CuIn=cvCreateImage( size, IPL_DEPTH_16S, 1 );	//init
	cvSetZero(CuIn);	//clear array
	
	for (int i = 0; i < dx_image->width; i++) {
		for (int j = 0; j < dx_image->height; j++) {
			float dx = ((short*)(dx_image->imageData + dx_image->widthStep*j))[i];
			float dy = ((short*)(dy_image->imageData + dy_image->widthStep*j))[i];
			
			float angle = (float)((180.0/PI)*(atan2(dy,dx)));
			angle = angle+90/numEOHbins;

			if (angle<0) angle +=180.0;
			if (angle > 180.0) angle -= 180.0;
			
			int index = (int)(angle / binsize);	//index is from 0..8;
			
			float value = sqrt(dx * dx + dy * dy);
			if (value<80)		//threshold
				value=0;
			
			((short*)(EObins[index]->imageData + EObins[index]->widthStep*j))[i]=value;
			((short*)(CuIn->imageData + CuIn->widthStep*j))[i]+=value;
			//((short*)(dest->imageData + dest->widthStep*j))[i]=value;
		}
	}
	
	cvReleaseImage(&dx_image);
	cvReleaseImage(&dy_image);

	/*cvNamedWindow("best", 1);
	cvShowImage( "best", EObins[4]);
	cvWaitKey(0);
	cvDestroyWindow("best");*/

	//IplImage *EOintegrals[eohbins];	//list of integral images for orientations
	for (m=0; m<eohbins; m++) {
		outs[m]=EOHIntegral(EObins[m]);
		cvReleaseImage(&EObins[m]);
	}

	if (CumulativeIntensities!=NULL)
		cvReleaseImage(&CumulativeIntensities);
	CumulativeIntensities=EOHIntegral(CuIn);
	cvReleaseImage(&CuIn);
	
	/*cvNamedWindow("best", 1);
	cvShowImage( "best", EObins[0]);
	cvWaitKey(0);
	cvDestroyWindow("best");*/
	

}

IplImage* CImageDatabase::getEOHbin(int i, int j) {
	return EOHbins[i][j];
}

IplImage* CImageDatabase::CVIntegral(IplImage *pImageToMatch) {
	CvSize size;
	IplImage *ret;
	size = cvSize(pImageToMatch->width,pImageToMatch->height);
	ret = cvCreateImage( size, IPL_DEPTH_32F, 1);
	for (int e=0; e<pImageToMatch->width; e++) {
		for (int y=0; y<pImageToMatch->height; y++) {
			((float*)(ret->imageData + y*ret->widthStep))[e]=0;
		}
	}	//initialization done;

	float s=0;
	float cur=0;
	for (int x=0; x< ret->width; x++) {
		s=0;
		for (int y=0; y< ret->height; y++) {
			s=s+((uchar*)(pImageToMatch->imageData + y*pImageToMatch->widthStep))[x];
			if ((x-1)<0) {
				cur=0;
			}else { 
				cur=((float*)(ret->imageData + y*ret->widthStep))[x-1];
			}
			((float*)(ret->imageData + y*ret->widthStep))[x]=(cur+s);
		}
	}

	return ret;
}

IplImage* CImageDatabase::EOHIntegral(IplImage *pImageToMatch) {
	CvSize size;
	IplImage *ret;
	size = cvSize(pImageToMatch->width,pImageToMatch->height);
	ret = cvCreateImage( size, IPL_DEPTH_32F, 1);
	for (int e=0; e<pImageToMatch->width; e++) {
		for (int y=0; y<pImageToMatch->height; y++) {
			((float*)(ret->imageData + y*ret->widthStep))[e]=0;
		}
	}	//initialization done;

	float s=0;
	float cur=0;
	for (int x=0; x< ret->width; x++) {
		s=0;
		for (int y=0; y< ret->height; y++) {
			s=s+((short*)(pImageToMatch->imageData + y*pImageToMatch->widthStep))[x];
			if ((x-1)<0) {
				cur=0;
			}else { 
				cur=((float*)(ret->imageData + y*ret->widthStep))[x-1];
			}
			((float*)(ret->imageData + y*ret->widthStep))[x]=(cur+s);
		}
	}

	return ret;
}

bool CImageDatabase::loadSeries(const char *series, std::vector<training*>& trList) {

	FILE *ser = fopen(series, "rt");
	if(!ser)
		return false;

	while(true) {		//for every line in the file (WC) 
		char strLine[256];

		// Read a line from feature list file
		if(fgets(strLine, 256, ser) == NULL)	//if there are no more features: exit loop
			break;
		 
		//remove unnecessary /n at end of line
		int nStrLength= strlen(strLine);
		strLine[nStrLength-1]=strLine[nStrLength];

		// Only process the line if we have some valid information
		if(nStrLength > 0) {  
			//try to load WC from file
			char feat[7];
			int featno=0;
			char x[2];
			int offsetx=0;
			char y[2];
			int offsety=0;
			char scax[10];
			int scalex=0;
			char scay[10];
			int scaley=0;
			char ce[3];
			float CE=0;
			char thet[10];
			float theta=0;
			char sign[10];
			int s=0;
			char al[10];
			float alpha=0;
			char nmm[6];
			float nm;
			char pmm[6];
			float pm;

			sscanf(strLine, "%s%i%s%i%s%i%s%i%s%i%s%f%s%f%s%i%s%f%s%f%s%f", feat, &featno, x, &offsetx,
				y, &offsety, scax, &scalex, scay, &scaley, ce, &CE, thet, &theta, sign, &s, al, &alpha,
				nmm, &pm, pmm, &nm);

			training *tr=new training();
			tr->settraining(featno, offsetx, offsety, scalex, scaley);
			tr->ce=CE;
			tr->theta=theta;
			tr->s=s;
			tr->alpha=alpha;
			tr->pm=pm;
			tr->nm=nm;

			trList.push_back(tr);

		}
	}

	fclose(ser);
	return true;
}


void CImageDatabase::destroy()
{
	for(int ii = 0;ii < m_nEntries;ii++)
	{
		if(m_arrstrImageName[ii] != NULL)
		{
			freeString(m_arrstrImageName[ii]);
			m_arrstrImageName[ii] = NULL;
		}

		if(m_arrstrDescription[ii] != NULL)
		{
			freeString(m_arrstrDescription[ii]);
			m_arrstrDescription[ii] = NULL;
		}
	}

	m_nEntries = 0;
}

// Get the number of entries in the database
int CImageDatabase::getNumberOfEntries()
{
	return m_nEntries;
}

int CImageDatabase::getNumberOfSubs()
{
	return numSubs;
}

// Get the specified image at the given database index
IplImage *CImageDatabase::getImage1(int nImageIndex)
{
	if(nImageIndex < 0 || nImageIndex >= m_nEntries)
		return NULL;

	return m_arrImage1[nImageIndex];
}

IplImage *CImageDatabase::getSub(int nImageIndex)
{
	if(nImageIndex < 0 || nImageIndex >= numSubs)
		return NULL;

	return subs[nImageIndex];
}

// Get the name of the image at the given database index
char *CImageDatabase::getImageName(int nImageIndex)
{
	if(nImageIndex < 0 || nImageIndex >= m_nEntries)
		return NULL;

	return m_arrstrImageName[nImageIndex];
}

// Get the image description at the given database index
char *CImageDatabase::getDescription(int nImageIndex)
{
	if(nImageIndex < 0 || nImageIndex >= m_nEntries)
		return NULL;

	return m_arrstrDescription[nImageIndex];
}

std::vector<IplImage*>& CImageDatabase::getPositiveIntegrals(){
	return positiveIntegrals;
}

std::vector<IplImage*>& CImageDatabase::getNegativeIntegrals(){
	return negativeIntegrals;
}

void CImageDatabase::integralImage(IplImage *pImageToMatch, int index, int subcount){
	CvSize size;
	size=cvGetSize(subs[subcount]);
	CvHistogram *cartest;
	float range[]={0,255}; 
	float* ranges[] = {range};
	int abins=integralBins;
	int carhist_size[] = {abins};
	cartest = cvCreateHist(1, carhist_size, CV_HIST_ARRAY, ranges, 1);	//decleration of test histogram
	
	IplImage *t1;
	IplImage *testImage;
	testImage=cvCreateImage(size, IPL_DEPTH_8U, 1);
	t1=subs[subcount];
	//testImage=subs[subcount];
	if (t1->nChannels>1)
		cvCvtColor( t1, testImage, CV_BGR2GRAY );
	else 
		testImage=cvCloneImage(t1);

	if (pImageToMatch->nChannels>1)
		cvCvtColor( pImageToMatch, pImageToMatch, CV_BGR2GRAY );
	cvCalcHist( &testImage, cartest, 0, 0 );	//create histogram for test image

	printf("intImage has size %i x %i \n", pImageToMatch->width, pImageToMatch->height);

	for (int y=0; y<INTEGRAL_IMAGE_BINS; y++){
		bins[y] = cvCreateImage( cvSize(pImageToMatch->width+1, pImageToMatch->height+1),  IPL_DEPTH_32S, 1);
		sels[y] = cvCreateImage( cvSize(pImageToMatch->width, pImageToMatch->height),  IPL_DEPTH_8U, 1);
	}

	for (int i=0; i<pImageToMatch->width; i++) {
		for (int j=0; j<pImageToMatch->height; j++) {
			for (int y=0; y<INTEGRAL_IMAGE_BINS; y++) {
				((uchar*)(sels[y]->imageData + j*sels[y]->widthStep))[i]=0;		//initialize integral images
			}
		}
	} 

	int binwidth=255/integralBins;	//range of each bin
	float binw=(float)255/integralBins;
	if ((float)(binw-binwidth)>0)
		binwidth++;
	int range1=binwidth;
	//int	range2=0;
	int *binranges= new int[integralBins];
	for (int g=0;g<integralBins;g++) {
		binranges[g]=binwidth;
		//printf("binranges[%i]: %i\n", g, binwidth);
		binwidth+=range1;
	}

	for (i=0; i<pImageToMatch->width; i++) {
		for (int j=0; j<pImageToMatch->height; j++) {

			int selsIndex=0;
			uchar p=((uchar*)(pImageToMatch->imageData + pImageToMatch->widthStep*j))[i];
			
			selsIndex=p/range1;

			((uchar*)(sels[selsIndex]->imageData + j*sels[selsIndex]->widthStep))[i]=1;
		}
	}

	for (int u=0; u<INTEGRAL_IMAGE_BINS; u++) 
		cvIntegral(sels[u], bins[u], 0, 0);

	int testcarwidth=testImage->width;		//with and height of test image. (car1test.jpg)

	int testcarheight=testImage->height;
	int carwidth=pImageToMatch->width;		//with and height of com a=image (0001.jpg)
	int carheight=pImageToMatch->height;

	CvHistogram *temphist;					//temporary comparison hist(sliding window histogram)
	temphist = cvCreateHist(1, carhist_size, CV_HIST_ARRAY, ranges, 1);

	double max=0;		//correlation strength comparison
	int tempi=0;
	int tempj=0;
	int tempfactor=0;
	int factors[7] = { -15, -10, -5, 0, 5, 10, 15};
	double ratio=(double)testcarwidth/testcarheight;
	//double ratio=1;

	for (int r=0; r<7; r++) {							//3 window sizes
		int testcarheight1=testcarheight+factors[r];
		int testcarwidth1=(int)(testcarwidth+(factors[r]*ratio));

		float normfactor = (float)(testcarwidth1*testcarheight1)/(testcarwidth*testcarheight);
		for (int i=0; i<(carwidth-testcarwidth1+1); i++) {			//main comparison loop
			for (int j=0; j<(carheight-testcarheight1+1); j++) {

				int corner1 = i+testcarwidth1;
				int corner2 = j+testcarheight1;

				for (int m=0; m<integralBins; m++) {			//creation of temphist

					int *A= (int*)(bins[m]->imageData + j*bins[m]->widthStep) + i;
					int *B= (int*)(bins[m]->imageData + (corner2)*bins[m]->widthStep) + (corner1);
					int *C= (int*)(bins[m]->imageData + j*bins[m]->widthStep) + (corner1);
					int *D= (int*)(bins[m]->imageData + (corner2)*bins[m]->widthStep) + i;
					int sum = *A + *B - *C - *D;
					//printf(" sum for i: %i j: %i is %i\n", i, j, sum);

					*((float*)(cvPtr1D( (temphist)->bins, (m), 0 )))=(float)(sum*normfactor);
				}

				double tempscore=cvCompareHist( temphist, cartest, CV_COMP_CORREL);
				//printf (" tempscore: %lf \n", tempscore);
				if (tempscore>max) {
					max = tempscore;
					tempi=i;
					tempj=j;
					tempfactor=factors[r];
				}
			}
		}
	}

	printf ("best match occurs at location: %i %i with score %lf\n", tempi, tempj, max);

	//cvRectangle( pImageToMatch, cvPoint(tempi, tempj), cvPoint(tempi+testcarwidth, tempj+testcarheight), CV_RGB(0.8,0.8,0.8),1 );
	cvRectangle( pImageToMatch, cvPoint(tempi, tempj), cvPoint((int)(tempi+testcarwidth+tempfactor*ratio), tempj+testcarheight+tempfactor), CV_RGB(250,250,250) ,2 );

	/*FILE *pInFile = fopen("bin4.txt", "w");

	for (i=0; i<bins[4]->width; i++) {
		for (int j=0; j<bins[4]->height; j++) {
	        int *pq0 = 0;
			pq0 = (int*)(bins[4]->imageData + j*bins[4]->widthStep) + i;
			fprintf(pInFile, " %i ", *pq0);
		}
		fprintf(pInFile, "\n");
	}

	fclose(pInFile);*/

	//cvNamedWindow( "Integrals", 1 );
	//cvShowImage( "Integrals", testImage );
	cvShowImage( "target",  pImageToMatch);
	//cvWaitKey(0);
	//cvDestroyWindow( "Integrals" );
	//cvReleaseImage(&testImage);
	cvReleaseHist(&cartest);
	cvReleaseHist(&temphist);
	cvReleaseImage(&t1);
	for (y=0; y<INTEGRAL_IMAGE_BINS; y++){
		cvReleaseImage(&bins[y]);
		cvReleaseImage(&sels[y]);
	}
	delete [] binranges;
}

void CImageDatabase::exit(){
	for(int ii = 0;ii < m_nEntries;ii++){
		cvReleaseImage(&m_arrImage1[ii]);
	}
	for(int yy=0; yy<numSubs; yy++) {
		cvReleaseImage(&subs[yy]);
	}
	for(int zz=0; zz<num_positives; zz++) {
		cvReleaseImage(&positives[zz]);
	}
	for(zz=0; zz<num_negatives; zz++) {
		cvReleaseImage(&negatives[zz]);
	}
}

double CImageDatabase::avGrad(double *ar){
	double x=0;
	for (int i=0;i<5;i++)
		x+=ar[i];
	x=x/5.0;
	return x;
}

int CImageDatabase::getMin1(int a, int b)
{
	int ret=0;
	if (a<=b)
		ret=a;
	else 
		ret=b;
	return ret;
}

int CImageDatabase::getMax1(int a, int b)
{
	int ret=0;
	if (b<=a)
		ret=a;
	else 
		ret=b;
	return ret;
}

int CImageDatabase::abs1(int a, int b)
{
	int cur=a-b;
	if (cur<0)
		cur=cur*(-1);
	return cur;
}

//*************************** PRIVATE MEMBERS *****************************
// Allocate a string with the specified number of characters

char *CImageDatabase::allocateString(int nSize)
{
	if(nSize <= 0)
		return NULL;
	char *pString = new char[nSize];
	return pString;
}

// Allocate a new string which is a copy of the specified string
char *CImageDatabase::allocateString(const char *pString)
{
	int nSize = strlen(pString);
	char *pNewString = allocateString(nSize + 1);
	if(pNewString != NULL)
		strcpy(pNewString, pString);
	return pNewString;
}

// Free up the specified string
void CImageDatabase::freeString(char *pString)
{
	if(pString != NULL)
		delete [] pString;
}

#ifdef _EiC
main(1,"ImageDatabase.cpp");
#endif
	
