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"
78 #define WINDOW_PROD "BARCAM recognition product"
80 // size of graphical windows
81 #define WINDOW_WIDTH 640
82 #define WINDOW_HEIGHT 480
84 // size of desired region of interest (crop camera view)
85 #define ROI_LU_X WINDOW_WIDTH/2 - 40
87 #define ROI_RL_X WINDOW_WIDTH/2 + 40
88 #define ROI_RL_Y WINDOW_HEIGHT - 20
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 drawPauseText(IplImage *img);
132 void selectROI(CvCapture* capture, struct roi *roi);
134 /******************** multimode computational functions ***********************/
135 int countThreshold(const IplImage *frame);
136 int recognize(const CvMat *frame);
138 /********************************** MODE_IMAGE ********************************/
139 int modeImage(char *imageFilename);
141 /********************************* MODE_VIDEO *********************************/
142 int modeVideo(CvCapture* capture, struct roi *roi);
144 /****************************** MODE_RECOGNIZE ********************************/
145 int recognizeMode_processKeys(IplImage *frame);
146 void displayFrames(IplImage *frame, IplImage **thrFrame, CvMat *fMat,
147 int cfgSide, int cfgCenter);
148 int modeRecognize(CvCapture* capture, struct roi *roi);
150 /********************************* MODE_WAIT **********************************/
151 int waitMode_processKeys(int previousMode);
152 int modeWait(int previousMode);
154 /******************************** mode manager ********************************/
155 void setAnalyticWindowsVisible(bool visible);
156 void destroyGUI(void);
157 int modeManager(int defaultMode, char *paramC = NULL);
159 /*********************************** orte *************************************/
160 bool getCameraControlOn(void);
161 void send_cmr_res_cb(const ORTESendInfo *info, void *vinstance, void *recvCallBackParam);
162 void rcv_cmr_ctrl_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam);
163 void rcv_robot_switches_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam);
165 /********************************* application ********************************/
166 int getParamI(int argc, char *argv[], char *imgFilename);
167 int main(int argc, char *argv[]);
170 /******************************************************************************/
171 /**************************** variable declarations ***************************/
172 /******************************************************************************/
174 struct robottype_orte_data orte;
175 bool camera_control_on = false;
185 /******************************************************************************/
186 /********************** multimode graphical functions *************************/
187 /******************************************************************************/
189 /** Saves current image to a new file in the current directory.
190 * @param img Image to save to file.
191 * @return Value returned by cvSaveImage. */
192 int saveFrame(const CvArr *img)
194 struct stat stFileInfo;
198 //find a non-existent filename (e.g. "snapshot13.png")
200 sprintf(filename, SNAPSHOTFILENAME, i++);
201 } while (!stat(filename, &stFileInfo));
203 fprintf(stdout, "Saving frame to %s...\n", filename);
204 return cvSaveImage(filename, img);
207 /******************************************************************************/
209 /** Writes text "pause" in the CAMERA window.
210 * @param img Frame to display with PAUSE text. */
212 void drawPauseText(IplImage *img)
214 cvPutText(img, "PAUSE", cvPoint(img->width/2 - 40,img->height - 50),
215 &fontLarge, cvScalar(0,0,255));
216 cvShowImage(WINDOW_ORIG, img);
220 void drawPauseText(IplImage *img) {}
221 #endif /* WITH_GUI */
224 /******************************************************************************/
226 /** Setting region of interest in the ROI window.
227 * @param capture Pointer to a camera capture.
228 * @param roi Pointer to ROI structure */
230 void selectROI(CvCapture* capture, struct roi *roi)
232 IplImage* frame = NULL;
236 // wait 10ms for an event
237 switch(cvWaitKey(10) & 0xFF) {
240 cvDestroyWindow(WINDOW_ROI);
255 // reset ROI to full frame
258 roi->rl.x = WINDOW_WIDTH;
259 roi->rl.y = WINDOW_HEIGHT;
263 // increase left border
268 // decrease left border
273 // increase upper border
278 // decrease upper border
283 // decrease lower border
288 // increase lower border
293 // decrease right border
298 // increase right border
303 fprintf(stderr, "ROI step: %d left: %d up: %d right: %d down: %d\n",
304 step, roi->lu.x, roi->lu.y, roi->rl.x, roi->rl.y);
306 step = (step < 0 ? 0 : step);
308 frame = cvQueryFrame(capture);
310 cvPutText(frame, "Select ROI", cvPoint(frame->width/2 -60,
312 &fontLarge, cvScalar(0,0,255));
314 cvRectangle(frame, roi->lu, roi->rl, cvScalar(0,0,255), 2, 8, 0);
316 cvShowImage(WINDOW_ROI, frame);
322 void selectROI(CvCapture *capture, struct roi *roi) {}
323 #endif /* WITH_GUI */
325 /******************************************************************************/
326 /******************** multimode computational functions ***********************/
327 /******************************************************************************/
329 /** Returns a threshold computed from the frame.
330 * @param frame Frame to compute a threshold from.
331 * @return Mean of all pixels of the frame. */
332 int countThreshold(const IplImage *frame)
334 return cvAvg(frame).val[0];
337 /******************************************************************************/
339 /** Returns an ordinary number of recognized configuration.
340 * @param frame Float representation of frame.
342 int recognize(IplImage* roi_frame) {
346 /* say you want to set some pixels in the ROI to 0 */
347 for (i = 0; i < roi_frame->height/2; i++) {
348 for (j = 0; j < roi_frame->width/2; j++) {
349 ((uchar*)(roi_frame->imageData + i * roi_frame->widthStep))[j*3] = 0;
350 ((uchar*)(roi_frame->imageData + i * roi_frame->widthStep))[j*3+1] = 0;
351 ((uchar*)(roi_frame->imageData + i * roi_frame->widthStep))[j*3+2] = 0;
355 // IplImage* dst = cvCreateImage( cvGetSize(roi_frame), roi_frame->depth, 1 );
356 // IplImage* color_dst = cvCreateImage( cvGetSize(roi_frame), roi_frame->depth, roi_frame->nChannels);
358 // CvMemStorage* storage = cvCreateMemStorage(0);
363 // cvCanny(roi_frame, dst, 50, 200, 3 );
365 // cvCvtColor( dst, color_dst, CV_GRAY2BGR );
367 // lines = cvHoughLines2( dst,
369 // CV_HOUGH_STANDARD,
376 // for( i = 0; i < MIN(lines->total,100); i++ )
378 // float* line = (float*)cvGetSeqElem(lines,i);
379 // float rho = line[0];
380 // float theta = line[1];
382 // double a = cos(theta), b = sin(theta);
383 // double x0 = a*rho, y0 = b*rho;
384 // pt1.x = cvRound(x0 + 1000*(-b));
385 // pt1.y = cvRound(y0 + 1000*(a));
386 // pt2.x = cvRound(x0 - 1000*(-b));
387 // pt2.y = cvRound(y0 - 1000*(a));
388 // cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 );
391 // cvNamedWindow( "Hough", 1 );
392 // cvShowImage( "Hough", color_dst );
402 /******************************************************************************/
403 /********************************** MODE_IMAGE ********************************/
404 /******************************************************************************/
406 /** Simulates MODE_RECOGNIZE over one specified image filename (PC only).
407 * @param imageFilename Image to load and recognize.
408 * @return Code of mode to switch to. */
410 int modeImage(char *imageFilename)
412 IplImage *frame = NULL;
414 frame = cvLoadImage(imageFilename);
417 fprintf(stderr, "File %s cannot be loaded as image.\n", imageFilename);
423 //TODO do something useful with the image
426 // wait infinitely for a keyboard event
427 switch((char)(cvWaitKey(0) & 0xFF)) {
436 cvReleaseImage(&frame);
441 int modeImage(char *imageFilename) {
442 fprintf(stderr, "Image mode is unsupported on PPC.\nTerminating.\n");
445 #endif /* WITH_GUI */
447 /******************************************************************************/
448 /********************************* MODE_VIDEO *********************************/
449 /******************************************************************************/
451 /** Displays just a real video in a window (only on PC).
452 * @param capture Pointer to a camera capture.
453 * @return Code of mode to switch to. */
455 int modeVideo(CvCapture* capture, struct roi *roi)
457 IplImage *frame = NULL;
458 IplImage *roi_frame = NULL;
461 // wait 10ms for an event
462 switch(cvWaitKey(10) & 0xFF) {
467 // switch to recognize mode
470 return MODE_RECOGNIZE;
472 // pause - switch to wait mode
475 drawPauseText(roi_frame);
478 // save frame to file
481 saveFrame(roi_frame);
486 cvResetImageROI(frame);
487 selectROI(capture, roi);
492 // get one frame from camera (do not release it!)
493 frame = cvQueryFrame(capture);
496 fprintf(stderr, "NULL frame\n");
500 cvSetImageROI(frame, cvRect(roi->lu.x, roi->lu.y, roi->rl.x - roi->lu.x,
501 roi->rl.y - roi->lu.y));
503 roi_frame = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
505 cvCopy(frame, roi_frame, NULL);
507 cvShowImage(WINDOW_ORIG, roi_frame);
514 int modeVideo(CvCapture* capture) {
515 fprintf(stderr, "Video mode is unsupported on PPC.\nTerminating.\n");
518 #endif /* WITH_GUI */
520 /******************************************************************************/
521 /****************************** MODE_RECOGNIZE ********************************/
522 /******************************************************************************/
524 /** On PC processes keyboard events, on PPC does nothing.
525 * @param frame Last camera frame.
526 * @return MODE_RECOGNIZE or mode to switch to. */
528 int recognizeMode_processKeys(IplImage *roi_frame)
530 // wait 10ms for an event
531 switch (cvWaitKey(10) & 0xFF) {
544 drawPauseText(roi_frame);
545 camera_control_on = 0;
548 return MODE_RECOGNIZE;
552 int recognizeMode_processKeys(IplImage *frame)
554 return MODE_RECOGNIZE;
556 #endif /* WITH_GUI */
558 /******************************************************************************/
560 /** Displays analytic frames on screen (on PC), or saves (input) frame to file
561 * (on PPC in debug mode).
562 * @param frame Input frame from camera.
563 * @param thrFrame Thresholded frame.
564 * @param fMat Float representation of frame.
565 * @param cfgSide Index of current side configuration.
566 * @param cfgCenter Index of current center configuration. */
568 void displayFrames(IplImage *roi_frame) {
569 cvShowImage(WINDOW_PROD, roi_frame);
575 void displayFrames(IplImage *frame, IplImage **thrFrame, CvMat *fMat,
576 int cfgSide, int cfgCenter) { /* nothing */ }
577 #endif /* WITH_GUI */
579 /******************************************************************************/
581 /** Implements the camera recognition of corns configurations.
582 * @param capture Pointer to a camera capture.
583 * @return Code of mode to switch to. */
584 int modeRecognize(CvCapture* capture, struct roi *roi)
587 IplImage *frame = NULL;
588 IplImage *roi_frame = NULL;
590 while (camera_control_on) {
592 if ((ret = recognizeMode_processKeys(roi_frame)) != MODE_RECOGNIZE)
595 //get one frame from camera (do not release!)
596 frame = cvQueryFrame(capture);
599 fprintf(stderr, "NULL frame\n");
602 } //else if(orte.camera_result.error & camera_ERR_NO_FRAME) {
603 // orte.camera_result.error &= ~camera_ERR_NO_FRAME;
604 //ORTEPublicationSend(orte.publication_camera_result);
607 cvSetImageROI(frame, cvRect(roi->lu.x, roi->lu.y, roi->rl.x - roi->lu.x,
608 roi->rl.y - roi->lu.y));
610 roi_frame = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
612 cvCopy(frame, roi_frame, NULL);
614 //TODO call image processing (do something useful with the image, FFT atc.)
615 ret = recognize(roi_frame);
618 cvShowImage(WINDOW_PROD, roi_frame);
619 #endif /* WITH_GUI */
622 // orte.camera_result.side = sideConfig;
623 // orte.camera_result.center = centerConfig;
624 // orte.camera_result.sideDist = sideDist;
625 // orte.camera_result.centerDist = centerDist;
626 // ORTEPublicationSend(orte.publication_camera_result);
634 /******************************************************************************/
635 /********************************* MODE_WAIT **********************************/
636 /******************************************************************************/
638 /** Returns mode to switch to from wait mode. On PC processes keyboard events,
639 * on PPC just tests for orte.camera_control.on value.
640 * @param previousMode Mode to switch to, if no more waiting is needed.
641 * @return Mode to switch to. */
643 int waitMode_processKeys(int previousMode)
645 // wait 10ms for an event
646 switch(cvWaitKey(10) & 0xFF) {
654 camera_control_on = 1;
664 int waitMode_processKeys(int previousMode) {
665 return (getCameraControlOn() ? previousMode : MODE_WAIT);
667 #endif /* WITH_GUI */
669 /******************************************************************************/
671 /** Waits until orte.camera_control.on is set to true or, on PC P-key
673 * @param previousMode Mode to switch to when waiting stops.
674 * @return Code of mode to switch to. */
675 int modeWait(int previousMode)
679 while((mode = waitMode_processKeys(previousMode)) == MODE_WAIT) {
680 fprintf(stderr, "waiting...\n");
688 /******************************************************************************/
689 /******************************** mode manager ********************************/
690 /******************************************************************************/
692 /** Initializes GUI, displays static video window. */
695 cvNamedWindow(WINDOW_ORIG, CV_WINDOW_AUTOSIZE);
696 cvInitFont(&fontLarge, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0, 0, 2);
699 void initGUI(void) {}
700 #endif /* WITH_GUI */
702 /******************************************************************************/
704 /** Destroys highgui windows. */
706 void destroyGUI(void)
708 cvDestroyWindow(WINDOW_ORIG);
709 cvDestroyWindow(WINDOW_PROD);
710 cvDestroyWindow(WINDOW_ROI);
713 void destroyGUI(void) {}
714 #endif /* WITH_GUI */
716 /******************************************************************************/
718 /** Switches between modes of the program.
719 * @param defaultMode The first mode to run.
720 * @param paramC Used only in MODE_IMAGE mode (store filepath here).
721 * @return Zero on success, error number on fail. */
722 int modeManager(int defaultMode, char *paramC)
724 int mode = defaultMode;
725 int lastMode = MODE_RECOGNIZE;
726 CvCapture* capture = NULL;
734 if (defaultMode == MODE_IMAGE) {
735 fprintf(stderr, "barcam started in image mode\n");
737 // connect to a camera
738 while (!(capture = cvCaptureFromCAM(-1))) {
739 fprintf(stderr, "NULL capture (is camera connected?)\n");
740 //orte.camera_result.error |= camera_ERR_NO_VIDEO;
741 //ORTEPublicationSend(orte.publication_camera_result);
745 //orte.camera_result.error &= ~camera_ERR_NO_VIDEO;
746 //ORTEPublicationSend(orte.publication_camera_result);
747 fprintf(stderr, "barcam started, camera connected successfully\n");
752 while(!(mode & MODE_QUIT)) {
756 mode = modeVideo(capture, &roi);
757 lastMode = MODE_VIDEO;
761 mode = modeRecognize(capture, &roi);
762 lastMode = MODE_RECOGNIZE;
766 mode = modeWait(lastMode);
770 mode = modeImage(paramC);
771 lastMode = MODE_IMAGE;
774 // jump out of the loop
776 goto _modeManager_end;
781 cvReleaseCapture(&capture);
787 /******************************************************************************/
788 /*********************************** orte *************************************/
789 /******************************************************************************/
791 /** Returns actual state of orte.camera_control.on.
792 * If value changed from previous call, informative output is printed. */
794 inline bool getCameraControlOn(void) {
795 return camera_control_on;
799 inline bool getCameraControlOn(void) {
800 if(orte.camera_control.on!=camera_control_on) {
801 camera_control_on = orte.camera_control.on;
802 fprintf(stderr, "orte: camera_control changed: ctrl %d\n",
805 return camera_control_on;
807 #endif /* WITH_GUI */
809 /******************************************************************************/
811 /** Orte camera result callback function. Does nothing. */
812 void send_cmr_res_cb(const ORTESendInfo *info, void *vinstance,
813 void *recvCallBackParam) { /* nothing */ }
815 /******************************************************************************/
817 /** Orte camera control callback function.
818 * Sets actual value of orte.camera_control.on to camera_control_on. */
819 void rcv_cmr_ctrl_cb(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam) {
820 struct robottype_orte_data *orte_data = (struct robottype_orte_data *)recvCallBackParam;
822 switch (info->status) {
824 fprintf(stderr, "orte: New camera data: ctrl %d\n",
825 orte_data->camera_control.on);
826 getCameraControlOn();
829 fprintf(stderr, "ORTE deadline occurred - CMR_CTRL receive\n");
835 /******************************************************************************/
836 /********************************* application ********************************/
837 /******************************************************************************/
839 /** If "-i filename" is in argv, filename is stored to imgFilename.
840 * @return Mode to switch to. */
842 int getStartMode(int argc, char *argv[], char *imgFilename) {
845 // scan for program arguments
846 while((opt = getopt(argc, argv, "i:")) != -1) {
850 if(optarg) sprintf(imgFilename, "%s", optarg);
852 fprintf(stderr, "Specify image filename to process: barcam -i filename\n");
860 camera_control_on = true;
865 int getStartMode(int argc, char *argv[], char *imgFilename) {
868 #endif /* WITH_GUI */
870 /******************************************************************************/
872 /** The program may on PC be called with -i argument followed by an image
873 * filename, i.e. rozkuk -i image.png, then the program runs in image mode.
874 * Else call it without arguments. On PC it starts in video mode, to switch
875 * modes keyboard is used (R-recognize, W-wait, Esc-quit). On PPC only two
876 * modes are available - recognize and wait. Orte's camera_control_on variable
877 * is used to switch between them. */
878 int main(int argc, char *argv[])
880 char imgFilename[100];
883 //ret = robottype_roboorte_init(&orte);
886 // fprintf(stderr, "robottype_roboorte_init failed\n");
891 // robottype_publisher_camera_result_create(&orte, send_cmr_res_cb, &orte);
892 // robottype_subscriber_camera_control_create(&orte, rcv_cmr_ctrl_cb, &orte);
893 // robottype_subscriber_robot_switches_create(&orte, rcv_robot_switches_cb, &orte);
895 ret = getStartMode(argc, argv, imgFilename);
896 modeManager(ret, imgFilename);
898 //ret = robottype_roboorte_destroy(&orte);