1 /*******************************************************************************
3 * rozkuk - OpenCV based corns camera recognition program
5 * Created for Eurobot 2010 competition.
7 * Petr Kubizňák (kubiznak.petr@gmail.com), 2010
9 ******************************************************************************/
16 #include <semaphore.h>
21 //#include "roboorte.h"
22 //#include "rozkorte.h"
25 #include <opencv/cv.h>
26 #include <opencv/highgui.h>
28 #include "clr2float.h"
30 /******************************************************************************/
33 #define MODE_QUIT 0x01
34 #define MODE_REALTIME 0x02
35 #define MODE_RECOGNIZE 0x04
37 // mask of all modes / errors
38 #define MASK_MODES 0x07
39 #define MASK_ERRORS (~MASK_MODES)
42 #define ERR_MASK_READ_FAILURE 0x08
44 // default mode in standard session
45 #define START_MODE MODE_RECOGNIZE
47 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
49 // default mode in debug session
51 #define START_MODE MODE_REALTIME
53 // highgui windows names
54 #define WINDOW_ORIG "ROZKUK original scene"
55 #define WINDOW_THRES "ROZKUK threshold"
56 #define WINDOW_MASK "ROZKUK mask"
57 #define WINDOW_PROD "ROZKUK product"
61 #define KEY_SPACE 0x20
69 // number of frames passed in rozkuk mode before refresh
72 #endif /*----------- DEBUG SESSION ONLY -----------*/
74 //default threshold and saturation
76 #define SATURATION 1.0
80 //mask filename pattern
81 #define MASKFILENAME "../rozkuk_masks/mask%02d.bin"
83 //size of frames from camera
84 #define FRAME_WIDTH 640
85 #define FRAME_HEIGHT 480
86 #define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
88 /******************************************************************************/
90 // function declarations
91 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
92 void drawPauseText(IplImage *img);
93 int saveFrame(const IplImage *img);
94 void displayProduct(const CvMat *floatMat, int recognizedLayout);
95 void displayFloatMat(const CvMat *floatMat, const char *windowName);
96 int modeRealtime(CvCapture* capture);
97 #endif /*----------- DEBUG SESSION ONLY -----------*/
98 int modeRecognize(CvCapture* capture);
99 int modeManager(int defaultMode);
100 int recognize(const CvMat *frame);
101 int loadMask(const char *filename, CvMat **mask);
103 void freeMasks(void);
105 /******************************************************************************/
107 // variable declarations
108 CvMat **masks=NULL; //float mask matrices
109 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
110 CvFont font; //text font
112 /******************************************************************************/
114 /** Writes text "pause" in the CAMERA window. */
115 void drawPauseText(IplImage *img) {
116 cvPutText(img,"pause", cvPoint(300,440), &font, cvScalar(255,255,255));
117 cvShowImage(WINDOW_ORIG, img);
120 /******************************************************************************/
122 /** Saves current image to a new file in the current directory. */
123 int saveFrame(const IplImage *img) {
124 struct stat stFileInfo;
125 char filename[30] = "snapshot00.png";
127 //find a non-existent filename
128 while(!stat(filename, &stFileInfo)) sprintf(filename, "snapshot%02d.png", ++i);
130 return cvSaveImage(filename, img);
133 /******************************************************************************/
135 /** Displays in separate window the result of multiplying camera frame (in float)
136 * and recognized mask.
137 * @param floatMat Pointer to the camera frame converted to float matrix.
138 * @param recognizedLayout Index of recognized situation. */
139 void displayProduct(const CvMat *floatMat, int recognizedLayout) {
140 CvMat *product = cvCloneMat(floatMat);
142 cvMul(floatMat, masks[recognizedLayout], product); // count product
143 displayFloatMat(product, WINDOW_PROD);
145 cvReleaseMat(&product);
148 /******************************************************************************/
150 /** Normalizes the matrix values and displays them in window specified by name.
151 * @param floatMat Pointer to matrix data to display.
152 * @param windowName Name of window in which to display the image. */
153 void displayFloatMat(const CvMat *floatMat, const char *windowName) {
154 double min=0.0, max=0.0;
155 CvMat *normalized = cvCloneMat(floatMat);
157 cvMinMaxLoc(floatMat, &min, &max); // find extremes
158 cvConvertScale(floatMat, normalized, 1/(max-min), -(min/(max-min))); // normalize
159 cvShowImage(windowName, normalized);
161 cvReleaseMat(&normalized);
164 /******************************************************************************/
166 /** Displays a real video in a window (only for DEBUG session).
167 * @param capture Pointer to a camera capture.
168 * @return Code of mode to switch to. */
169 int modeRealtime(CvCapture* capture) {
170 IplImage* frame = NULL; // frame from camera
171 int pause=0; // set pause=1 to pause the video
174 /* keyboard events handeling */
175 switch(cvWaitKey(10) & 0xFF) { // wait 10ms for an event
179 // switch to recognize mode
182 return MODE_RECOGNIZE;
187 drawPauseText(frame);
189 // save frame to file
196 frame = cvQueryFrame(capture); // Get one frame
198 perror("NULL frame");
202 if(!pause) cvShowImage(WINDOW_ORIG, frame); // show image (! Do not release the frame !)
206 #endif /*----------- DEBUG SESSION ONLY -----------*/
208 /******************************************************************************/
210 /** Implements the camera recognition of corns.
211 * In DEBUG session the results are also displayed on screen.
212 * @param capture Pointer to a camera capture.
213 * @return Code of mode to switch to. */
214 int modeRecognize(CvCapture* capture) {
215 IplImage *frame = NULL; // frame from camera
216 IplImage *thresFrame = NULL; // thresholded frame
217 CvMat *floatMat = NULL; // float <-1,1> image of the frame
218 int layout; // number of recognized situation
219 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
220 int framesPassed = PASS_FRAMES; // number of passed frames before refresh
221 int pause=0; // set pause=1 to pause processing
222 #endif /*----------- DEBUG SESSION ONLY -----------*/
224 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
225 /* keyboard events handeling */
226 switch(cvWaitKey(10) & 0xFF) { // wait 10ms for an event
232 framesPassed = PASS_FRAMES;
234 // switch to recognize mode
237 return MODE_REALTIME;
242 drawPauseText(frame);
244 // save frame to file
250 #endif /*----------- DEBUG SESSION ONLY -----------*/
253 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
254 if(pause) cvQueryFrame(capture);
256 #endif /*----------- DEBUG SESSION ONLY -----------*/
257 frame = cvQueryFrame(capture);
259 perror("NULL frame");
263 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
266 // transform colorful image to its float <-1,1> representation
267 cvReleaseImage(&thresFrame);
268 thresFrame = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
269 #endif /*----------- DEBUG SESSION ONLY -----------*/
271 clr2float(frame, &floatMat, THRESHOLD, SATURATION, thresFrame); // get float representation (in DEBUG session, thresholded image is stored to thresFrame)
272 layout = recognize(floatMat);
273 printf("varianta: %d\n", layout);
274 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
275 displayProduct(floatMat, layout);
276 #endif /*----------- DEBUG SESSION ONLY -----------*/
277 cvReleaseMat(&floatMat);
279 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
280 if(framesPassed++ > PASS_FRAMES) {
282 cvShowImage(WINDOW_ORIG, frame); // show image (! Do not release the frame !)
283 cvShowImage(WINDOW_THRES, thresFrame);
284 displayFloatMat(masks[layout], WINDOW_MASK); // display selected mask
285 cvReleaseImage(&thresFrame);
287 #endif /*----------- DEBUG SESSION ONLY -----------*/
293 /******************************************************************************/
295 /** Switches between modes of the program.
296 * @param defaultMode The first mode to run. */
297 int modeManager(int defaultMode) {
298 int mode=defaultMode;
301 // connect to a camera
302 while(!(capture=cvCaptureFromCAM(CV_CAP_ANY))) {
303 perror("NULL capture");
307 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
308 // create gui windows and init font
309 cvNamedWindow(WINDOW_ORIG, CV_WINDOW_AUTOSIZE); // real camera video / one frame viewer
310 cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0, 0, 1); //init text font
311 #endif /*----------- DEBUG SESSION ONLY -----------*/
313 while(!(mode & MODE_QUIT)) {
314 switch(mode & MASK_MODES) {
316 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
318 cvDestroyWindow(WINDOW_THRES);
319 mode = modeRealtime(capture);
321 #endif /*----------- DEBUG SESSION ONLY -----------*/
324 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
325 cvNamedWindow(WINDOW_THRES, CV_WINDOW_AUTOSIZE);
326 cvMoveWindow(WINDOW_THRES, cvQueryFrame(capture)->width, 0);
327 cvNamedWindow(WINDOW_MASK, CV_WINDOW_AUTOSIZE);
328 cvMoveWindow(WINDOW_MASK, 0, cvQueryFrame(capture)->height+50);
329 cvNamedWindow(WINDOW_PROD, CV_WINDOW_AUTOSIZE);
330 cvMoveWindow(WINDOW_PROD, cvQueryFrame(capture)->width, cvQueryFrame(capture)->height+50);
331 #endif /*----------- DEBUG SESSION ONLY -----------*/
332 mode = modeRecognize(capture);
336 goto end; // jump out of the loop
341 cvReleaseCapture(&capture);
342 #ifdef ROZKUK_DEBUG /************ DEBUG SESSION ONLY ************/
343 cvDestroyWindow(WINDOW_ORIG);
344 cvDestroyWindow(WINDOW_THRES);
345 cvDestroyWindow(WINDOW_MASK);
346 cvDestroyWindow(WINDOW_PROD);
347 #endif /*----------- DEBUG SESSION ONLY -----------*/
348 return mode & MASK_ERRORS;
351 /******************************************************************************/
353 /** Returns an ordinary number of recognized layout.
354 * @param frame Float representation of frame. */
355 int recognize(const CvMat *frame) {
356 double max = cvDotProduct(frame, masks[0]);
358 for(int i=1; i<MASKSCNT; i++) {
359 double prod = cvDotProduct(frame, masks[i]);
368 /******************************************************************************/
370 /** Loads binary (float) data to *mask from file.
371 * @param filename Path to file to read.
372 * @param mask Address of array, where to alloc memory and store the data.
373 * @return Length of read data or zero in case of error. */
374 int loadMask(const char *filename, CvMat **mask) {
377 FILE *pFile = fopen(filename, "rb"); //open binary file for reading
380 sprintf(msg, "Mask %s cannot be loaded.", filename);
385 *mask = cvCreateMat(FRAME_HEIGHT, FRAME_WIDTH, CV_32FC1);
386 data = (*mask)->data.fl;
387 len = fread((float *)data, sizeof(float), FRAME_SIZE, pFile); //read data
393 /******************************************************************************/
395 /** Loads all the float masks from files.
396 * @return Zero if ok, else non-zero. */
397 int loadMasks(void) {
398 masks = (CvMat **)malloc(MASKSCNT*sizeof(CvMat *)); //alloc memory for array of masks
399 for(int i=0; i<MASKSCNT; i++) {
401 sprintf(filename, MASKFILENAME, i);
402 if(!loadMask(filename, masks+i)) return ERR_MASK_READ_FAILURE;
407 /******************************************************************************/
409 /** Frees the memory alloced for masks. */
410 void freeMasks(void) {
411 for(int i=0; i<MASKSCNT; i++) {
412 cvReleaseMat(masks+i);
417 /******************************************************************************/
419 int main(int argc, char *argv[]) {
421 /* while (orte_init()) {
426 if((ret=loadMasks())) return ret;
427 ret = modeManager(START_MODE);