// VideoTool.cpp : Defines the entry point for the console application. #include #include #include #include #include #include #include #include #include #include #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_ #define MIN_SHAPE_SEP 11 using namespace std; // Our Globals! double Hue_Min = -.1; double Hue_Max = .5; double Sat_Min = .12; double Sat_Max = .99; double Val_Min = .04; double Val_Max = .99; double Val_Dist_Max = 2; double Val_Dist_Min = .5; int R_Min = 20; // 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; // 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 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 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 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; // 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? { if (new_click_pt.x < 0 || new_click_pt.x > 319 || new_click_pt.y < 0 || new_click_pt.y > 239) return; // 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; } struct setStruct { public: int card1, card2, card3; setStruct(int c1, int c2, int c3) { card1 = c1; card2 = c2; card3 = c3; } bool operator==(setStruct rhs) { return ((card1 == rhs.card1) && (card2 == rhs.card2) && (card3 == rhs.card3)); } }; struct imageProp { public: enum color { red, blue, green }; enum shape { diamond, oval, squiggle }; enum fill { none, lines, solid }; int myNumShapes; color myColor; shape myShape; fill myFill; imageProp() :myNumShapes(0), myColor(red), myShape(oval), myFill(none) { //nothing to do } imageProp(int ns, color col, shape shp, fill phil) { myNumShapes = ns; myColor = col; myShape = shp; myFill = phil; } }; // just in case you'd like to use these... inline double mymin(double a, double b) { return ab?a:b; } // 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; if (maxRGB <= 0.0) { *h = -1; *s = 0; return; } *s = delta/maxRGB; // better scaling than 255! 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; } bool notWhite(double hue, double sat, double val, double r, double g, double b) { return (sat > .8) || ( (r > 25) && (g < 6) && (b < 6) ) || ( (g > 25) && (r < 6) && (b < 6) ) || ( (b > 25) && (r < 6) && (g < 6) ); } imageProp getProperties(IplImage* image) { uchar* pixel; // a pixel from the input, "frame" double r, g, b; double hue, sat, val; int xlow = 5;//(int)mymin(pt4.x,pt5.x); int xhi = 300;//(int)mymax(pt4.x,pt5.x); int ylow = 0;//(int)mymin(pt4.y,pt5.y); int yhi = 240;//(int)mymax(pt4.y,pt5.y); int realy; int number = 0; imageProp::color picColor; imageProp::shape picShape; imageProp::fill picFill; int numWhiteCols = 0, numRed = 0, numGreen = 0, numBlue = 0; int sep = 0, sepCount = 0; //separation and separation count int squiggleIndications = 0; int numNonWhitePixels = 0; int numTotalPixels = 0; int linesCount = 0; bool whiteBool = false; for (int x = xlow; x MIN_SHAPE_SEP) ++number; numWhiteCols = 0; //color: if( (r > g) && (r > b) ) ++numRed; else if( (g > r) && (g > b) ) ++numGreen; else ++numBlue; //shape: if(!beenColorYet) { //If this is the first colored one, note where the last white was lastWhite = y - 1; beenColorYet = true; } seenColor = true; if(whitePixelsInARow > 15) { ++whiteSections; whitePixelsInARow = 0; } //fill: ++numNonWhitePixels; if(onWhite) { ++numCrossings; onWhite = false; } } else { if(seenColor) //if it's white and have seen a color since last change, move { firstLastWhite = y; seenColor = false; } ++whitePixelsInARow; //fill: if(!onWhite) { ++numCrossings; onWhite = true; } } } ++numWhiteCols; //shape finding if(lastWhite < firstLastWhite) { sep += (firstLastWhite - lastWhite); ++sepCount; } if(whiteSections == 3) ++squiggleIndications; if(numCrossings > 16) ++linesCount; } //Determine color if( (numRed > numGreen) && (numRed > numBlue) ) picColor = imageProp::red; else if( (numGreen > numRed) && (numGreen > numBlue) ) picColor = imageProp::green; else if( (numBlue > numRed) && (numBlue > numGreen) ) picColor = imageProp::blue; else exit(5); // Poor color definitions //Determine shape if((sep / sepCount) < 100) picShape = imageProp::diamond; else { if((squiggleIndications / number) > 5) picShape = imageProp::squiggle; else picShape = imageProp::oval; } //Determine fill: if((linesCount / number) > 12) picFill = imageProp::lines; else if(((double(numNonWhitePixels) / double(numTotalPixels)) / double(number)) > .05) picFill = imageProp::solid; else picFill = imageProp::none; return imageProp(number, picColor, picShape, picFill); } bool isSet(imageProp* p, int i, int j, int k) { if(((p[i].myColor == p[j].myColor) && (p[i].myColor == p[k].myColor) && (p[j].myColor == p[k].myColor)) || ((p[i].myColor != p[j].myColor) && (p[i].myColor != p[k].myColor) && (p[j].myColor != p[k].myColor))) { if(((p[i].myShape == p[j].myShape) && (p[i].myShape == p[k].myShape) && (p[j].myShape == p[k].myShape)) || ((p[i].myShape != p[j].myShape) && (p[i].myShape != p[k].myShape) && (p[j].myShape != p[k].myShape))) { if(((p[i].myFill == p[j].myFill) && (p[i].myFill == p[k].myFill) && (p[j].myFill == p[k].myFill)) || ((p[i].myFill != p[j].myFill) && (p[i].myFill != p[k].myFill) && (p[j].myFill != p[k].myFill))) { if(((p[i].myNumShapes == p[j].myNumShapes) && (p[i].myNumShapes == p[k].myNumShapes) && (p[j].myNumShapes == p[k].myNumShapes)) || ((p[i].myNumShapes != p[j].myNumShapes) && (p[i].myNumShapes != p[k].myNumShapes) && (p[j].myNumShapes != p[k].myNumShapes))) { return true; } } } } return false; } void playSet(IplImage** images) { std::vector sets; sets.clear(); imageProp* imageProperties = new imageProp[12]; for(int sTLV /*someTempLoopVar*/ = 0; sTLV < 12; ++sTLV) { imageProperties[sTLV] = getProperties(images[sTLV]); cout << "Card " << sTLV << " has " << imageProperties[sTLV].myNumShapes << " shapes, is " << imageProperties[sTLV].myColor << " colored, is " << imageProperties[sTLV].myFill << " filled, and is " << imageProperties[sTLV].myShape << " shaped.\n"; } for(int i = 0; i < 12; ++i) { cout << "looking at card " << i << endl; for(int j = 0; j < 12; ++j) { for(int k = 0; k < 12; ++k) { if((k != j) && (k != i) && (i != j)) { if(isSet(imageProperties, i, j, k)) { int temp, tempi = i, tempj = j, tempk = k; if(tempj < tempi) { temp = tempi; tempi = tempj; tempj = temp; } if(tempk < tempj) { temp = tempk; tempk = tempj; tempj = temp; } if(tempj < tempi) { temp = tempi; tempi = tempj; tempj = temp; } setStruct tempSet = setStruct(tempi, tempj, tempk); int lcv; for(lcv = 0; lcv < int(sets.size()); ++lcv) if(sets[lcv] == tempSet) break; if(lcv == sets.size()) sets.push_back(tempSet); } } } } } for(int lcv = 0; lcv < int(sets.size()); ++lcv) { cout << "Cards " << sets[lcv].card1 << ", " << sets[lcv].card2 << ", and " << sets[lcv].card3 << " form a set.\n"; } delete[] imageProperties; } int main( int argc, char** argv ) { // in case you want to log things... //ofstream logfile("logfile_out.txt"); //ifstream loginfile("logfile_in.txt"); // 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 ); } /* * set up the video windows */ for (int i=0 ; i<12 ; ++i) cvNamedWindow( setwnd[i], CV_WINDOW_AUTOSIZE ); cvNamedWindow( wndname, CV_WINDOW_AUTOSIZE ); cvNamedWindow( wndname3, CV_WINDOW_AUTOSIZE ); cvNamedWindow( wndname2, 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:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\VideoBMPs\\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; //} if (saveOnlyOneImageToFile == true) { 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); } /* * 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(Hue_Max - .01 >= -.5) Hue_Max -= .01; } else if (keyCode == (int)'2') { if(Hue_Max + .01 <= 1.0) Hue_Max += .01; } else if (keyCode == (int)'3') { if(Sat_Max - .01 >= 0) Sat_Max -= .01; } else if (keyCode == (int)'4') { if(Sat_Max + .01 <= 1.0) Sat_Max += .01; } else if (keyCode == (int)'5') { if(Val_Max - .01 >= 0) Val_Max -= .01; } else if (keyCode == (int)'6') { if(Val_Max + .01 <= 1.0) Val_Max += .01; } else if (keyCode == (int)'!') { if(Hue_Min - .01 >= -.5) Hue_Min -= .01; } else if (keyCode == (int)'@') { if(Hue_Min + .01 <= 1.0) Hue_Min += .01; } else if (keyCode == (int)'#') { if(Sat_Min - .01 >= 0) Sat_Min -= .01; } else if (keyCode == (int)'$') { if(Sat_Min + .01 <= 1.0) Sat_Min += .01; } else if (keyCode == (int)'%') { if(Val_Min - .01 >= 0) Val_Min -= .01; } else if (keyCode == (int)'^') { if(Val_Min + .01 <= 1.0) Val_Min += .01; } else if (keyCode == (int)'0'){ if(Val_Dist_Max +.1 <=3.0) Val_Dist_Max +=.1; } else if (keyCode == (int)'9'){ if(Val_Dist_Max -.1 >=0.0) Val_Dist_Max -=.1; } else if (keyCode == (int)')'){ if(Val_Dist_Min +.1 <=1.0) Val_Dist_Min +=.1; } else if (keyCode == (int)'('){ if(Val_Dist_Min -.1 >=0.0) Val_Dist_Min -=.1; } else if (keyCode == (int)'7'){ if(R_Min - 5 >= 0) R_Min -=5; } else if (keyCode == (int)'8'){ if(R_Min + 5 <= 255) R_Min +=5; } else if (keyCode == (int)'p') { cout << "Hue_Max: " << Hue_Max << " Hue_Min: " << Hue_Min << endl; cout << "Sat_Max: " << Sat_Max << " Sat_Min: " << Sat_Min << endl; cout << "Val_Max: " << Val_Max << " Val_Min: " << Val_Min << endl; cout << "Val_Dist_Max: " << Val_Dist_Max << "Val_Dist_Min" << Val_Dist_Min << endl; cout << "R_Min: " << R_Min << endl; } /* * plays the game of Set */ 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:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\VideoBMPs\\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:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\VideoBMPs\\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]); } } playSet(setimages); } /* * 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; } /* * the spacebar advances the image in the VideoBMPs directory */ else if (keyCode == (int)' ') { if (showing_savedImage == true) { int i; sscanf(filename2,"C:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\VideoBMPs\\image%05d.bmp",&i); sprintf(filename2,"C:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\VideoBMPs\\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:\\Program Files\\ERSP\\sample_code\\driver\\VideoTool\\VideoBMPs\\image%05d.bmp",i); cvReleaseImage(&undis_frame); undis_frame = cvLoadImage(filename2); cvReleaseImage(&undis_frame_painted); undis_frame_painted = cvLoadImage(filename2); continue; } cout << "Getting image " << i << " from VideoBMPs.\n"; 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 bool alreadyHaveIt(int j,int imageIndices[12]) { for (int i=0 ; i<12 ; ++i) { if (imageIndices[i] == j) return true; } return false; } // 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 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 Hue_Min && sat < Sat_Max && sat > Sat_Min && val < Val_Max && val > Val_Min) // set hue, and make saturation allowable within a range of the value. if(/*r > R_Min*/r>g && r>b && hue < Hue_Max && hue > Hue_Min && sat > Sat_Min && sat < val*(Val_Dist_Max) && sat > val*(Val_Dist_Min) && val < Val_Max && val > Val_Min) { 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=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=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