/* * OpenCV application * */ //#include "stdafx.h" // remove this if you're on MAC OS X! #include "cxcore.h" // basic OpenCV data structures #include "cv.h" // basic OpenCV algorithms #include "highgui.h" // OpenCV's (limited) display and event-handling routines #include // epic C-style I/O; feel free to change to iostream... #include // to compute frames per second enum CAP_SOURCE { GET_IMAGES_FROM_CAMERA, GET_IMAGES_FROM_FILE, GET_IMAGES_FROM_VIDEO }; using namespace std; // aargh! // GLOBALS - there's no avoiding them in OpenCV #ifdef _WIN32 /* Windows */ const char* IMAGES_DIRECTORY = "..\\SetOpenCV\\setImages_v1\\"; #else /* Mac OS X */ const char* IMAGES_DIRECTORY = "../../setImages_v1/"; #endif const char* RAW_IMAGE_NAME = "Raw Image"; const char* DRAW_IMAGE_NAME = "Drawing Image"; const char* BINARY_IMAGE_NAME = "Binary Image"; const char* COLOR_TRACKBAR_WINDOW = "Color Thresholds"; char BUFFER[1024]; // general-purpose string buffer for filenames, printing, etc. // IMAGES IplImage* source_frame = NULL; IplImage* raw_image = NULL; IplImage* draw_image = NULL; IplImage* binary_image = NULL; IplImage* binary_image_copy = NULL; // STATE int IMAGE_SOURCE = GET_IMAGES_FROM_CAMERA; // GET_IMAGES_FROM_FILE, GET_IMAGES_FROM_VIDEO int rectangle_selection = 0; // 0 == no drawing, 1 == need 1st pt, 2 == need 2nd pt. int rectangle_ul[2], rectangle_lr[2]; // the opposing-corner selection pts (need not be ul/lr) // STORAGE CvMemStorage* storage = 0; // THRESHOLDS int RedLow = 100; int GreenLow = 100; int BlueLow = 100; int RedHigh = 200; int GreenHigh = 200; int BlueHigh = 200; // NETWORKING-SPECIFIC DATA enum SERVER_MESSAGES { SERVER_RUN, SERVER_QUIT }; int server_control = SERVER_RUN; // global value available to control the server's state // Helper Functions #include "pixel_access.h" // get_rgb_pixel, set_rgb_pixel, get_gs_pixel, set_gs_pixel #include "image_handling.h" // ensure_image_size #include "file_handling.h" // check_for_file #ifdef _WIN32 // are we on Windows? #include "socket_handling_win.h" // start_vision_server (for windows) #else #include "socket_handling_mac.h" // start_vision_server (for Mac OS X -- maybe Linux, but haven't tested it) #endif // onMouse is the function for handling mouse events // void onMouse(int event, int x, int y, int flags, void* param) // handle mouse events { if (!rectangle_selection && event == CV_EVENT_LBUTTONDOWN) // print single-pixel data { int r,g,b,gs; get_rgb_pixel (raw_image, x, y, r, g, b); // get the pixel from raw_inage get_gs_pixel (binary_image, x, y, gs); // get the pixel from binary_inage printf ("pixel at (%d,%d) is (%3d,%3d,%3d) and in binary is %3d.\n", x, y, r, g, b, gs); } if (rectangle_selection && event == CV_EVENT_LBUTTONDOWN) // starts and ends a rectangle_selection { if (rectangle_selection == 1) { rectangle_ul[0] = x; rectangle_ul[1] = y; rectangle_selection=2; } else if (rectangle_selection == 2) { rectangle_lr[0] = x; rectangle_lr[1] = y; rectangle_selection=1; } } if (rectangle_selection == 2 && event == CV_EVENT_MOUSEMOVE) // move a rectangle_selection around { rectangle_lr[0] = x; rectangle_lr[1] = y; } return; } // main sets everything up and runs a "grab-process-show" loop // int main (int argc, char * const argv[]) { // thresholds RedLow = 0; GreenLow = 0; BlueLow = 0; RedHigh = 50; GreenHigh = 50; BlueHigh = 50; // start storage storage = cvCreateMemStorage(0); // start the vision server - comment this out for no networking... server_thread(); // set up all of the windows and position them cvNamedWindow (RAW_IMAGE_NAME, CV_WINDOW_AUTOSIZE); cvMoveWindow (RAW_IMAGE_NAME,20,20); cvNamedWindow (DRAW_IMAGE_NAME, CV_WINDOW_AUTOSIZE); cvMoveWindow (DRAW_IMAGE_NAME,700,20); cvNamedWindow (BINARY_IMAGE_NAME, CV_WINDOW_AUTOSIZE); cvMoveWindow (BINARY_IMAGE_NAME,20,500); cvNamedWindow (COLOR_TRACKBAR_WINDOW, CV_WINDOW_AUTOSIZE); cvMoveWindow (COLOR_TRACKBAR_WINDOW,700,500); // trackbars are great! cvCreateTrackbar ( "RedLow", COLOR_TRACKBAR_WINDOW, &RedLow, 255, NULL /* callback for motion */ ); cvCreateTrackbar ( "RedHigh", COLOR_TRACKBAR_WINDOW, &RedHigh, 255, NULL /* callback for motion */ ); cvCreateTrackbar ( "GreenLow", COLOR_TRACKBAR_WINDOW, &GreenLow, 255, NULL /* callback for motion */ ); cvCreateTrackbar ( "GreenHigh", COLOR_TRACKBAR_WINDOW, &GreenHigh, 255, NULL /* callback for motion */ ); cvCreateTrackbar ( "BlueLow", COLOR_TRACKBAR_WINDOW, &BlueLow, 255, NULL /* callback for motion */ ); cvCreateTrackbar ( "BlueHigh", COLOR_TRACKBAR_WINDOW, &BlueHigh, 255, NULL /* callback for motion */ ); int close_iterations = 1; // number of times to dilate before eroding for the morphological closing cvCreateTrackbar ( "Iters", COLOR_TRACKBAR_WINDOW, &close_iterations, 10, NULL /* callback for motion */ ); cvSetMouseCallback (RAW_IMAGE_NAME, onMouse, NULL); // mouse events handled from the raw_image window CvCapture* source = cvCreateCameraCapture (CV_CAP_ANY); // check if there is a camera available printf ("You %s have a camera.\n", source ? "do" : "don't"); // report the results to the console... CvFont font_structure; // how OpenCV holds its fonts cvInitFont ( &font_structure, CV_FONT_HERSHEY_PLAIN, 1.0 /* hscale */, 1.0 /* vscale */ ); clock_t last_clock_ticks = clock(); // previous ticks since program started clock_t clock_ticks = last_clock_ticks + 1; // current ticks since program started double fps = 1.0; // frames per second CvSeq *contours, *biggest_contour; CvScalar colorOut = CV_RGB( rand()&255, rand()&255, rand()&255 ); CvScalar colorIn = CV_RGB( rand()&255, rand()&255, rand()&255 ); double area, max_area; int image_index_to_view = 0; // image index to grab from IMAGES_DIRECTORY // the "grab-process-show" loop: until 'q' or ESC is pressed ... // while (true) { clock_ticks = clock(); // get the number of clock ticks fps = CLOCKS_PER_SEC/double(clock_ticks - last_clock_ticks); // compute fps last_clock_ticks = clock_ticks; // reset the old value if (source && IMAGE_SOURCE == GET_IMAGES_FROM_CAMERA) // grab source_frame from CAMERA { source_frame = cvQueryFrame (source); // grab camera frame ensure_image_size (raw_image, source_frame, 3 ); // make sure raw_image is the same size cvFlip (source_frame, raw_image, 1); // need to flip from camera to raw_image } else // grab source_frame from FILE { strcpy (BUFFER, IMAGES_DIRECTORY); // print directory name to BUFFER sprintf (BUFFER+strlen(BUFFER), // then append ... "image%05d.bmp", image_index_to_view); // ... the filename if (file_is_present (BUFFER)) // from file_handling.h source_frame = cvLoadImage( BUFFER ); // grab the file if it's present else if (source_frame != NULL) cvZero (source_frame); // no file? zero out old source_frame else source_frame = cvCreateImage( cvSize(100,100), IPL_DEPTH_8U, 3); // nothing at all? default value. ensure_image_size (raw_image, source_frame, 3 ); // make sure raw_image is the same size cvCopy ( source_frame, raw_image ); // copy into raw_image } ensure_image_size (draw_image, raw_image, 3 /* rgb */ ); // make sure draw_image is the right size ensure_image_size (binary_image, raw_image, 1 /* gs */ ); // make sure binary_image is the right size ensure_image_size (binary_image_copy, raw_image, 1 /* gs */ ); // make sure binary_image_copy is the right size // we will start draw_image as a copy of raw_image cvCopy (raw_image, draw_image); // go through and change some pixels to all red - just to show how to access individual pixels... for (int row=draw_image->height-25 ; row < draw_image->height ; ++row ) { for (int col=draw_image->width-125 ; col < draw_image->width ; ++col ) { set_rgb_pixel (draw_image, col, row, 255 /* red */, 0 /* green */, 0 /* blue */); } } // write text on top of draw_image sprintf (BUFFER, "%4.1f", fps); // print the frames per second on the image cvPutText (draw_image, BUFFER, cvPoint(draw_image->width-100,draw_image->height-10), &font_structure, CV_RGB(255,255,0)); // draw shapes on top of draw_image if (rectangle_selection == 2) // draw the selection rectangle as it's being defined { int ulx = rectangle_ul[0], uly = rectangle_ul[1], lrx = rectangle_lr[0], lry = rectangle_lr[1]; printf ("Rectangle: %d, %d, %d, %d\n", ulx, uly, lrx, lry); cvRectangle (draw_image, cvPoint(ulx,uly), cvPoint(lrx,lry), CV_RGB(255,255,0), 2 /* thickness */ ); } // create a binary_image CvScalar lowerb = cvScalar (BlueLow, GreenLow, RedLow); // lower-bound thresholds CvScalar upperb = cvScalar (BlueHigh, GreenHigh, RedHigh); // upper-bound thresholds cvInRangeS (raw_image, lowerb, upperb, binary_image); // this thresholds between them // erode and dilate can be done in-place (src and dst are both binary_image) cvDilate (binary_image, binary_image, NULL /* default 3x3 square mask */, close_iterations /* iterations */); cvErode (binary_image, binary_image, NULL /* default 3x3 square mask */, close_iterations /* iterations */); // copy it cvCopy (binary_image, binary_image_copy); // get contours cvFindContours( binary_image_copy, storage, &contours, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) ); // CV_RETR_LIST // find and draw the largest-area contour max_area = 0; biggest_contour = NULL; while (contours) { area = fabs ( cvContourArea (contours) ); if ( max_area < area ) { biggest_contour = contours; max_area = area; } contours = contours->h_next; } // draw only the largest-area contour, as saved above if (max_area > 0) { colorOut = CV_RGB( rand()&255, rand()&255, rand()&255 ); cvDrawContours( draw_image, biggest_contour, colorOut, colorOut, -1, CV_FILLED, 8 ); } // free the contour storage cvClearMemStorage( storage ); // show images cvShowImage (RAW_IMAGE_NAME, raw_image); cvShowImage (DRAW_IMAGE_NAME, draw_image); cvShowImage (BINARY_IMAGE_NAME, binary_image); // handle key press events - cvWaitKey is necessary to handle ALL events, as well! int key = cvWaitKey (10); // 10 milliseconds of waiting, I think // if (key == 'q' || key == 'Q' || key == 27) // quit the application, key 27 is ESC { break; } if (key == 'f' || key == 'F' ) // save the image to file { strcpy (BUFFER, IMAGES_DIRECTORY); // directory strcat (BUFFER, "img.bmp"); // plus filename cvSaveImage (BUFFER, raw_image); // saves it printf ("Image saved in %s\n", BUFFER); } if (key == 's' || key == 'S' ) // switch the image source { IMAGE_SOURCE = (GET_IMAGES_FROM_CAMERA == IMAGE_SOURCE) ? GET_IMAGES_FROM_FILE : GET_IMAGES_FROM_CAMERA; printf("Switching to IMAGE_SOURCE %d.\n", IMAGE_SOURCE); } if (key == 'c' || key == 'C' ) // print our color thresholds { printf ("Thresholds: Red: %3d -> %3d\n", RedLow, RedHigh); printf (" Green: %3d -> %3d\n", GreenLow, GreenHigh); printf (" Blue: %3d -> %3d\n", BlueLow, BlueHigh); } if (key == ' ' || key == 'B') // cycle forward (spacebar) or backward 'B' through the images { image_index_to_view += key == ' ' ? 1 : -1; // add or subtract 1 if (image_index_to_view < 0) image_index_to_view = 0; // can't go less than 0 } if (key == 'R') // turn on or off rectangle selection { if (rectangle_selection) { rectangle_selection = 0; /* turn off rectangle selection */ } else { rectangle_selection = 1; /* looking for first corner */ } printf("Rectangle drawing is %d.\n", rectangle_selection ); } if (key == '-') { server_control = SERVER_QUIT; } } // end of the "grab-process-show" while loop // return nicely from main... return 0; }