// VideoTool.cpp : Defines the entry point for the console application.

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <tchar.h>
#include <math.h>
#include <time.h>
#include <cassert>
#include <queue>
// TODO: reference additional headers your program requires here

#include "cv.h"
#include "highgui.h"

bool alreadyHaveIt(int j,int imageIndices[12]);

// ARGH! why is this necessary ??
#define _NO_HMC_WINSOCK_
#include "SmallSocket.h"
#undef _NO_HMC_WINSOCK_

using namespace std;

int colorMode = 0;

int cheatMax = 75;
// Our Reds!
double RedHueMin = -0.2;
double RedHueMax = 1.0;
double RedSatMin = .04;
double RedSatMax = .37;
double RedValMin = .01;
double RedValMax = .45;

int X = 3;
int rMin = 5;
int RedMaxBy = 0;

// Our Greens!
double GreenHueMin = .25;
double GreenHueMax = .97;
double GreenSatMin = .01;
double GreenSatMax = .26;
double GreenValMin = .01;
double GreenValMax = .26;

int gMin = 5;
int GreenMaxBy = 10;

// Our Purples!
double PurpleHueMin = -2;
double PurpleHueMax = 1.49;
double PurpleSatMin = .01;
double PurpleSatMax = .99;
double PurpleValMin = .01;
double PurpleValMax = .99;

int PurpleColorMax = 80;
int bMin = -1;
int PurpleMaxBy = -10;

bool isRed(int r, int g, int b, double h, double s, double v);
bool isGreen(int r, int g, int b, double h, double s, double v);
bool isPurple(int r, int g, int b, double h, double s, double v);

// these are the two functions you'll need to write
void RGBtoHSV( double r, double g, double b, double *h, double *s, double *v );
void processRed( IplImage* frame, IplImage* f_p );
void processGreen( IplImage* frame, IplImage* f_p );
void processPurple( IplImage* frame, IplImage* f_p );
int processColor(IplImage* frame, IplImage* f_p);

bool omni = false;

void convertBin(int image[320][240], IplImage* setFrame);
int scanSet(int processed[320][240], IplImage* setPic);
int countSet(int image[340][240]);
int shapeSet(int image[320][240]);
int texSet(int image[320][240]);
void erode(int image[320][240]);
void dilate(int image[320][240]);

void setGlobals();  // the code appears at the very bottom of this file

char wndname[] = "VideoTool";
char wndname2[] = "Undistorted image";
char wndname3[] = "Painted image";

char *setwnd[] = {"set0","set1","set2","set3","set4","set5","set6","set7","set8","set9","set10","set11"};
// here, static refers to the fact that these variables
// are local to this file (they're not available in other files,
// which is safer because it allows reuse of their names)
static CvSize imageSize;
static CvPoint old_click_pt;
static CvPoint new_click_pt;
static double framenum;

// global points for drawing boxes, defining loops, etc.
static CvPoint pt1;
static CvPoint pt2;
static CvPoint pt3;
static CvPoint pt4;
static CvPoint pt5;
static CvPoint pt6;
static CvPoint pt7;

// global calibration data
static float* M;
static float* D;

// more global variables
// these are simply recording all the different states you
// can put the program in via the keyboard
static bool bmpRecording = false;
static bool capturing = true;
static bool getImageFromFile = false;
static bool getImageAgainFromFile = false;
static bool getImage0FromVideoBMPs = false;
static bool saveNextImage = false;
static bool quittingTime = false;
static bool detectRed = false;
static bool detectGreen = false;
static bool detectPurple = false;
static bool detectColor = false;
static bool showing_savedImage = false;
static bool saveOnlyOneImageToFile = true;
static bool firstTimeForSet = true;

static char* filename = new char[150];
static char* filename2 = new char[150];
static int frameNumber = 0;
static int keyCode = -1;

// pointers to images in memory
static IplImage *frame;
static IplImage* undis_frame;
static IplImage* undis_frame_painted;
static IplImage** setimages;
static CvArr* undisMap;

// globals for tuning parameters by keyboard...
static int blueValue = 255;

// just in case you'd like to use these...
inline double mymin(double a, double b) { return a<b?a:b; }

inline double mymax(double a, double b) { return a>b?a:b; }

// handle mouse clicks here
void mouse_callback(int event, int x, int y, int flags)
{
       if (event == CV_EVENT_LBUTTONDOWN)
       {
               // cout << "(x,y) = (" << x << "," << y << ")" << endl;

               // reset old_click_pt
               old_click_pt.x = new_click_pt.x;
               old_click_pt.y = new_click_pt.y;

               // get new click point -- note the coordinate change in y
               new_click_pt.x = x;  // coming in from the window system
               new_click_pt.y = imageSize.height-y;  // window system and images have different y axes
       }
}

// print pixel information
void pixelInformation(IplImage* f)
{
       if (f == NULL) return;

       // see if things have changed...
       if (new_click_pt.x != old_click_pt.x || new_click_pt.y != old_click_pt.y) // has it changed?
       {
               // draw a line from old to new
               // cvLine(frame,old_click_pt,new_click_pt,CV_RGB(255,0,0),/*thickness*/1,/*connectivity*/8);
               // set the old = the new
               old_click_pt.x = new_click_pt.x;
               old_click_pt.y = new_click_pt.y;
               // print the RGB values and coordinates of the newly clicked point:
               // note that blue is #0, green is #1, and red is #2 !!

               /* note that this uses the undistorted frame right here... */

               // this is insane!!!
               // see the processRed function for an explanation
               // of why we need "realy"
               int realy = new_click_pt.y;
               if (getImageAgainFromFile || getImageFromFile)
               {
                       realy = imageSize.height - realy;
               }
               uchar* pixel = cvPtr2D(f,realy,new_click_pt.x);

               cout << "(x,y) = (" << new_click_pt.x << "," << new_click_pt.y << ") with (r,g,b) = ("
                        << (int)(pixel[2]) << "," << (int)(pixel[1]) << "," << (int)(pixel[0]) << ")";

               double hue,sat,val;
               RGBtoHSV((double)pixel[2],(double)pixel[1],(double)pixel[0],&hue,&sat,&val);

               cout << " and (h,s,v) = (" << hue << "," << sat << "," << val << ")" << endl;
       }
}

// the thread for the server
DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
       char recvbuf[80];
       char sendbuf[80];

       string t("HI");
       SmallSocket SS(SmallSocket::SERVER);

   sprintf( recvbuf, "Server Started", *(DWORD*)lpParam );
   //MessageBox( NULL, szMsg, "ThreadFunc", MB_OK );

       while (true)
       {
               SS.receive(recvbuf,80);
               cout << "Received: " << recvbuf << endl;

               if (recvbuf[0] == 'q') {
                       SS.sendout("q",2);
                       // set a variable that tells it to quit...
                       quittingTime = true;
                   // cvReleaseCapture( &capture );
                       //      cvDestroyWindow("result");
                       break;
               }

               if (recvbuf[0] == 'e') {
                       // just an example of passing in more information
                       // and using sscanf to extract it
                       // sscanf(recvbuf,"q %lf %lf %lf ",&savedXforLog,&savedYforLog,&savedTforLog);
                       //
                       //the connection requires that something come back...
                       // note that we're sending two zeros every time here...
                       sprintf(sendbuf, "%d %d", 0, 0);
                       SS.sendout(sendbuf,80);
               }

               // pause for a bit...
               Sleep(10);
       }

   return 0;

}

int main( int argc, char** argv )
{
       // in case you want to log things...
       //ofstream logfile("logfile_out.txt");
       //ifstream loginfile("logfile_in.txt");

       double* currentHueMin = &RedHueMin;
       double* currentHueMax = &RedHueMax;
       double* currentSatMin = &RedSatMin;
       double* currentSatMax = &RedSatMax;
       double* currentValMin = &RedValMin;
       double* currentValMax = &RedValMax;

       // set up the globals...
       setGlobals();

       // start the server's thread
       // make sure that all imageprocessing is in main's thread
       DWORD dwThreadId, dwThrdParam = 1;
   HANDLE hThread;
   char szMsg[80];

   hThread = CreateThread(
       NULL,                        // default security attributes
       0,                           // use default stack size
       ThreadFunc,                  // thread function
       &dwThrdParam,                // argument to thread function
       0,                           // use default creation flags
       &dwThreadId);                // returns the thread identifier

   // Check the return value for success.
   if (hThread == NULL)
   {
       sprintf( szMsg, "CreateThread failed." );
       MessageBox( NULL, szMsg, "main", MB_OK );
   }

		for (int i=0 ; i<12 ; ++i)
			cvNamedWindow( setwnd[i], CV_WINDOW_AUTOSIZE );

       /*
        * set up the video windows
        */
       cvNamedWindow( wndname, CV_WINDOW_AUTOSIZE );
       cvNamedWindow( wndname2, CV_WINDOW_AUTOSIZE );
       cvNamedWindow( wndname3, CV_WINDOW_AUTOSIZE );

       /*
        * set up the mouse input
        */
       //cvSetMouseCallback( wndname, mouse_callback );
       cvSetMouseCallback( wndname2, mouse_callback );

       /*
        * more camera-specific stuff
        */
       CvCapture* capture = 0;
       capture = cvCaptureFromCAM(0);

       // this is allocating the undis_frame once (it will get written each time)
       // get one frame and then copy it...
       if (cvGrabFrame(capture))
       {
               frame = cvRetrieveFrame( capture );
               undis_frame = cvCloneImage(frame);
               undis_frame_painted = cvCloneImage(frame);
               // now let's set up the undistortion parameters
               // note that the docs say 3*wider, but that did not work
               // 3*wider _and_ 3*higher worked...
               undisMap = cvCreateMat( imageSize.width*3, imageSize.height*3, CV_32SC3 );
               // need to release this at the end of the program...
               cvUnDistortInit( frame, undisMap, M, D, 1 );
       }
       else
       {
               cout << "No camera??" << endl;
               capturing = false;
       }

       // main loop
       while (!quittingTime)
   {
               if (capturing)
               {
                       if( !cvGrabFrame( capture ))   break;
                       frame = cvRetrieveFrame( capture );
                       if( !frame ) break;

                       // cvUnDistortOnce( frame, undis_frame, M, D, 1 );  // might take some extra time...
                       cvUnDistort( frame, undis_frame, undisMap, 1 );
                       cvReleaseImage(&undis_frame_painted);
                       undis_frame_painted = cvCloneImage(undis_frame);
               }
               else if (getImageFromFile || getImageAgainFromFile)
               {
                       if (getImageFromFile) {
                               // ask for a frame filename
                               int i;
                               // should factor this path out!!
                               if (getImage0FromVideoBMPs) {
                                       i = 0;
                                       getImage0FromVideoBMPs = false;
                               }
                               else {
                                       cout << "What image number (in C:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\VideoBMPs): ";
                                       cin >> i;
                               }
                               sprintf(filename2,"C:\\BMPs\\image%05d.bmp",i);
                               // we probably need to release the images returned by cvLoadImage somewhere...
                               //frame = cvLoadImage(filename2);
                               //undis_frame = cvCloneImage(frame);
                               cvReleaseImage(&undis_frame);
                               undis_frame = cvLoadImage(filename2);
                               cvReleaseImage(&undis_frame_painted);
                               undis_frame_painted = cvLoadImage(filename2);
                               if (undis_frame == NULL) {
                                       cout << "Could not find that image.\n";
                                       continue;
                               }
                               getImageFromFile = false;
                               getImageAgainFromFile = true;

                       }
                       else if (getImageAgainFromFile) {
                               cvReleaseImage(&undis_frame_painted);
                               undis_frame_painted = cvCloneImage(undis_frame);
                       }
               }
               else
               {
                       ;
               }

               // click only on undis_image
               pixelInformation(undis_frame_painted);

               // save the images to a file, if desired
               if (bmpRecording == true && capturing == true)
               {
                       sprintf(filename,"C:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\BMPs\\image%05d.bmp",frameNumber);
                       cout << "Captured single image (dist): " << filename <<  endl;
                       cvSaveImage(filename,frame);
                       sprintf(filename2,"C:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\BMPsUnd\\image%05d.bmp",frameNumber);
                       cout << "Captured single image (undist): " << filename2 <<  endl;
                       cvSaveImage(filename2,undis_frame);
                       ++frameNumber;
                       //saveNextImage = false;
                   //if (getImageFromFile) {
                       //      bmpRecording = false;
                       //}
               }

               // here we can add graphics to each frame
               // in order that they show up on the screen
               // we also decide what to display in this routine
               if (detectRed == true)
               {
                       processRed(undis_frame,undis_frame_painted);
               }
               if (detectGreen == true)
               {
                       processGreen(undis_frame,undis_frame_painted);
               }
               if (detectPurple == true)
               {
                       processPurple(undis_frame,undis_frame_painted);
               }
               if (detectColor == true)
               {
                       processColor(undis_frame,undis_frame_painted);
               }
			   if(omni == true)
			   {
				   int omniset[320][240];
				   for(int i = 0; i < 12; ++i)
				   {
					   scanSet(omniset, setimages[i]);
						erode(omniset);
						dilate(omniset);
					   convertBin(omniset, setimages[i]);
				   }
			   }
               /*
                * display everything in the windows
                */
               cvShowImage(wndname, frame);
               cvShowImage(wndname2, undis_frame);
               cvShowImage(wndname3, undis_frame_painted);

               //handle key presses
               /*
                * quits
                */
               if( (keyCode = cvWaitKey( 10 )) == ((int)'q') ) {
                       break;                       // quit everything
               }
               /*
                * we use = and - to increase and decrease blueValue
                */
               else if (keyCode == (int)'=') {
                       if (blueValue < 251) blueValue += 5;
               }
               else if (keyCode == (int)'-') {
                       if (blueValue > 4) blueValue -= 5;
               }
               else if (keyCode == (int)'1') {
                       if(*currentHueMax - .01 >= -.5) *currentHueMax -= .01;
               }
               else if (keyCode == (int)'2') {
                       if(*currentHueMax + .01 <= 1.5) *currentHueMax += .01;
               }
               else if (keyCode == (int)'3') {
                       if(*currentSatMax - .01 >= 0) *currentSatMax -= .01;
               }
               else if (keyCode == (int)'4') {
                       if(*currentSatMax + .01 <= 1.0) *currentSatMax += .01;
               }
               else if (keyCode == (int)'5') {
                       if(*currentValMax - .01 >= 0) *currentValMax -= .01;
               }
               else if (keyCode == (int)'6') {
                       if(*currentValMax + .01 <= 1.0) *currentValMax += .01;
               }
               else if (keyCode == (int)'!') {
                       if(*currentHueMin - .01 >= -.5) *currentHueMin -= .01;
               }
               else if (keyCode == (int)'@') {
                       if(*currentHueMin + .01 <= 1.5) *currentHueMin += .01;
               }
               else if (keyCode == (int)'#') {
                       if(*currentSatMin - .01 >= 0) *currentSatMin -= .01;
               }
               else if (keyCode == (int)'$') {
                       if(*currentSatMin + .01 <= 1.0) *currentSatMin += .01;
               }
               else if (keyCode == (int)'%') {
                       if(*currentValMin - .01 >= 0) *currentValMin -= .01;
               }
               else if (keyCode == (int)'^') {
                       if(*currentValMin + .01 <= 1.0) *currentValMin += .01;
               }
               else if (keyCode == (int)'7'){
                       if(rMin - 5 >= 0) rMin -=5;
               }
               else if (keyCode == (int)'8'){
                       if(rMin + 5 <= 255) rMin +=5;
               }
               else if (keyCode == (int)'p') {
                       cout << "*currentHueMax: " << *currentHueMax << " *currentHueMin: " << *currentHueMin << endl;
                       cout << "*currentSatMax: " << *currentSatMax << " *currentSatMin: " << *currentSatMin << endl;
                       cout << "*currentValMax: " << *currentValMax << " *currentValMin: " << *currentValMin << endl;
                       cout << "rMin: " << rMin << endl;
               }
               else if (keyCode == (int)'X') {
                       if(!firstTimeForSet)
                       {
								cout << endl;
                               int color[12];
                               int shape[12];
                               int number[12];
                               int texture[12];

                               int setinfo[320][240];
							   char* decision;

                               for(int i = 0; i < 12; i++)
                               {
                                       color[i] = scanSet(setinfo, setimages[i]);
									   if(color[i] == 1)
										   decision = "red";
									   else if(color[i] == 2)
										   decision = "green";
									   else
										   decision = "blue";                          

									   number[i] = countSet(setinfo);
                                       cout << "Card #"<<i<<" has " << number[i] << " " << decision;
                                       
									   texture[i] = texSet(setinfo);
									   if(texture[i] == 1)
										   decision = "filled";
									   else if(texture[i] == 2)
										   decision = "empty";
									   else
										   decision = "textured";
									   cout << " " << decision;

									   shape[i] = shapeSet(setinfo);
									   if(shape[i] == 3)
									   {
										   decision = "squiggle";
										   shape[i] = 1;
									   }
									   else if(shape[i] == 2)
									   {
										   decision = "diamond";
										   shape[i] = 2;
									   }
									   else
									   {
										   decision = "oval";
										   shape[i] = 3;
									   }
									   cout << " " << decision;
									   if(number[i] > 1)
										   cout << "s";
									   cout << "." << endl;
                               }
							   cout << endl;
							   int score = 0;
							for(int x = 0; x < 12; ++x)
								for(int y = x+1; y < 12; ++y)
									for(int z = y+1; z < 12; ++z)
										if(x!=y && x!= z && y!=z)
										{
											if(shape[x] == shape[y] && shape[x] == shape[z])
												score++;
											if(shape[x] != shape[y] && shape[y] != shape[z] && shape[x] != shape[z])
												score++;
											if(number[x] == number[y] && number[x] == number[z])
												score++;
											if(number[x] != number[y] && number[y] != number[z] && number[x] != number[z])
												score++;
											if(texture[x] == texture[y] && texture[x] == texture[z])
												score++;
											if(texture[x] != texture[y] && texture[y] != texture[z] && texture[x] != texture[z])
												score++;
											if(color[x] == color[y] && color[x] == color[z])
												score++;
											if(color[x] != color[y] && color[y] != color[z] && color[x] != color[z])
												score++;

											if(score == 4)
											{
												cout << "Cards "<< x <<","<<y<<", and "<<z<< " form a set." << endl;
												z == 999;
											}
											score = 0;
										}
					   }
               }
			   else if (keyCode == (int)'M') {
					omni = !omni;
			   }
               else if (keyCode == (int)'S') {
                       capturing = false;
                       getImageFromFile = false;
                       char filenameset[500]; // for filename...

                       /* is this the first play? -- we need to open 12 windows... */
                       if (firstTimeForSet == true)
                       {
                               srand( (unsigned)time( NULL ) );

                               cout << "Setting up set!" << endl;
                               setimages = new IplImage*[12]; // should delete this somewhere...
                               for (int i=0 ; i<12 ; ++i)
                               {
                                       sprintf(filenameset,"C:\\BMPs\\image%05d.bmp",i);
                                       //cvReleaseImage(&undis_frame);
                                       setimages[i] = cvLoadImage(filenameset); // load image0 12 times.
                                       cout << "Setting up window " << i << " named " << setwnd[i] << endl;
                                       cvShowImage(setwnd[i], setimages[i]);
                               }

                               firstTimeForSet = false;
                       }
                       else {
                               cout << "Reading in random images..." << endl;
                               int imageIndices[12];
                               for (int i=0 ; i<12 ; ++i) { imageIndices[i] = -1; }

                               for (int i=0 ; i<12 ; ++i)
                               {
                                       cout << "i is " << i << endl;

                                       while (1) {
                                               int randImage = (int)(81.0*rand()/RAND_MAX);
                                               if (randImage < 0 || randImage > 80) continue;
                                               cout << "  randImage is " << randImage << endl;
                                               bool b = alreadyHaveIt(randImage,imageIndices);
                                               if (!b)
                                               {
                                                  imageIndices[i] = randImage;
                                               }
                                               else
                                               {
                                                       cout << "Have it ";
                                                       for (int i=0 ; i<12 ; ++i)
                                                               cout << imageIndices[i] << " ";
                                                       cout << endl;
                                                       continue;
                                               }
                                               break;
                                       }

                                       sprintf(filenameset,"C:\\BMPs\\image%05d.bmp",imageIndices[i]);
                                       //cvReleaseImage(&(setimages[i]));
                                       setimages[i] = cvLoadImage(filenameset); // load image0 12 times.
                                       cout << "Setting up window " << i << " named " << setwnd[i] << " with image #" << imageIndices[i] << endl;
                                       cvShowImage(setwnd[i], setimages[i]);
                               }
                       }
               }
               /*
                * records video to bitmaps (files)
                */
               else if (keyCode == (int)'f') {
                       if (bmpRecording) {
                               cout << "Stopping the writing to bitmaps\n";
                               bmpRecording = false;
                       } else {
                               cout << "Starting to write to bitmaps\n";
                               bmpRecording = true;
                       }
                       showing_savedImage = false;
               }
               /*
                * gets image from a file # in ./VideoBMPs
                */
               else if (keyCode == (int)'g') {
                       cout << "Getting image from file.\n";
                       capturing = false;
                       getImageFromFile = true;
                       getImageAgainFromFile = false;
                       bmpRecording = false;
                       saveNextImage = false;
                       showing_savedImage = true;
               }
               /*
                * toggle continuous video
                */
               else if (keyCode == (int)'s') {
                       if (capturing) {
                               cout << "Stopping continuous capturing.\n";
                               capturing = false;
                               getImageFromFile = false;
                       }
                       else {
                               cout << "Starting continuous capturing.\n";
                               capturing = true;
                               getImageFromFile = false;
                               getImageAgainFromFile = false;
                               /* reset undis_image */
                               // note this assumes that everything went well
                               // initially with the first captured frame... !!
                               cvReleaseImage(&undis_frame);
                               undis_frame = cvCloneImage(frame);
                               cvReleaseImage(&undis_frame_painted);
                               undis_frame_painted = cvCloneImage(frame);
                               // not to mention that these transition images have to be released!
                       }
                       showing_savedImage = false;
               }
               else if (keyCode == (int)'e') {
                       // emulate server behavior
                       saveNextImage = true;
                       showing_savedImage = false;
               }
               /*
                * toggle finding red (and displaying)
                */
               else if (keyCode == (int)'z') {
                       detectRed = !detectRed;
                       currentHueMin = &RedHueMin;
                       currentHueMax = &RedHueMax;
                       currentSatMin = &RedSatMin;
                       currentSatMax = &RedSatMax;
                       currentValMin = &RedValMin;
                       currentValMax = &RedValMax;
               }
               else if (keyCode == (int)'v') {
                       detectColor = !detectColor;
               }
               else if (keyCode == (int)'x') {
                       detectGreen = !detectGreen;
                       currentHueMin = &GreenHueMin;
                       currentHueMax = &GreenHueMax;
                       currentSatMin = &GreenSatMin;
                       currentSatMax = &GreenSatMax;
                       currentValMin = &GreenValMin;
                       currentValMax = &GreenValMax;
               }
               else if (keyCode == (int)'c') {
                       detectPurple = !detectPurple;
                       currentHueMin = &PurpleHueMin;
                       currentHueMax = &PurpleHueMax;
                       currentSatMin = &PurpleSatMin;
                       currentSatMax = &PurpleSatMax;
                       currentValMin = &PurpleValMin;
                       currentValMax = &PurpleValMax;
               }
               /*
                * the spacebar advances the image in the VideoBMPs directory
                */
               else if (keyCode == (int)' ') {
                       if (showing_savedImage == true)
                       {
                               int i;
                               sscanf(filename2,"C:\\BMPs\\image%05d.bmp",&i);
                               sprintf(filename2,"C:\\BMPs\\image%05d.bmp",++i);
                               cvReleaseImage(&undis_frame);
                               undis_frame = cvLoadImage(filename2);
                               cvReleaseImage(&undis_frame_painted);
                               undis_frame_painted = cvLoadImage(filename2);

                               // wrap around!
                               if (undis_frame == NULL)
                               {
                                       i = 0;
                                       sprintf(filename2,"C:\\BMPs\\image%05d.bmp",i);
                                       cvReleaseImage(&undis_frame);
                                       undis_frame = cvLoadImage(filename2);
                                       cvReleaseImage(&undis_frame_painted);
                                       undis_frame_painted = cvLoadImage(filename2);

                                       continue;
                               }
                               getImageAgainFromFile = true;
                               getImageFromFile = false;
                       }
                       /*
                        * initial hit of the space bar...
                        */
                       else {
                               cout << "No image from file is currently showing..." << endl;
                               cout << "Getting image 0 from VideoBMPs.\n";
                               capturing = false;
                               getImageFromFile = true;
                               getImageAgainFromFile = false;
                               getImage0FromVideoBMPs = true;
                               bmpRecording = false;
                               saveNextImage = false;
                               showing_savedImage = true;
                       }
               }

       }

       // release things before quitting
   cvReleaseCapture( &capture );
       cvDestroyWindow("result");

} // end of main

void convertBin(int image[320][240], IplImage* setFrame)
{
	for(int i = 0; i < 320; ++i)
		for(int j = 0; j < 240; ++j)
		{
			uchar* color = cvPtr2D(setFrame, j, i);

			int val = 0;

			if(image[i][j] == 1)
				val = 255;

			color[0] = val;
			color[1] = val;
			color[2] = val;
		}
}

int countSet(int image[340][240])
{
       int scratch[320][240];
       int count = 0;

       for(int i = 0; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
                       scratch[i][j] = 0;

       for(int i = 25; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
               {
                       if(image[i][j] == 1 && scratch[i][j] != 2)
                       {
                               int tinycount = 0;
                               queue<pair<int,int> > Q;
                               Q.push(pair<int,int>(i,j));

                               int x =0;
                               int y = 0;

                               while(!Q.empty())
                               {
                                       pair<int,int> point = Q.front();
                                       Q.pop();
                                       x = point.first;
                                       y = point.second;

                                       scratch[x][y] = 2;
                                       tinycount++;

                                       for(int l = -1; l < 2; ++l)
                                               for(int m = -1; m < 2; ++m)
                                               {
                                                       if(x+l >= 0 && x+l < 320 && y+m >=0 && y+m < 240)
                                                       {
                                                               if(image[x+l][y+m] == 1 && scratch[x+l][y+m] !=2)
                                                                       Q.push(pair<int,int>(x+l, y+m));
                                                               scratch[x+l][y+m] =2;
                                                       }
                                               }
                               }

                               if(tinycount > 450)
                                       count++;
                       }
               }

       return count;
}

int texSet(int image[320][240])
{
	int transition = 0;
	int maxtrans = 0;
	int pixelcount = 0;
	int highscore = 0;
	bool pixel = false;

	for(int i = 25; i < 320; i+=10)
	{
		for(int j = 0; j < 240; ++j)
		{
			if(image[i][j] == 1)
			{
				if(!pixel)
				{
					pixel = true;
					transition++;
				}
				pixelcount++;
			}
			if(image[i][j] == 0 && pixel)
			{
				pixel = false;
				transition++;
			}
		}
		if(transition > maxtrans)
			maxtrans = transition;
		if(pixelcount > 120)
			highscore++;
		transition = 0;
		pixelcount = 0;
	}

	int texture = 0;
	if(maxtrans > 20)
		texture = 3;
	else
	{
		if(highscore > 0)
			texture = 1;
		else
			texture = 2;
	}

	return texture;
}

int shapeSet(int image[320][240])
{
	int depth = 1;
	int require = 3;
	int count = 0;
	int test[10];

	for(int j = 239; j >= 0; --j)
		for(int i = 20; i < 320; ++i)
		{
			if(image[i][j] == 1)
			{
				if(depth == require)
				{
					depth = 1;
					test[count] = i-require;
					count++;
					i = 321;
					j-=15;
				}
				else
					depth++;
			}
			else
				depth = 1;
			if(count == 10)
				j = -1;
		}

	int exp = 0;
	for(int x = 1; x < 10; ++x)
	{
		if(abs(test[x] - test[x-1]) > 3)
			exp++;
	}
	
	if(exp < 5)
		return 1;
	else if(exp > 7)
		return 2;
	else
		return 3;
}
int scanSet(int processed[320][240], IplImage* setPic)
{
       double hue,sat,val;
       int redcount = 0;
       int greencount = 0;
       int bluecount = 0;

       for(int i = 0; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
               {
                       int processNumber = 0;
                       uchar* color = cvPtr2D(setPic,j,i);

                       int r = (int)(color[2]);  // the red component of the pixel we care about
                       int g = (int)(color[1]);  // the green component of the pixel we care about
                       int b = (int)(color[0]);  // the blue component of the pixel we care about

                       RGBtoHSV(r,g,b,&hue,&sat,&val);

                       if(isGreen(r,g,b,hue,sat,val))
                       {
                               processNumber = 1;
                               greencount++;
                       }
                       if (isPurple(r,g,b,hue,sat,val))
                       {
                               processNumber = 1;
                               bluecount++;
                       }
                       if (isRed(r,g,b,hue,sat,val))
                       {
                               processNumber = 1;
                               redcount++;
                       }

                       processed[i][j] = processNumber;
               }

       int champion  = (int)mymax(mymax(redcount, bluecount), mymax(bluecount, greencount));

       if(champion == redcount)
               return 1;
       else if(champion == greencount)
               return 2;
       else if(champion == bluecount)
               return 3;
       else return 0;
}

// read about HSV at http://en.wikipedia.org/wiki/HSV_color_space
// and http://www.cs.rit.edu/~ncs/color/t_convert.html#RGB%20to%20HSV%20&%20HSV%20to%20RGB
//
// feel free to grab code from above or elsewhere online, if you'd like
// be sure you understand what RANGE _your_ code for HSV is "returning"
// in the h, s, and v pointers...
void RGBtoHSV( double r, double g, double b, double *h, double *s, double *v )
{
       double maxRGB;
       double minRGB;
       double delta;

       // get max and min
       if(r >= g && r >= b)
       {
               maxRGB = r;
               if(g >= b)
                       minRGB = b;
               else
                       minRGB = g;
       }
       else if(g >= b)
       {
               maxRGB = g;
               if(r >= b)
                       minRGB = b;
               else
                       minRGB = r;
       }
       else
       {
               maxRGB = b;
               if(r >= g)
                       minRGB = g;
               else
                       minRGB = r;
       }

       delta = maxRGB - minRGB;
       *v = maxRGB/255.0;
       *s = delta/255.0;

       if(delta == 0)
       {
               *h = -1;
               return;
       }

       if(r == maxRGB)
               *h = (g - b)/delta;
       else if (g == maxRGB)
               *h = (1.0/3.0) + (b-r)/delta;
       else
               *h = (2.0/3.0) + (r-g)/delta;
}

// here is where we seek out the red molding and indicate what we've found
// the input named "frame" is the source location of our pixels
// the "output" named f_p is the destination for drawing

void erode(int image[320][240])
{
       int scratch[320][240];

       for(int i = 0; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
                       scratch[i][j] = image[i][j];

       for(int i = 0; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
               {
                       if(scratch[i][j] == 0)
                       {
                               for(int l = -1; l <= 1; ++l)
                                       for(int m = -1; m <=1; ++m)
                                               if(i+l >= 0 && i+l < 320 && j+m >=0 && j+m < 240)
                                                       image[i+l][j+m] = 0;
                       }
               }
}

void dilate(int image[320][240])
{
       int scratch[320][240];

       for(int i = 0; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
                       scratch[i][j] = image[i][j];

       for(int i = 0; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
               {
                       if(scratch[i][j] == 1)
                       {
                               for(int l = -1; l <= 1; ++l)
                                       for(int m = -1; m <=1; ++m)
                                               if(i+l >= 0 && i+l < 320 && j+m >=0 && j+m < 240)
                                                       image[i+l][j+m] = 1;
                       }
               }
}

int processColor(IplImage* frame, IplImage* f_p)
{
       double hue,sat,val;

       for(int i = 0; i < 320; ++i)
               for(int j = 0; j < 240; ++j)
               {
                       int newcolor = 0;

                       uchar* color = cvPtr2D(frame,j,i);
                       uchar* painted = cvPtr2D(f_p,j,i);

                       int r = (int)(color[2]);  // the red component of the pixel we care about
                       int g = (int)(color[1]);  // the green component of the pixel we care about
                       int b = (int)(color[0]);  // the blue component of the pixel we care about

                       RGBtoHSV(r,g,b,&hue,&sat,&val);
                       int quick = (r+g+b)/3;

                       if(isRed(r,g,b,hue,sat,val) || isGreen(r,g,b,hue,sat,val) || isPurple(r,g,b,hue,sat,val))
                               newcolor = 255;

                       painted[0] = newcolor;
                       painted[1] = newcolor;
                       painted[2] = newcolor;
               }
       return 0;
}

bool isGreen(int r, int g, int b, double hue, double sat, double val)
{
	return g > gMin && g>r+GreenMaxBy && g>b+GreenMaxBy
		&& hue < GreenHueMax && hue > GreenHueMin
		&& sat > GreenSatMin && sat < GreenSatMax
		&& val < GreenValMax && val > GreenValMin;
}

void processGreen(IplImage* frame, IplImage* f_p)
{
   // some useful local variables...
       int r,g,b;
       double hue,sat,val;

       // pixels are handled as uchar*'s
       uchar* color;     // a pixel from the input, "frame"
       uchar* painted;   // a pixel from the output, "painted"
       uchar* painted2;   // a pixel from the output, "painted"

       // this draws a rectangle from pt4 to pt5 with the color
       // specified by the three RGB values in the CV_RGB macro
       // the R, G, and B channels are all 0 to 255...

       // see the "this is insane!" caution below in order to
       // use graphics on the live video stream...
       cvRectangle(f_p, pt4, pt5, CV_RGB(0,0,255), 1); // 1 == thickness
       cvCircle( f_p, pt4, 10,  CV_RGB(255,255,0), /*thickness*/ 1 );

       // This loops through the pixels in the rectangle specified
       // by pt4 and pt5 (see setGlobals for their corners)

       int xlow = (int)mymin(pt4.x,pt5.x);
       int xhi = (int)mymax(pt4.x,pt5.x);
       int ylow = (int)mymin(pt4.y,pt5.y);
       int yhi = (int)mymax(pt4.y,pt5.y);

       int matrix[250][250];
       assert(xhi - xlow < 250 && yhi - ylow < 250);

       /*for(int i = 0; i < 25; i++)
               redTop[i] = redBottom[i] = -2;*/

       int y, realy;

       /*int ** matrix;
       matrix= new int*[yhi-ylow];//[xhi-xlow];
       for(int j = 0; j < yhi-ylow; j++)
               matrix[j] = new int[xhi-xlow];*/

       for (int x = xlow; x<xhi; x++)          //the x direction goes left to right
       {
               for (int y = ylow; y<yhi; y++)  //the y direction goes top to bottom
               {
                       // this is insane!!!
                       // unfortunately, access to the pixels is different depending on
                       // the source of the pixels: static images and video reverse their
                       // y orientations

                       // we handle this here...
                       realy = y;
                       if (getImageAgainFromFile || getImageFromFile)
                       {
                               realy = imageSize.height - realy;  // reverse if static image
                       }

                       // note that we need to use "realy" in each of these cases
                       color = cvPtr2D(frame,realy,x);    // get the pixel we care about
                       painted = cvPtr2D(f_p,realy,x);    // get the pixel we (might) change

                       r = (int)(color[2]);  // the red component of the pixel we care about
                       g = (int)(color[1]);  // the green component of the pixel we care about
                       b = (int)(color[0]);  // the blue component of the pixel we care about

                       // you might want to call this here!
                       RGBtoHSV(r,g,b,&hue,&sat,&val);

                       // draw on each pixel that we think is "red"
                       //if(hue < RedHueMax && hue > RedHueMin && sat < RedSatMax && sat > RedSatMin && val < RedValMax && val > RedValMin)
                       // set hue, and make saturation allowable within a range of the value.
                       int quick = (r+g+b)/3;
                       if(isGreen(r,g,b,hue,sat,val))
                       {
                               painted[0] = 0;  // sets blue to 0
                               painted[1] = 255;    // sets green to 0
                               painted[2] = 0;    // sets red to 255
                               //cout << "y = " << y << "\t x = " << x << endl;
                               //cout << "r = " << y-ylow << "\t x-xlow" << x-xlow << endl;
                               matrix[y-ylow][x-xlow]=1;
                               //cout << "matrix has: " << matrix[y-ylow][x-xlow] << endl;
                       }
                       else
                       {
                               matrix[y-ylow][x-xlow]=0;
                       }
               }
       }
}

bool isPurple(int r, int g, int b, double hue, double sat, double val)
{
	return b>g+PurpleMaxBy && b>r+PurpleMaxBy
		/*&& hue < PurpleHueMax && hue > PurpleHueMin
		&& sat < PurpleSatMax && sat > PurpleSatMin
		&& val < PurpleValMax && val > PurpleValMin*/
		&& r < PurpleColorMax && g < PurpleColorMax  && b < PurpleColorMax;
	//return r < PurpleColorMax && g < PurpleColorMax  && b < PurpleColorMax;
}


void processPurple(IplImage* frame, IplImage* f_p)
{
   // some useful local variables...
       int r,g,b;
       double hue,sat,val;

       // pixels are handled as uchar*'s
       uchar* color;     // a pixel from the input, "frame"
       uchar* painted;   // a pixel from the output, "painted"
       uchar* painted2;   // a pixel from the output, "painted"

       // this draws a rectangle from pt4 to pt5 with the color
       // specified by the three RGB values in the CV_RGB macro
       // the R, G, and B channels are all 0 to 255...

       // see the "this is insane!" caution below in order to
       // use graphics on the live video stream...
       cvRectangle(f_p, pt4, pt5, CV_RGB(0,0,255), 1); // 1 == thickness
       cvCircle( f_p, pt4, 10,  CV_RGB(255,255,0), /*thickness*/ 1 );

       // This loops through the pixels in the rectangle specified
       // by pt4 and pt5 (see setGlobals for their corners)

       int xlow = (int)mymin(pt4.x,pt5.x);
       int xhi = (int)mymax(pt4.x,pt5.x);
       int ylow = (int)mymin(pt4.y,pt5.y);
       int yhi = (int)mymax(pt4.y,pt5.y);

       int matrix[250][250];
       assert(xhi - xlow < 250 && yhi - ylow < 250);

       /*for(int i = 0; i < 25; i++)
               redTop[i] = redBottom[i] = -2;*/

       int y, realy;

       /*int ** matrix;
       matrix= new int*[yhi-ylow];//[xhi-xlow];
       for(int j = 0; j < yhi-ylow; j++)
               matrix[j] = new int[xhi-xlow];*/

       for (int x = xlow; x<xhi; x++)          //the x direction goes left to right
       {
               for (int y = ylow; y<yhi; y++)  //the y direction goes top to bottom
               {
                       // this is insane!!!
                       // unfortunately, access to the pixels is different depending on
                       // the source of the pixels: static images and video reverse their
                       // y orientations

                       // we handle this here...
                       realy = y;
                       if (getImageAgainFromFile || getImageFromFile)
                       {
                               realy = imageSize.height - realy;  // reverse if static image
                       }

                       // note that we need to use "realy" in each of these cases
                       color = cvPtr2D(frame,realy,x);    // get the pixel we care about
                       painted = cvPtr2D(f_p,realy,x);    // get the pixel we (might) change

                       r = (int)(color[2]);  // the red component of the pixel we care about
                       g = (int)(color[1]);  // the green component of the pixel we care about
                       b = (int)(color[0]);  // the blue component of the pixel we care about

                       // you might want to call this here!
                       RGBtoHSV(r,g,b,&hue,&sat,&val);

                       // draw on each pixel that we think is "red"
                       //if(hue < RedHueMax && hue > RedHueMin && sat < RedSatMax && sat > RedSatMin && val < RedValMax && val > RedValMin)
                       // set hue, and make saturation allowable within a range of the value.
                       //int quick = (r+g+b)/3;
                       if(isPurple(r,g,b,hue,sat,val))
                       {
                               painted[0] = 255;  // sets blue to 0
                               painted[1] = 0;    // sets green to 0
                               painted[2] = 0;    // sets red to 255
                               //cout << "y = " << y << "\t x = " << x << endl;
                               //cout << "r = " << y-ylow << "\t x-xlow" << x-xlow << endl;
                               matrix[y-ylow][x-xlow]=1;
                               //cout << "matrix has: " << matrix[y-ylow][x-xlow] << endl;
                       }
                       else
                       {
                               matrix[y-ylow][x-xlow]=0;
                       }
               }
       }
}

bool isRed(int r, int g, int b, double hue, double sat, double val)
{
	return r > rMin && r>g+RedMaxBy && r>b+RedMaxBy
		&& hue < RedHueMax && hue > RedHueMin
		&& sat > RedSatMin && sat < RedSatMax
		&& val < RedValMax && val > RedValMin;
}

// here is where we seek out the red molding and indicate what we've found
// the input named "frame" is the source location of our pixels
// the "output" named f_p is the destination for drawing
void processRed(IplImage* frame, IplImage* f_p)
{
   // some useful local variables...
       int r,g,b;
       double hue,sat,val;

       // pixels are handled as uchar*'s
       uchar* color;     // a pixel from the input, "frame"
       uchar* painted;   // a pixel from the output, "painted"
       uchar* painted2;   // a pixel from the output, "painted"

       // this draws a rectangle from pt4 to pt5 with the color
       // specified by the three RGB values in the CV_RGB macro
       // the R, G, and B channels are all 0 to 255...

       // see the "this is insane!" caution below in order to
       // use graphics on the live video stream...
       cvRectangle(f_p, pt4, pt5, CV_RGB(0,0,255), 1); // 1 == thickness
       cvCircle( f_p, pt4, 10,  CV_RGB(255,255,0), /*thickness*/ 1 );

       // This loops through the pixels in the rectangle specified
       // by pt4 and pt5 (see setGlobals for their corners)

       int xlow = (int)mymin(pt4.x,pt5.x);
       int xhi = (int)mymax(pt4.x,pt5.x);
       int ylow = (int)mymin(pt4.y,pt5.y);
       int yhi = (int)mymax(pt4.y,pt5.y);

       int matrix[250][250];
       assert(xhi - xlow < 250 && yhi - ylow < 250);
       int colWidth = 10;
       int sampleCols = (xhi-xlow)/colWidth;
       int redTop[25];
       int redBottom[25];
       int redMiddle[25];

       /*for(int i = 0; i < 25; i++)
               redTop[i] = redBottom[i] = -2;*/

       bool foundTop;
       bool foundBottom;
       int temp;
       int temp2;
       int count;
       int i;
       int j;
       int z;
       int y, realy;

       /*int ** matrix;
       matrix= new int*[yhi-ylow];//[xhi-xlow];
       for(int j = 0; j < yhi-ylow; j++)
               matrix[j] = new int[xhi-xlow];*/

       for (int x = xlow; x<xhi; x++)          //the x direction goes left to right
       {
               for (int y = ylow; y<yhi; y++)  //the y direction goes top to bottom
               {
                       // this is insane!!!
                       // unfortunately, access to the pixels is different depending on
                       // the source of the pixels: static images and video reverse their
                       // y orientations

                       // we handle this here...
                       realy = y;
                       if (getImageAgainFromFile || getImageFromFile)
                       {
                               realy = imageSize.height - realy;  // reverse if static image
                       }

                       // note that we need to use "realy" in each of these cases
                       color = cvPtr2D(frame,realy,x);    // get the pixel we care about
                       painted = cvPtr2D(f_p,realy,x);    // get the pixel we (might) change

                       r = (int)(color[2]);  // the red component of the pixel we care about
                       g = (int)(color[1]);  // the green component of the pixel we care about
                       b = (int)(color[0]);  // the blue component of the pixel we care about

                       // you might want to call this here!
                       RGBtoHSV(r,g,b,&hue,&sat,&val);

                       // draw on each pixel that we think is "red"
                       //if(hue < RedHueMax && hue > RedHueMin && sat < RedSatMax && sat > RedSatMin && val < RedValMax && val > RedValMin)
                       // set hue, and make saturation allowable within a range of the value.
                       int quick = (r+g+b)/3;
                       if(isRed(r,g,b,hue,sat,val))
                       {
                               painted[0] = 0;  // sets blue to 0
                               painted[1] = 0;    // sets green to 0
                               painted[2] = blueValue;    // sets red to 255
                               //cout << "y = " << y << "\t x = " << x << endl;
                               //cout << "r = " << y-ylow << "\t x-xlow" << x-xlow << endl;
                               matrix[y-ylow][x-xlow]=1;
                               //cout << "matrix has: " << matrix[y-ylow][x-xlow] << endl;
                       }
                       else
                       {
                               matrix[y-ylow][x-xlow]=0;
                       }
               }
       }

       // look through sample columns, trying to find the top yValue of a dense red region, and
       // then yValue for the end of that dense region.
       for(i = 0; i < xhi-xlow; i+=colWidth) // col (x's)
       {
               foundTop = false;
               foundBottom = false;
               for(j = 0; j < yhi-ylow; j++) // row (y's)
               {
                       if(!foundTop && matrix[j][i] != 0) // haven't found a top yet and this is red
                       {

                               count = 0; // a count of how many of the next 5 pixels are red
                               for(z = j+1; z <= j+5 && z<yhi-ylow; z++)
                               {
                                       if(matrix[z][i] != 0) // is red
                                               count++;
                               }
                               if(count>=4)
                               {
                                       foundTop = true;
                                       redTop[i/colWidth] = j; // stores the y value of the "top" of the red
                               }
                       }
                       // looking for a bottom and this is red
                       else if(foundTop && !foundBottom && matrix[j][i]!=0)
                       {
                               count = 0; // a count of how many of the next 5 pixels are NOT red
                               for(z = j+1; z <= j+5 && z<yhi-ylow; z++)
                               {
                                       if(matrix[z][i]==0) // these are NOT red
                                               count++;
                               }
                               if(count==5)
                               {
                                       foundBottom = true;
                                       redBottom[i/colWidth] = j; // store the y value of the "bottom" of the red
                               }
                       }
               }
               // no top found, so store a signal
               if(!foundTop)
               {
                       redTop[i/colWidth] = -1;
               }
               // no bottom found, so store a signal
               if(!foundBottom)
               {
                       redBottom[i/colWidth] = -1;
               }
       }

       // now if we found both a top and bottom, store the avg of the two
       for(int e = 0; e < sampleCols; e++)
       {
               if(redTop[e] == -1 || redBottom[e] == -1) // not a valid column, so signal
                       redMiddle[e] = -1;
               else
                       redMiddle[e] = (redTop[e] + redBottom[e])/2; // this is the avg of the top and bottom
       }

       // now calculate a linear regression of the midpoints
       int xVal;
       int yVal;
       int yValOld;
       int sumX = 0;
       int sumY = 0;
       int sumXY = 0;
       int sumXSquared = 0;
       int n = 0;

       // trying to calculate best a,b for y = a + bx
       double aVal;
       double bVal;

       // calculating the needed sums for a linear regression
       for(int e = 0; e < sampleCols; e++)
       {
               if(redMiddle[e] != -1)
               {
                       xVal = e*colWidth + xlow;
                       yVal = redMiddle[e] + ylow;
                       if(n>=1 && (yVal - yValOld > 25 || yVal - yValOld < -25)) // this is an outlier
                               break;                                                                                          // ignore it in the stats

                       sumX            += xVal;
                       sumY            += yVal;
                       sumXY           += xVal*yVal;
                       sumXSquared += xVal*xVal;

                       yValOld = yVal;
                       n++;
               }
       }
       // using the equation listed on (http://cne.gmu.edu/modules/dau/stat/regression/linregsn/nreg_4_frm.html)
       bVal = (sumXY - (sumX * sumY)/double(n)) / double(sumXSquared - (sumX * sumX)/double(n));
       aVal = sumY/double(n) - bVal * sumX/double(n);

       CvPoint linePt1, linePt2;

       // don't fit a line if there are less than 3 valid points
       if(n >= 3)
       {
               linePt1.x = xlow;
               linePt1.y = int(aVal + bVal * xlow);

               linePt2.x = xhi;
               linePt2.y = int(aVal + bVal * xhi);

               // fix video insanity
               if (getImageAgainFromFile || getImageFromFile)
               {
                       linePt1.y = imageSize.height - linePt1.y;  // reverse if static image
                       linePt2.y = imageSize.height - linePt2.y;  // reverse if static image
               }

               cvLine(f_p, linePt1, linePt2,CV_RGB(0,255,0),1,8);      // 1 == thickness, 8 = connectedness

       }

       // this is just to see the process (top, middle, and bottom pixels turned green)
       for(int e = 0; e<sampleCols; e++)
       {
               // draw the detected tops
               y = redTop[e]+ylow;
               realy = y;
               if (getImageAgainFromFile || getImageFromFile)
               {
                       realy = imageSize.height - realy;  // reverse if static image
                       //cout << "realy: " << realy << endl;
               }
               if(redTop[e] != -1)
               {
                       painted = cvPtr2D(f_p,realy,e*colWidth+xlow);    // get the pixel we (might) change
                       painted[0] = 0;  // sets blue to 0
                       painted[1] = blueValue;    // sets green to 255
                       painted[2] = 0;    // sets red to 0
               }

               // draw the detected bottoms
               y = redBottom[e]+ylow;
               realy = y;
               if (getImageAgainFromFile || getImageFromFile)
               {
                       realy = imageSize.height - realy;  // reverse if static image
               }
               if(redBottom[e] != -1)
               {
                       painted2 = cvPtr2D(f_p,realy,e*colWidth+xlow);    // get the pixel we (might) change
                       painted2[0] = 0;  // sets blue to 0
                       painted2[1] = blueValue;    // sets green to 255
                       painted2[2] = 0;    // sets red to 0
               }

               // draw the calculated middles
               y = redMiddle[e]+ylow;
               realy = y;
               if (getImageAgainFromFile || getImageFromFile)
               {
                       realy = imageSize.height - realy;  // reverse if static image
               }
               if(redMiddle[e] != -1)
               {
                       painted2 = cvPtr2D(f_p,realy,e*colWidth+xlow);    // get the pixel we (might) change
                       painted2[0] = 0;  // sets blue to 0
                       painted2[1] = blueValue;    // sets green to 255
                       painted2[2] = 0;    // sets red to 0
               }
       }

//      delete[][] matrix;
//      delete[] redTop;
//      delete[] redBottom;

//      cout << "done\n";
}

void setGlobals()
{
       // mouse click locations (old and new, to tell if we've
       // clicked on a new point
       old_click_pt.x = 0;
       old_click_pt.y = 0;
       new_click_pt.x = 0;
       new_click_pt.y = 0;

       // in theory these should get deleted at the end of the program, too...

       // this is the calibration matrix of the camera
       M = new float[9];
       M[0]=    393.1788940f; M[1]=      0.0000000f; M[2]=    162.8373871f;
       M[3]=      0.0000000f; M[4]=    395.7017517f; M[5]=    121.8078156f;
       M[6]=      0.0000000f; M[7]=      0.0000000f; M[8]=      1.0000000f;

       // these are the distortion parameters of the camera
   D = new float[4];
       D[0]=-0.358375f;
       D[1]=0.168058f;
       D[2]=-0.006497f;
       D[3]=0.001283f;

   // theseimage sizes are hard-coded, but should probably be obtained for each
   // image individually -- however, with our cameras and images, this is safe.
       imageSize.width = 320; imageSize.height = 240;

       // set up some global points for drawing, etc.
   int margin = 12;
       pt1.x = margin; pt1.y = margin;
   pt2.x = imageSize.width-margin; pt2.y = imageSize.height-margin;

       pt3.x = imageSize.width/2;
       pt3.y = imageSize.height/2;

       pt4.x = 80;
       pt4.y = 12;

       pt5.x = 240;
       pt5.y = 228;

       pt6.x = 92;
       pt6.y = 24;

       pt7.x = 228;
       pt7.y = 216;

}

bool alreadyHaveIt(int j,int imageIndices[12])
{
       for (int i=0 ; i<12 ; ++i)
       {
               if (imageIndices[i] == j) return true;
       }
       return false;
}
