1 /*******************************************************************************
3 * barcam - OpenCV based camera recognition program.
5 * Created for Eurobot 2010 competition.
7 * Petr Kubizňák (kubiznak.petr@gmail.com), 2010
8 * rewriten by Mihal Vokac (vokac.m@gmail.com), for Eurobot 2011
10 * This program is used to recognize type of playing elements (pawns, qeens,
11 * kings) in Eurobot 2011 competition.
12 * Program can switch between several modes, also depending on platform - on PPC,
13 * only modes RECOGNIZE and WAIT are present, on PC, there are also VIDEO and
14 * IMAGE modes. Lets introduce them:
15 * RECOGNIZE: Camera image is processed and playing element type is recognized.
16 * The results are published continually using orte. On PC, the result and
17 * some subresults are displayed graphically.
18 * WAIT: Program waits until orte.camera_control.on is set to true, or, on PC,
19 * waiting is interrupted by W key. This is the default mode for PPC.
20 * VIDEO (PC only): Video from camera is just displayed in a window. Default
21 * mode for PC. Use R key to switch to RECOGNIZE mode.
22 * IMAGE (PC only): Pseudo-mode used to analyze *one* image loaded from file.
23 * Is useful also for finding a good threshold value, using +/- keys. To use
24 * this mode, start the program with -i argument (see below). There is no way
25 * to switch from this mode to another one.
28 * Usage: ./barcam [-i filename]
30 * Start in image mode, load filename to analyze.
34 * No arguments possible.
36 ******************************************************************************/
43 /******************************************************************************/
49 #include <semaphore.h>
54 #include <opencv/cv.h>
55 #include <opencv/highgui.h>
58 #include <roboorte_robottype.h>
62 /******************************************************************************/
63 /***************************** macro definitions ******************************/
64 /******************************************************************************/
66 //uncomment next line to "log" the output frames - save them as pnm to the working directory
70 #define MODE_QUIT 0x01
71 #define MODE_VIDEO 0x02
72 #define MODE_RECOGNIZE 0x04
73 #define MODE_WAIT 0x08
74 #define MODE_IMAGE 0x10
76 // highgui windows names
77 #define WINDOW_ORIG "BARCAM original scene"
78 #define WINDOW_PROD "BARCAM recognition product"
80 // size of graphical windows
81 #define WINDOW_WIDTH 640
82 #define WINDOW_HEIGHT 480
84 //TODO tune size of region of interest (crop camera view)
87 #define ROI_WIDTH WINDOW_WIDTH
88 #define ROI_HEIGHT WINDOW_HEIGHT
92 #define KEY_SPACE 0x20
105 #define KEY_PLUS 0x2B
106 #define KEY_MINUS 0x2D
117 // filename pattern of snapshots (PPC does not support png)
119 #define SNAPSHOTFILENAME "snapshot%02d.png"
121 #define SNAPSHOTFILENAME "snapshot%02d.pnm"
122 #endif /* WITH_GUI */
125 /******************************************************************************/
126 /************************** function declarations *****************************/
127 /******************************************************************************/
129 /********************** multimode graphical functions *************************/
130 int saveFrame(const CvArr *img);
131 void selectROI(CvCapture* capture, CvRect *roi);
133 /******************** multimode computational functions ***********************/
134 int countThreshold(const IplImage *frame);
135 int recognize(const CvMat *frame);
137 /********************************** MODE_IMAGE ********************************/
138 int modeImage(char *imageFilename);
140 /********************************* MODE_VIDEO *********************************/
141 int modeVideo(CvCapture* capture, CvRect *roi);
143 /****************************** MODE_RECOGNIZE ********************************/
144 int recognizeMode_processKeys(IplImage *frame);
145 void displayFrames(IplImage *frame);
146 int modeRecognize(CvCapture* capture, CvRect *roi);
148 /********************************* MODE_WAIT **********************************/
149 int waitMode_processKeys(int previousMode);
150 int modeWait(int previousMode);
152 /******************************** mode manager ********************************/
153 void setAnalyticWindowsVisible(bool visible);
154 void destroyGUI(void);
155 int modeManager(int defaultMode, char *paramC = NULL);
157 /*********************************** orte *************************************/
158 bool getCameraControlOn(void);
159 void send_cmr_res_cb(const ORTESendInfo *info, void *vinstance, void *recvCallBackParam);
160 void rcv_cmr_ctrl_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam);
161 void rcv_robot_switches_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam);
163 /********************************* application ********************************/
164 int getParamI(int argc, char *argv[], char *imgFilename);
165 int main(int argc, char *argv[]);
168 /******************************************************************************/
169 /**************************** variable declarations ***************************/
170 /******************************************************************************/
172 struct robottype_orte_data orte;
173 bool camera_control_on = false;
178 /******************************************************************************/
179 /********************** multimode graphical functions *************************/
180 /******************************************************************************/
182 /** Saves current image to a new file in the current directory.
183 * @param img Image to save to file.
184 * @return Value returned by cvSaveImage. */
185 int saveFrame(const CvArr *img)
187 struct stat stFileInfo;
191 //find a non-existent filename (e.g. "snapshot13.png")
193 sprintf(filename, SNAPSHOTFILENAME, i++);
194 } while (!stat(filename, &stFileInfo));
196 fprintf(stdout, "Saving frame to %s...\n", filename);
197 return cvSaveImage(filename, img);
200 /******************************************************************************/
202 /** Setting region of interest in the ROI window.
203 * @param capture Pointer to a camera capture.
204 * @param roi Pointer to ROI rectangle. */
206 void selectROI(CvCapture* capture, CvRect *roi)
208 IplImage* frame = NULL;
212 // wait 10ms for an event
213 switch(cvWaitKey(10) & 0xFF) {
230 // reset ROI to full frame
233 roi->width = WINDOW_WIDTH;
234 roi->height = WINDOW_HEIGHT;
238 // increase left border
244 // decrease left border
250 // increase upper border
256 // decrease upper border
262 // decrease lower border
267 // increase lower border
272 // decrease right border
277 // increase right border
282 step = (step < 0 ? 0 : step);
284 fprintf(stderr, "ROI step: %d x: %d x: %d width: %d height: %d\n",
285 step, roi->x, roi->y, roi->width, roi->height);
287 frame = cvQueryFrame(capture);
289 cvPutText(frame, "Select ROI", cvPoint(frame->width/2 -60,
291 &fontLarge, cvScalar(0,0,255));
293 cvRectangle(frame, cvPoint(roi->x, roi->y), cvPoint(roi->width + roi->x,
294 roi->height + roi->y),
295 cvScalar(0,0,255), 2, 8, 0);
296 cvShowImage(WINDOW_ORIG, frame);
302 void selectROI(CvCapture *capture, CvRect *roi) {}
303 #endif /* WITH_GUI */
305 /******************************************************************************/
306 /******************** multimode computational functions ***********************/
307 /******************************************************************************/
309 /** Returns a threshold computed from the frame.
310 * @param frame Frame to compute a threshold from.
311 * @return Mean of all pixels of the frame. */
312 int countThreshold(const IplImage *frame)
314 return cvAvg(frame).val[0];
317 /******************************************************************************/
319 /** Returns an ordinary number of recognized configuration.
320 * @param frame Frame to be processed.
322 int recognize(IplImage* fft) {
326 //IplImage* fft = NULL;
328 //cvCvtColor( roi_frame, fft, CV_BGR2GRAY );
330 // example of accessing image data (invert the image)
331 for(i = 0; i < fft->height; i++) {
332 for(j = 0; j < fft->width; j++) {
333 for(k = 0; k < fft->nChannels; k++) {
334 fft->imageData[i*fft->widthStep + j*fft->nChannels + k] =
335 255 - fft->imageData[i*fft->widthStep + j*fft->nChannels + k];
340 // cvDFT(fft, fft, CV_DXT_FORWARD, fft->height);
342 // CvMemStorage* storage = cvCreateMemStorage(0);
346 // cvCanny(dst, dst, 50, 200, 3 );
348 // cvCvtColor( dst, color_dst, CV_GRAY2BGR );
351 // lines = cvHoughLines2( dst,
353 // CV_HOUGH_STANDARD,
360 // for( i = 0; i < MIN(lines->total,100); i++ )
362 // float* line = (float*)cvGetSeqElem(lines,i);
363 // float rho = line[0];
364 // float theta = line[1];
366 // double a = cos(theta), b = sin(theta);
367 // double x0 = a*rho, y0 = b*rho;
368 // pt1.x = cvRound(x0 + 1000*(-b));
369 // pt1.y = cvRound(y0 + 1000*(a));
370 // pt2.x = cvRound(x0 - 1000*(-b));
371 // pt2.y = cvRound(y0 - 1000*(a));
372 // cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 );
376 // lines = cvHoughLines2( dst,
378 // CV_HOUGH_PROBABILISTIC,
384 // for( i = 0; i < lines->total; i++ )
386 // CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
387 // cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 );
391 // cvClearMemStorage(storage);
397 /******************************************************************************/
398 /********************************** MODE_IMAGE ********************************/
399 /******************************************************************************/
401 /** Simulates MODE_RECOGNIZE over one specified image filename (PC only).
402 * @param imageFilename Image to load and recognize.
403 * @return Code of mode to switch to. */
405 int modeImage(char *imageFilename)
407 IplImage *frame = NULL;
409 frame = cvLoadImage(imageFilename);
412 fprintf(stderr, "File %s cannot be loaded as image.\n", imageFilename);
418 //TODO do something useful with the image
421 // wait infinitely for a keyboard event
422 switch((char)(cvWaitKey(0) & 0xFF)) {
431 cvReleaseImage(&frame);
436 int modeImage(char *imageFilename) {
437 fprintf(stderr, "Image mode is unsupported on PPC.\nTerminating.\n");
440 #endif /* WITH_GUI */
442 /******************************************************************************/
443 /********************************* MODE_VIDEO *********************************/
444 /******************************************************************************/
446 /** Displays just a real video in a window (only on PC).
447 * @param capture Pointer to a camera capture.
448 * @param roi Pointer to ROI rectangle.
449 * @return Code of mode to switch to. */
451 int modeVideo(CvCapture* capture, CvRect *roi)
453 IplImage *frame = NULL;
456 // wait 10ms for an event
457 switch(cvWaitKey(10) & 0xFF) {
462 // switch to recognize mode
465 return MODE_RECOGNIZE;
467 // pause - switch to wait mode
472 // save frame to file
478 // display ROI select window
481 cvResetImageROI(frame);
482 selectROI(capture, roi);
483 cvSetImageROI(frame, *roi);
488 // get one frame from camera (do not release it!)
489 frame = cvQueryFrame(capture);
492 fprintf(stderr, "NULL frame\n");
496 cvShowImage(WINDOW_ORIG, frame);
503 int modeVideo(CvCapture* capture, CvRect *roi) {
504 fprintf(stderr, "Video mode is unsupported on PPC.\nTerminating.\n");
507 #endif /* WITH_GUI */
509 /******************************************************************************/
510 /****************************** MODE_RECOGNIZE ********************************/
511 /******************************************************************************/
513 /** On PC processes keyboard events, on PPC does nothing.
514 * @param frame Last camera frame.
515 * @return MODE_RECOGNIZE or mode to switch to. */
517 int recognizeMode_processKeys(IplImage *frame)
519 // wait 10ms for an event
520 switch (cvWaitKey(10) & 0xFF) {
533 camera_control_on = 0;
536 // save frame to file
542 return MODE_RECOGNIZE;
546 int recognizeMode_processKeys(IplImage *frame)
548 return MODE_RECOGNIZE;
550 #endif /* WITH_GUI */
552 /******************************************************************************/
554 /** Displays analytic frames on screen (on PC), or saves (input) frame to file
555 * @param frame Input frame from camera.
556 * @param window_name Name of the window to show frame in.
559 void displayFrames(const char* window_name, IplImage *frame) {
560 cvShowImage(window_name, frame);
566 void displayFrames(const char* window_name, IplImage *frame) { /* nothing */ }
567 #endif /* WITH_GUI */
569 /******************************************************************************/
571 /** Implements the camera recognition of corns configurations.
572 * @param capture Pointer to a camera capture.
573 * @param roi Pointer to ROI rectangle.
574 * @return Code of mode to switch to. */
575 int modeRecognize(CvCapture* capture, CvRect *roi)
578 IplImage *frame = NULL;
579 IplImage *roi_frame = cvCreateImage(cvSize(roi->width, roi->height), 8, 3);
581 while (camera_control_on) {
583 if ((ret = recognizeMode_processKeys(roi_frame)) != MODE_RECOGNIZE)
586 //get one frame from camera (do not release!)
587 frame = cvQueryFrame(capture);
590 fprintf(stderr, "NULL frame\n");
593 } //else if(orte.camera_result.error & camera_ERR_NO_FRAME) {
594 // orte.camera_result.error &= ~camera_ERR_NO_FRAME;
595 //ORTEPublicationSend(orte.publication_camera_result);
598 cvSetImageROI(frame, *roi);
600 cvCopy(frame, roi_frame);
602 //TODO call image processing (do something useful with the image, FFT atc.)
603 ret = recognize(roi_frame);
605 displayFrames(WINDOW_ORIG, frame);
606 displayFrames(WINDOW_PROD, roi_frame);
609 // orte.camera_result.side = sideConfig;
610 // orte.camera_result.center = centerConfig;
611 // orte.camera_result.sideDist = sideDist;
612 // orte.camera_result.centerDist = centerDist;
613 // ORTEPublicationSend(orte.publication_camera_result);
621 /******************************************************************************/
622 /********************************* MODE_WAIT **********************************/
623 /******************************************************************************/
625 /** Returns mode to switch to from wait mode. On PC processes keyboard events,
626 * on PPC just tests for orte.camera_control.on value.
627 * @param previousMode Mode to switch to, if no more waiting is needed.
628 * @return Mode to switch to. */
630 int waitMode_processKeys(int previousMode)
632 // wait 10ms for an event
633 switch(cvWaitKey(10) & 0xFF) {
641 camera_control_on = 1;
651 int waitMode_processKeys(int previousMode) {
652 return (getCameraControlOn() ? previousMode : MODE_WAIT);
654 #endif /* WITH_GUI */
656 /******************************************************************************/
658 /** Waits until orte.camera_control.on is set to true or, on PC P-key
660 * @param previousMode Mode to switch to when waiting stops.
661 * @return Code of mode to switch to. */
662 int modeWait(int previousMode)
666 while((mode = waitMode_processKeys(previousMode)) == MODE_WAIT) {
667 fprintf(stderr, "waiting...\n");
675 /******************************************************************************/
676 /******************************** mode manager ********************************/
677 /******************************************************************************/
679 /** Initializes GUI, displays static video window. */
682 cvNamedWindow(WINDOW_ORIG, CV_WINDOW_AUTOSIZE);
683 cvInitFont(&fontLarge, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0, 0, 2);
686 void initGUI(void) {}
687 #endif /* WITH_GUI */
689 /******************************************************************************/
691 /** Destroys highgui windows. */
693 void destroyGUI(void)
695 cvDestroyWindow(WINDOW_ORIG);
696 cvDestroyWindow(WINDOW_PROD);
699 void destroyGUI(void) {}
700 #endif /* WITH_GUI */
702 /******************************************************************************/
704 /** Switches between modes of the program.
705 * @param defaultMode The first mode to run.
706 * @param paramC Used only in MODE_IMAGE mode (store filepath here).
707 * @return Zero on success, error number on fail. */
708 int modeManager(int defaultMode, char *paramC)
710 int mode = defaultMode;
711 int lastMode = MODE_RECOGNIZE;
712 CvCapture* capture = NULL;
717 roi.width = ROI_WIDTH;
718 roi.height = ROI_HEIGHT;
720 if (defaultMode == MODE_IMAGE) {
721 fprintf(stderr, "barcam started in image mode\n");
723 // connect to a camera
724 while (!(capture = cvCaptureFromCAM(-1))) {
725 fprintf(stderr, "NULL capture (is camera connected?)\n");
726 //orte.camera_result.error |= camera_ERR_NO_VIDEO;
727 //ORTEPublicationSend(orte.publication_camera_result);
731 //orte.camera_result.error &= ~camera_ERR_NO_VIDEO;
732 //ORTEPublicationSend(orte.publication_camera_result);
733 fprintf(stderr, "barcam started, camera connected successfully\n");
738 while(!(mode & MODE_QUIT)) {
742 mode = modeVideo(capture, &roi);
743 lastMode = MODE_VIDEO;
747 mode = modeRecognize(capture, &roi);
748 lastMode = MODE_RECOGNIZE;
752 mode = modeWait(lastMode);
756 mode = modeImage(paramC);
757 lastMode = MODE_IMAGE;
760 // jump out of the loop
762 goto _modeManager_end;
767 cvReleaseCapture(&capture);
773 /******************************************************************************/
774 /*********************************** orte *************************************/
775 /******************************************************************************/
777 /** Returns actual state of orte.camera_control.on.
778 * If value changed from previous call, informative output is printed. */
780 inline bool getCameraControlOn(void) {
781 return camera_control_on;
785 inline bool getCameraControlOn(void) {
786 if(orte.camera_control.on!=camera_control_on) {
787 camera_control_on = orte.camera_control.on;
788 fprintf(stderr, "orte: camera_control changed: ctrl %d\n",
791 return camera_control_on;
793 #endif /* WITH_GUI */
795 /******************************************************************************/
797 /** Orte camera result callback function. Does nothing. */
798 void send_cmr_res_cb(const ORTESendInfo *info, void *vinstance,
799 void *recvCallBackParam) { /* nothing */ }
801 /******************************************************************************/
803 /** Orte camera control callback function.
804 * Sets actual value of orte.camera_control.on to camera_control_on. */
805 void rcv_cmr_ctrl_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam) {
806 struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
808 switch (info->status) {
810 fprintf(stderr, "orte: New camera data: ctrl %d\n",
811 orte_data->camera_control.on);
812 getCameraControlOn();
815 fprintf(stderr, "ORTE deadline occurred - CMR_CTRL receive\n");
821 /******************************************************************************/
822 /********************************* application ********************************/
823 /******************************************************************************/
825 /** If "-i filename" is in argv, filename is stored to imgFilename.
826 * @return Mode to switch to. */
828 int getStartMode(int argc, char *argv[], char *imgFilename) {
831 // scan for program arguments
832 while((opt = getopt(argc, argv, "i:")) != -1) {
836 if(optarg) sprintf(imgFilename, "%s", optarg);
838 fprintf(stderr, "Specify image filename to process: barcam -i filename\n");
846 camera_control_on = true;
851 int getStartMode(int argc, char *argv[], char *imgFilename) {
854 #endif /* WITH_GUI */
856 /******************************************************************************/
858 /** The program may on PC be called with -i argument followed by an image
859 * filename, i.e. rozkuk -i image.png, then the program runs in image mode.
860 * Else call it without arguments. On PC it starts in video mode, to switch
861 * modes keyboard is used (R-recognize, W-wait, Esc-quit). On PPC only two
862 * modes are available - recognize and wait. Orte's camera_control_on variable
863 * is used to switch between them. */
864 int main(int argc, char *argv[])
866 char imgFilename[100];
869 //ret = robottype_roboorte_init(&orte);
872 // fprintf(stderr, "robottype_roboorte_init failed\n");
877 // robottype_publisher_camera_result_create(&orte, send_cmr_res_cb, &orte);
878 // robottype_subscriber_camera_control_create(&orte, rcv_cmr_ctrl_cb, &orte);
879 // robottype_subscriber_robot_switches_create(&orte, rcv_robot_switches_cb, &orte);
881 ret = getStartMode(argc, argv, imgFilename);
882 modeManager(ret, imgFilename);
884 //ret = robottype_roboorte_destroy(&orte);