#include "cvManager.h"

cvManager::cvManager(){
	bSetup				= false;
	which				= 0;	
}

//changing cameras or switching from/to the camera mode
//requires the app to be restarted - mabe we can change this?
//---------------------------		
void cvManager::setupCamera(int deviceNumber, int width, int height){
	VG.setVerbose(true);
	//VG.setDeviceID(deviceNumber);
	
	
	#ifdef CVM_USE_SEE_SAW
		VG.initGrabber(640,480);
		//VideoFramePreStretch.allocate(720,576);
		W = width;
		H = height;	
	#else
		
		VG.initGrabber(width, height);
		W = VG.width;
		H = VG.height;	
	#endif
	
	
	
	
			
	bCameraSetup = true;
	which = 2;

	setupCV();
}
		
//same as above - from/to using test movies
//requires a restart
//---------------------------		
void cvManager::setupVideo(string videoPath){
	
	VP.loadMovie(videoPath);
	VP.play(); 
	VP.setPosition(0.0);
	VP.setSpeed(0.90);
	VP.setUseTexture(true);
	W = VP.width;
	H = VP.height;
	bVideoSetup = true;
	which = 1;
	
	setupCV();
}

//good for adjusting the color balance, brightness etc
//---------------------------		
void cvManager::openCameraSettings(){
	if(bCameraSetup)VG.videoSettings();			
}

//---------------------------		
void cvManager::useCamera(){
	if(bCameraSetup)which = 2;	
}		

//---------------------------		
void cvManager::useVideo(){
	if(bVideoSetup)which = 1;	
}	


//do all our openCV allocation
//---------------------------		
void cvManager::setupCV(){
	
	if(bSetup) return;

	//our openCV inits
	VideoFrame.allocate(W, H);
	PresenceFrame.allocate(W, H);
	GreyFrame.allocate(W, H);
	ImageFrame.allocate(W, H);
	
	#ifdef CVM_USE_SEE_SAW
		VideoFramePreStretch.allocate(640,480);
	#endif
	
	bSetup = true;
}

//---------------------------		
void cvManager::passInImageToFindCardsIn(ofImage &imgToLookAt){
	ImageFrame.setFromPixels(imgToLookAt.getPixels(), W, H);
}


//standard video processing
//---------------------------		
void cvManager::processFrame(int threshold, bool bUseImageNotVideo){


	///////////////////////////////////////////////////////////
	// Part 1 - get the video data
	///////////////////////////////////////////////////////////
	
	//pointer to our incoming video pixels			
	unsigned char * pixCam;

	if (bUseImageNotVideo == false){
		//either grab pixels from video or grab from camera
		if(which == 1){
			VP.idleMovie();	
			pixCam 	= VP.getPixels();
		}
		else 
		if(which == 2){
			VG.grabFrame();
			pixCam 	= VG.getPixels();		
		}else{
			return; 			
		}
	} else {
		// get the pixels out of an image, useful for the card loading, or getting cards from a still frame.
		// use passInImageToFindCardsIn, and the default param: bUseImageNotVideo
		pixCam 	= ImageFrame.getPixels();  
	}
	///////////////////////////////////////////////////////////
	// Part 2 - load into openCV and make greyscale
	///////////////////////////////////////////////////////////
	
	
	#ifdef CVM_USE_SEE_SAW
		// checking....
		//VideoFramePreStretch.setFromPixels(pixCam, 640,480);
		//VideoFrame.scaleIntoMe(VideoFramePreStretch, CV_INTER_AREA );
		
		VideoFrame.setFromPixels(pixCam, 640,480);
		//VideoFrame.scaleIntoMe(VideoFramePreStretch, CV_INTER_AREA );
	
	#else
		VideoFrame.setFromPixels(pixCam,640,480);
	#endif
	
	
	
	//VideoFrame.setFromPixels(pixCam, W, H);
	GreyFrame.setFromColorImage(VideoFrame);
	
	///////////////////////////////////////////////////////////
	// Part 3 - do thresholding
	///////////////////////////////////////////////////////////
	PresenceFrame = GreyFrame;	
	PresenceFrame.threshold(threshold);
	//PresenceFrame.erode_3x3();

	
}
		
//here we clean up obvious bad blobs
//add any stuff you can to get rid of blobs that don't fit the profile
//theo - this seems pretty card specific wouldn't be a bad idea to move it to a seperate class?
//---------------------------		
vector <ofxCvBlob> cvManager::findBlobs(int minSize, int maxSize){
			
	vector <ofxCvBlob> goodBlobs;
	goodBlobs.clear();

	// find the largest blobs of possible candidates 
	//OPTIMIZE - resample contour after we get it back?
	int numBlobs = Contour.findContours(PresenceFrame, minSize, maxSize, 50, false, false);  
	
	if( numBlobs == 0){
		return goodBlobs;
	}
	
	//we go through and get rid of blobs that aren't a good match
	for(int j = 0; j < numBlobs; j++){

		// theo - don't think we need this as min blob size takes care of it
		//if(Contour.blobs[j].area < MIN_CARD_AREA){
		//	continue;
		//}
		
		/*	GET RID OF COMPLEX BLOBS
			if the length of the contour is longer than the perimter of the bounding box
			then we can skip it. this gets rid of blobs that have concave parts to them
			good for getting rid of hands and other complex shapes. 
		*/
		float perimBox = Contour.blobs[j].boundingRect.width*2 + Contour.blobs[j].boundingRect.height*2;
		if( perimBox < Contour.blobs[j].length ){
			continue;
		}
		
		goodBlobs.push_back(Contour.blobs[j]);
	}
		
	return goodBlobs;
} 
		
//--------------------------
void cvManager::toggleVideoPlayback(){
	if(VP.getSpeed() == 0.0){
		VP.setSpeed(1.0);
	}else{
		VP.setSpeed(0.0);
	}
}

		
//---------------------------				
void cvManager::draw(float x, float y, int w, int h){
	ofSetColor(255, 255, 255);
	VideoFrame.draw(x, y, w, h);
}



