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>
53 #include <opencv/cv.h>
54 #include <opencv/highgui.h>
57 #include <roboorte_robottype.h>
61 /******************************************************************************/
62 /***************************** macro definitions ******************************/
63 /******************************************************************************/
65 //uncomment next line to "log" the output frames - save them as pnm to the working directory
69 #define MODE_QUIT 0x01
70 #define MODE_VIDEO 0x02
71 #define MODE_RECOGNIZE 0x04
72 #define MODE_WAIT 0x08
73 #define MODE_IMAGE 0x10
75 // highgui windows names
76 #define WINDOW_ORIG "BARCAM original scene"
77 #define WINDOW_ROI "BARCAM set region of interest"
79 // size of graphical windows
80 #define WINDOW_WIDTH 640
81 #define WINDOW_HEIGHT 480
83 // size of desired region of interest (crop camera view)
86 #define ROI_RL_X WINDOW_WIDTH
87 #define ROI_RL_Y WINDOW_HEIGHT
91 #define KEY_SPACE 0x20
104 #define KEY_PLUS 0x2B
105 #define KEY_MINUS 0x2D
116 // default threshold and saturation
117 #define SATURATION 1.0
118 #define THRESHOLD_SHIFT -25 //automatic threshold correction
120 // filename pattern of snapshots (PPC does not support png)
122 #define SNAPSHOTFILENAME "snapshot%02d.png"
124 #define SNAPSHOTFILENAME "snapshot%02d.pnm"
125 #endif /* WITH_GUI */
127 //number of results to select the most supported one from
128 #define DECISION_BOX_SIZE 3
131 /******************************************************************************/
132 /************************** function declarations *****************************/
133 /******************************************************************************/
135 /********************** multimode graphical functions *************************/
136 int saveFrame(const CvArr *img);
137 void drawPauseText(IplImage *img);
138 void selectROI(CvCapture* capture, struct roi *roi);
139 void cropROI(IplImage* frame, struct roi *roi);
141 /******************** multimode computational functions ***********************/
142 int countThreshold(const IplImage *frame);
143 int recognize(const CvMat *frame);
145 /********************************** MODE_IMAGE ********************************/
146 int modeImage(char *imageFilename);
148 /********************************* MODE_VIDEO *********************************/
149 int modeVideo(CvCapture* capture, struct roi *roi);
151 /****************************** MODE_RECOGNIZE ********************************/
152 int recognizeMode_processKeys(IplImage *frame);
153 void displayFrames(IplImage *frame, IplImage **thrFrame, CvMat *fMat,
154 int cfgSide, int cfgCenter);
155 int modeRecognize(CvCapture* capture, struct roi *roi);
157 /********************************* MODE_WAIT **********************************/
158 int waitMode_processKeys(int previousMode);
159 int modeWait(int previousMode);
161 /******************************** mode manager ********************************/
162 void setAnalyticWindowsVisible(bool visible);
163 void destroyGUI(void);
164 int modeManager(int defaultMode, char *paramC = NULL);
166 /*********************************** orte *************************************/
167 bool getCameraControlOn(void);
168 void send_cmr_res_cb(const ORTESendInfo *info, void *vinstance, void *recvCallBackParam);
169 void rcv_cmr_ctrl_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam);
170 void rcv_robot_switches_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam);
172 /********************************* application ********************************/
173 int getParamI(int argc, char *argv[], char *imgFilename);
174 int main(int argc, char *argv[]);
177 /******************************************************************************/
178 /**************************** variable declarations ***************************/
179 /******************************************************************************/
181 struct robottype_orte_data orte;
182 bool camera_control_on = false;
192 /******************************************************************************/
193 /********************** multimode graphical functions *************************/
194 /******************************************************************************/
196 /** Saves current image to a new file in the current directory.
197 * @param img Image to save to file.
198 * @return Value returned by cvSaveImage. */
199 int saveFrame(const CvArr *img)
201 struct stat stFileInfo;
205 //find a non-existent filename (e.g. "snapshot13.png")
207 sprintf(filename, SNAPSHOTFILENAME, i++);
208 } while (!stat(filename, &stFileInfo));
210 fprintf(stdout, "Saving frame to %s...\n", filename);
211 return cvSaveImage(filename, img);
214 /******************************************************************************/
216 /** Writes text "pause" in the CAMERA window.
217 * @param img Frame to display with PAUSE text. */
219 void drawPauseText(IplImage *img)
221 cvPutText(img, "PAUSE", cvPoint(250,400), &fontLarge, cvScalar(0,0,255));
222 cvShowImage(WINDOW_ORIG, img);
226 void drawPauseText(IplImage *img) {}
227 #endif /* WITH_GUI */
230 /******************************************************************************/
232 /** Setting region of interest in the ROI window.
233 * @param capture Pointer to a camera capture.
234 * @param roi Pointer to ROI structure */
236 void selectROI(CvCapture* capture, struct roi *roi)
238 IplImage* frame = NULL;
242 // wait 10ms for an event
243 switch(cvWaitKey(10) & 0xFF) {
246 cvDestroyWindow(WINDOW_ROI);
261 // reset ROI to full frame
262 roi->lu.x = ROI_LU_X;
263 roi->lu.y = ROI_LU_Y;
264 roi->rl.x = ROI_RL_X;
265 roi->rl.y = ROI_RL_Y;
269 // increase left border
274 // decrease left border
279 // increase upper border
284 // decrease upper border
289 // decrease lower border
294 // increase lower border
299 // decrease right border
304 // increase right border
309 frame = cvQueryFrame(capture);
311 cvPutText(frame, "Select ROI", cvPoint(240,400), &fontLarge, cvScalar(0,0,255));
313 step = (step < 0 ? 0 : step);
315 fprintf(stderr, "ROI step: %d left: %d up: %d right: %d down: %d\n",
316 step, roi->lu.x, roi->lu.y, roi->rl.x, roi->rl.y);
318 cvRectangle(frame, roi->lu, roi->rl, cvScalar(0,0,255), 2, 8, 0);
320 cvShowImage(WINDOW_ROI, frame);
326 void setRegionOfInterrest(IplImage *img) {}
327 #endif /* WITH_GUI */
329 /******************************************************************************/
331 /** Sets selected ROI to the frame.
332 * Warning - the frame must be accesst from ROI coordinates now!
333 * @param frame Pointer to the frame.
334 * @param roi Pointer to ROI structure */
335 void cropROI(IplImage* frame, struct roi *roi)
337 cvSetImageROI(frame, cvRect(roi->lu.x, roi->lu.y, roi->rl.x - roi->lu.x,
338 roi->rl.y - roi->lu.y) );
342 /******************************************************************************/
344 /** Normalizes the matrix values and displays them in window specified by name.
345 * @param floatMat Pointer to matrix data to display.
346 * @param windowName Name of window in which to display the image. */
348 void displayFloatMat(const CvMat *floatMat, const char *windowName)
350 double min = 0.0, max = 0.0;
351 CvMat *normalized = cvCloneMat(floatMat);
353 //find extremes of floatMat
354 cvMinMaxLoc(floatMat, &min, &max);
356 cvConvertScale(floatMat, normalized, 1/(max-min), -(min/(max-min)));
357 cvShowImage(windowName, normalized);
359 cvReleaseMat(&normalized);
363 void displayFloatMat(const CvMat *floatMat, const char *windowName) {}
364 #endif /* WITH_GUI */
366 /******************************************************************************/
367 /******************** multimode computational functions ***********************/
368 /******************************************************************************/
370 /** Returns a threshold computed from the frame.
371 * @param frame Frame to compute a threshold from.
372 * @return Mean of all pixels of the frame. */
373 int countThreshold(const IplImage *frame)
375 return cvAvg(frame).val[0];
378 /******************************************************************************/
380 /** Returns an ordinary number of recognized configuration.
381 * @param frame Float representation of frame.
383 int recognize(IplImage *frame) {
391 /******************************************************************************/
392 /********************************** MODE_IMAGE ********************************/
393 /******************************************************************************/
395 /** Simulates MODE_RECOGNIZE over one specified image filename (PC only).
396 * @param imageFilename Image to load and recognize.
397 * @return Code of mode to switch to. */
399 int modeImage(char *imageFilename)
401 IplImage *frame = NULL;
403 frame = cvLoadImage(imageFilename);
406 fprintf(stderr, "File %s cannot be loaded as image.\n", imageFilename);
412 //TODO do something useful with the image
415 // wait infinitely for a keyboard event
416 switch((char)(cvWaitKey(0) & 0xFF)) {
425 cvReleaseImage(&frame);
430 int modeImage(char *imageFilename) {
431 fprintf(stderr, "Image mode is unsupported on PPC.\nTerminating.\n");
434 #endif /* WITH_GUI */
436 /******************************************************************************/
437 /********************************* MODE_VIDEO *********************************/
438 /******************************************************************************/
440 /** Displays just a real video in a window (only on PC).
441 * @param capture Pointer to a camera capture.
442 * @return Code of mode to switch to. */
444 int modeVideo(CvCapture* capture, struct roi *roi)
446 IplImage* frame = NULL;
449 // wait 10ms for an event
450 switch(cvWaitKey(10) & 0xFF) {
455 // switch to recognize mode
458 return MODE_RECOGNIZE;
460 // pause - switch to wait mode
463 drawPauseText(frame);
466 // save frame to file
474 cvResetImageROI(frame);
475 selectROI(capture, roi);
480 // get one frame from camera (do not release it!)
481 frame = cvQueryFrame(capture);
484 fprintf(stderr, "NULL frame\n");
490 cvShowImage(WINDOW_ORIG, frame);
497 int modeVideo(CvCapture* capture) {
498 fprintf(stderr, "Video mode is unsupported on PPC.\nTerminating.\n");
501 #endif /* WITH_GUI */
503 /******************************************************************************/
504 /****************************** MODE_RECOGNIZE ********************************/
505 /******************************************************************************/
507 /** On PC processes keyboard events, on PPC does nothing.
508 * @param frame Last camera frame.
509 * @return MODE_RECOGNIZE or mode to switch to. */
511 int recognizeMode_processKeys(IplImage *frame)
513 // wait 10ms for an event
514 switch (cvWaitKey(10) & 0xFF) {
527 drawPauseText(frame);
528 camera_control_on = 0;
531 // save frame to file
537 return MODE_RECOGNIZE;
541 int recognizeMode_processKeys(IplImage *frame)
543 return MODE_RECOGNIZE;
545 #endif /* WITH_GUI */
547 /******************************************************************************/
549 /** Implements the camera recognition of corns configurations.
550 * @param capture Pointer to a camera capture.
551 * @return Code of mode to switch to. */
552 int modeRecognize(CvCapture* capture, struct roi *roi)
555 IplImage *frame = NULL;
556 IplImage *roi_frame = NULL;
558 while (camera_control_on) {
560 if ((ret = recognizeMode_processKeys(frame)) != MODE_RECOGNIZE)
563 //get one frame from camera (do not release!)
564 frame = cvQueryFrame(capture);
567 fprintf(stderr, "NULL frame\n");
570 } //else if(orte.camera_result.error & camera_ERR_NO_FRAME) {
571 // orte.camera_result.error &= ~camera_ERR_NO_FRAME;
572 //ORTEPublicationSend(orte.publication_camera_result);
577 //TODO call some image processing (do something useful with the image, FFT atc.)
581 // orte.camera_result.side = sideConfig;
582 // orte.camera_result.center = centerConfig;
583 // orte.camera_result.sideDist = sideDist;
584 // orte.camera_result.centerDist = centerDist;
585 // ORTEPublicationSend(orte.publication_camera_result);
593 /******************************************************************************/
594 /********************************* MODE_WAIT **********************************/
595 /******************************************************************************/
597 /** Returns mode to switch to from wait mode. On PC processes keyboard events,
598 * on PPC just tests for orte.camera_control.on value.
599 * @param previousMode Mode to switch to, if no more waiting is needed.
600 * @return Mode to switch to. */
602 int waitMode_processKeys(int previousMode)
604 // wait 10ms for an event
605 switch(cvWaitKey(10) & 0xFF) {
613 camera_control_on = 1;
623 int waitMode_processKeys(int previousMode) {
624 return (getCameraControlOn() ? previousMode : MODE_WAIT);
626 #endif /* WITH_GUI */
628 /******************************************************************************/
630 /** Waits until orte.camera_control.on is set to true or, on PC P-key
632 * @param previousMode Mode to switch to when waiting stops.
633 * @return Code of mode to switch to. */
634 int modeWait(int previousMode)
638 while((mode = waitMode_processKeys(previousMode)) == MODE_WAIT) {
639 fprintf(stderr, "waiting...\n");
647 /******************************************************************************/
648 /******************************** mode manager ********************************/
649 /******************************************************************************/
651 /** Initializes GUI, displays static video window. */
654 cvNamedWindow(WINDOW_ORIG, CV_WINDOW_AUTOSIZE);
655 cvInitFont(&fontLarge, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0, 0, 2);
659 void initGUI(void) {}
660 #endif /* WITH_GUI */
662 /******************************************************************************/
664 /** Sets visibility of 3 analytic windows (threshold, mask and product).
665 * @param visible Use true to display windows, false to hide. */
667 void setAnalyticWindowsVisible(bool visible)
670 cvNamedWindow(WINDOW_ORIG, CV_WINDOW_AUTOSIZE);
672 cvDestroyWindow(WINDOW_ORIG);
677 void setAnalyticWindowsVisible(bool visible) {}
678 #endif /* WITH_GUI */
680 /******************************************************************************/
682 /** Destroys highgui windows. */
684 void destroyGUI(void)
686 cvDestroyWindow(WINDOW_ORIG);
690 void destroyGUI(void) {}
691 #endif /* WITH_GUI */
693 /******************************************************************************/
695 /** Switches between modes of the program.
696 * @param defaultMode The first mode to run.
697 * @param paramC Used only in MODE_IMAGE mode (store filepath here).
698 * @return Zero on success, error number on fail. */
699 int modeManager(int defaultMode, char *paramC)
701 int mode = defaultMode;
702 int lastMode = MODE_RECOGNIZE;
703 CvCapture* capture = NULL;
711 if (defaultMode == MODE_IMAGE) {
712 fprintf(stderr, "barcam started in image mode\n");
714 // connect to a camera
715 while (!(capture = cvCaptureFromCAM(-1))) {
716 fprintf(stderr, "NULL capture (is camera connected?)\n");
717 //orte.camera_result.error |= camera_ERR_NO_VIDEO;
718 //ORTEPublicationSend(orte.publication_camera_result);
722 //orte.camera_result.error &= ~camera_ERR_NO_VIDEO;
723 //ORTEPublicationSend(orte.publication_camera_result);
724 fprintf(stderr, "barcam started, camera connected successfully\n");
729 while(!(mode & MODE_QUIT)) {
733 setAnalyticWindowsVisible(false);
734 mode = modeVideo(capture, &roi);
735 lastMode = MODE_VIDEO;
739 setAnalyticWindowsVisible(true);
740 mode = modeRecognize(capture, &roi);
741 lastMode = MODE_RECOGNIZE;
745 mode = modeWait(lastMode);
749 setAnalyticWindowsVisible(true);
750 mode = modeImage(paramC);
751 lastMode = MODE_IMAGE;
754 // jump out of the loop
756 goto _modeManager_end;
761 cvReleaseCapture(&capture);
767 /******************************************************************************/
768 /*********************************** orte *************************************/
769 /******************************************************************************/
771 /** Returns actual state of orte.camera_control.on.
772 * If value changed from previous call, informative output is printed. */
774 inline bool getCameraControlOn(void) {
775 return camera_control_on;
779 inline bool getCameraControlOn(void) {
780 if(orte.camera_control.on!=camera_control_on) {
781 camera_control_on = orte.camera_control.on;
782 fprintf(stderr, "orte: camera_control changed: ctrl %d\n",
785 return camera_control_on;
787 #endif /* WITH_GUI */
789 /******************************************************************************/
791 /** Orte camera result callback function. Does nothing. */
792 void send_cmr_res_cb(const ORTESendInfo *info, void *vinstance,
793 void *recvCallBackParam) { /* nothing */ }
795 /******************************************************************************/
797 /** Orte camera control callback function.
798 * Sets actual value of orte.camera_control.on to camera_control_on. */
799 void rcv_cmr_ctrl_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam) {
800 struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
802 switch (info->status) {
804 fprintf(stderr, "orte: New camera data: ctrl %d\n",
805 orte_data->camera_control.on);
806 getCameraControlOn();
809 fprintf(stderr, "ORTE deadline occurred - CMR_CTRL receive\n");
815 /******************************************************************************/
816 /********************************* application ********************************/
817 /******************************************************************************/
819 /** If "-i filename" is in argv, filename is stored to imgFilename.
820 * @return Mode to switch to. */
822 int getStartMode(int argc, char *argv[], char *imgFilename) {
825 // scan for program arguments
826 while((opt = getopt(argc, argv, "i:")) != -1) {
830 if(optarg) sprintf(imgFilename, "%s", optarg);
832 fprintf(stderr, "Specify image filename to process: barcam -i filename\n");
840 camera_control_on = true;
845 int getStartMode(int argc, char *argv[], char *imgFilename) {
848 #endif /* WITH_GUI */
850 /******************************************************************************/
852 /** The program may on PC be called with -i argument followed by an image
853 * filename, i.e. rozkuk -i image.png, then the program runs in image mode.
854 * Else call it without arguments. On PC it starts in video mode, to switch
855 * modes keyboard is used (R-recognize, W-wait, Esc-quit). On PPC only two
856 * modes are available - recognize and wait. Orte's camera_control_on variable
857 * is used to switch between them. */
858 int main(int argc, char *argv[])
860 char imgFilename[100];
863 //ret = robottype_roboorte_init(&orte);
866 // fprintf(stderr, "robottype_roboorte_init failed\n");
871 // robottype_publisher_camera_result_create(&orte, send_cmr_res_cb, &orte);
872 // robottype_subscriber_camera_control_create(&orte, rcv_cmr_ctrl_cb, &orte);
873 // robottype_subscriber_robot_switches_create(&orte, rcv_robot_switches_cb, &orte);
875 ret = getStartMode(argc, argv, imgFilename);
876 modeManager(ret, imgFilename);
878 //ret = robottype_roboorte_destroy(&orte);