1: #include <stdlib.h>
2: #include <stdio.h>
3: #include <string.h>
4: #include <math.h>
5: #include <GL/glut.h>
6:
7: #define Round(v) ((int)(v+0.5))
8: #define MAX 800
9: #define MAX_FILE_LENGTH 256
10:
11: #define LOW_VALUE 0
12: #define HIGH_VALUE 255
13:
14: #define TRUE 1
15: #define FALSE 0
16:
17: /*cartesian coordinate type*/
18: typedef struct {int x;
19: int y;}coord;
20:
21: /*RGB color struct with floats*/
22: /*typedef struct {float red;
23: float green;
24: float blue;
25: }RGB;
26: */
27: /*RGB color struct with ints*/
28: typedef struct {int red;
29: int green;
30: int blue;
31: }RGB_INT;
32:
33: /*number of chain codes stored, */
34: #define MAX_NUMBER_OF_CHAINS 10
35: #define MAX_CHAINS MAX_NUMBER_OF_CHAINS
36:
37: /*These constant values are the chain code directions*/
38: #define NONE -1
39: #define EAST 0
40: #define NORTHEAST 1
41: #define NORTH 2
42: #define NORTHWEST 3
43: #define WEST 4
44: #define SOUTHWEST 5
45: #define SOUTH 6
46: #define SOUTHEAST 7
47:
48: typedef struct chainCode* chain_t;
49: typedef struct chainCode
50: {
51: chain_t prev;
52: int code;
53: coord location; /*absolute pixel location for starting point*/
54: chain_t next;
55: }chainCode; /*This struct can be refered to by: struct chainCode or chainCode*/
56:
57: struct PGMstructure
58: {
59: int maxVal;
60: int width;
61: int height;
62: RGB_INT data[MAX][MAX];
63: };
64:
65: typedef struct PGMstructure PGMImage;
66:
67: /*Evil globals, but not do-able otherwise.*/
68: static PGMImage *img_cur;
69: static PGMImage *img0; /*original*/
70: static PGMImage *img1; /*current*/
71: static PGMImage *img2; /*current*/
72: static int HSIZE;
73: static int VSIZE;
74: static int MVAL;
75:
76: const RGB_INT white = {255, 255, 255};
77: const RGB_INT yellow = {255, 255, 0};
78: const RGB_INT purple = {255, 0, 255};
79: const RGB_INT cyan = {0, 255, 255};
80: const RGB_INT red = {255, 0, 0};
81: const RGB_INT green = {0, 255, 0};
82: const RGB_INT blue = {0, 0, 255};
83: const RGB_INT black = {0, 0, 0};
84:
85: int cur_threash_val; /*for speed optimization of chain code recursion*/
86: int back_ground;
87:
88: /*pointer to an array of pointers which point to the first nodes in each of
89: the chain codes.*/
90: chainCode **chain_codes;
91:
92:
93: /*hold the points farthest away from each other for each object*/
94: coord corner1[MAX_CHAINS], corner2[MAX_CHAINS];
95: coord corner3[MAX_CHAINS], corner4[MAX_CHAINS];
96:
97: /*use double buffered output and keep running enable idle callback to call
98: detect_corners() over and over simulating realtime response.
99: Is set to TRUE or FALSE.*/
100: int is_buffered;
101:
102: /*used to determine if abstract lines should be drawn to the screen.
103: Set to <0 if no abstract lines are to be drawn. Otherwise
104: is set to the number of objects found (AKA number of chaincodes).*/
105: int draw_abstract_lines;
106:
107: /*used to draw the single object most likely to be considered the
108: tic-tac-toe board. Should be <0 if this should not be drawn.
109: Should be equal to the chain-code number (from 0 to MAX_CHAINS - 1)
110: if it is to be drawn.*/
111: int draw_abstract_board;
112:
113:
114: /**************Drawing funcitions************************************/
115: /********************************************************************/
116:
117: void setCPixel(int ix, int iy, RGB_INT color)
118: /*Same as setIPixel except that the last parameter is an RGB color*/
119: {
120: float x = (ix*2.0)/HSIZE - 1.0;
121: float y = (iy*2.0)/VSIZE - 1.0;
122:
123: float red = (float)color.red/(float)MVAL;
124: float green = (float)color.green/(float)MVAL;
125: float blue = (float)color.blue/(float)MVAL;
126:
127: glColor3f(red, green, blue);
128:
129: glBegin(GL_POINTS);
130: glVertex2f (x, y);
131: glEnd();
132: }
133:
134: void setCLines(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
135: /*Similar as setIPixel except that this one draws a line between the first set
136: of points given and the second set in the RGB color specified*/
137: {
138: float x1 = (ix1*2.0)/HSIZE - 1.0;
139: float y1 = (iy1*2.0)/VSIZE - 1.0;
140: float x2 = (ix2*2.0)/HSIZE - 1.0;
141: float y2 = (iy2*2.0)/VSIZE - 1.0;
142:
143: float red = (float)color.red/(float)MVAL;
144: float green = (float)color.green/(float)MVAL;
145: float blue = (float)color.blue/(float)MVAL;
146:
147: glColor3f(red, green, blue);
148:
149: glBegin(GL_LINES);
150: glVertex2f (x1, y1);
151: glVertex2f (x2, y2);
152: glEnd();
153: }
154:
155: void setCRect(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
156: /*Similar as setIPixel except that this one draws a line between the first set
157: of points given and the second set in the RGB color specified*/
158: {
159: float x1 = (ix1*2.0)/HSIZE - 1.0;
160: float y1 = (iy1*2.0)/VSIZE - 1.0;
161: float x2 = (ix2*2.0)/HSIZE - 1.0;
162: float y2 = (iy2*2.0)/VSIZE - 1.0;
163:
164: float red = (float)color.red/(float)MVAL;
165: float green = (float)color.green/(float)MVAL;
166: float blue = (float)color.blue/(float)MVAL;
167:
168: glColor3f(red, green, blue);
169:
170: glBegin(GL_POLYGON);
171: glVertex2f (x1, y1);
172: glVertex2f (x1, y2);
173: glVertex2f (x2, y2);
174: glVertex2f (x2, y1);
175: glEnd();
176: }
177:
178: void pxlcpy(PGMImage *dest, int dest_row, int dest_col,
179: PGMImage *src, int src_row, int src_col)
180: {
181: /*make sure values are within bounds*/
182: if(dest_col > 0 && dest_col < (*dest).width
183: && dest_row > 0 && dest_row < (*dest).height
184: && src_col > 0 && src_col < (*src).width
185: && src_row > 0 && src_row < (*src).height)
186: {
187: (*dest).data[dest_row][dest_col].red =
188: (*src).data[src_row][src_col].red;
189:
190: (*dest).data[dest_row][dest_col].green =
191: (*src).data[src_row][src_col].green;
192:
193: (*dest).data[dest_row][dest_col].blue =
194: (*src).data[src_row][src_col].blue;
195: }
196: }
197:
198:
199: /**********************Support functions*******************************/
200: /***********************************************************************/
201:
202: int rgb_avg(RGB_INT cur_pxl)
203: {
204: /*convert each RGB to the average of the original*/
205: return ((cur_pxl.red + cur_pxl.green + cur_pxl.blue) / 3);
206: }
207:
208: /*Returns average (with RGB avg) pixel value for the image passed in.*/
209: int img_pxl_avg(PGMImage* img)
210: {
211: int i, j; /*loop counting*/
212: int sum = 0;
213:
214: for(i = 0; i < (*img).height; i++)/*collumn*/
215: for(j = 0; j < (*img).width; j++)/*row*/
216: sum += rgb_avg((*img).data[i][j]);
217:
218: return (sum / ((*img).height * (*img).height));
219: }
220:
221: /*1st: pixel one of type RGB_INT
222: 2nd: pixel one of type RGB_INT
223: 3rd: differnce allowed to be considered "equal" or close enough*/
224: int pxlcmp (RGB_INT pxl1, RGB_INT pxl2, int range)
225: {
226: return ((abs((rgb_avg(pxl1) - rgb_avg(pxl2)))) < range);
227: }
228:
229: /* =================================================================
230: * drawString - outputs a string of characters to the graphics port
231: *
232: * x, y: defines the starting location to draw the text
233: * note: this point is the lower left anchor of
234: * the first character - a character's decending
235: * portion would be drawn below this point.
236: * theFont: points to the glut font to be used
237: * theString: holds the string to be output -- up to 255 ch
238: * ----------------------------------------------------------------- */
239: void drawString(int ix, int iy, void *theFont, char theString[256])
240: {
241: float x = (ix*2.0)/HSIZE - 1.0;
242: float y = (iy*2.0)/VSIZE - 1.0;
243: int i;
244: glRasterPos2f(x, y);
245: for (i = 0; theString[i] != '\0'; i++) /* draw the chars one at a time */
246: glutBitmapCharacter(theFont, theString[i]);
247: }
248:
249: /*return >0 if number of pixels is greater than img. pxl. avg., return <0 if
250: number of pixesl is less than img. pxl. avg. and return zero of equal*/
251: int background(int treash_value, PGMImage* img)
252: {
253: int i, j; /*loop counting*/
254: int pxl_less = 0, pxl_more = 0;
255:
256: for(i = 0; i < (*img).height; i++)/*collumn*/
257: for(j = 0; j < (*img).width; j++)/*row*/
258: {
259: if(rgb_avg((*img).data[i][j]) < treash_value)
260: pxl_less++;
261:
262: if(rgb_avg((*img).data[i][j]) > treash_value)
263: pxl_more++;
264: }
265:
266: if(pxl_less > pxl_more)
267: return -1;
268: else if(pxl_less < pxl_more)
269: return 1;
270: else
271: return 0;
272: }
273:
274: /******CHAIN CODE************************************************
275: ****************************************************************/
276:
277: int createNode(chainCode** first, chainCode** last, int new_x, int new_y,
278: int new_dir)
279: {
280: chainCode* temp;
281:
282: if(!(temp = (chain_t)malloc(sizeof(struct chainCode))))
283: {
284: printf("error creating node\n");
285: return FALSE;
286: }
287:
288: temp->next = NULL;
289: temp->code = new_dir;
290: temp->location.x = new_x;
291: temp->location.y = new_y;
292: temp->prev = *last;
293: if(*last)
294: (*last)->next = temp; /*now this is a good thing to set.*/
295: *last = temp; /*advance one*/
296:
297: if(*first == NULL)
298: *first = *last;/*set this for the first node in the list once*/
299:
300: return TRUE;
301: }
302:
303: /*returns TRUE if the chain code loops around itself, otherwise false*/
304: int checkCode(chainCode* first, int x_current, int y_current,
305: int x_check, int y_check, int dir)
306: {
307: struct chainCode* currentNode = first;
308:
309: while(currentNode && currentNode->next)
310: {
311: /*check two consedutive points*/
312: if((currentNode->location.x == x_current) &&
313: (currentNode->location.y == y_current) &&
314: (currentNode->code == dir) &&
315: (currentNode->next->location.x == x_check) &&
316: (currentNode->next->location.y == y_check) &&
317: (currentNode->next->next)) /*don't count the new node already*/
318: {
319: return TRUE; /*The chain code end looped around*/
320: }
321: else
322: currentNode = currentNode->next;
323: }
324: return FALSE;
325: }
326:
327: /*
328: Preconditions:
329: 1st parameter: integer value containing the current x coordinate.
330: 2nd parameter: integer value containing the current y coordinate.
331: 3rd parameter: pointer to the pgm image being used.
332: Postconditions: return true if pixel is deemed boarder of object, false
333: otherwise.*/
334: int checkThings(int x_check, int y_check, PGMImage *img)
335: {
336:
337: /*check for being in bounds*/
338: if((x_check < 0) || (y_check < 0) || (x_check >= (*img).width) ||
339: (y_check >= (*img).height))
340: return FALSE;
341:
342: /*tests if the next pixel is greater than the threashing value. This
343: value (cur_threash_val) should be set to the return value of
344: img_pxl_avg(). Also, checks if the pixel is considered in the background
345: or forground agains the value in back_ground. If so, return true to
346: indicate create new node.*/
347: if((rgb_avg((*img).data[y_check][x_check]) > cur_threash_val)
348: && (back_ground < 0))
349: return TRUE;
350:
351: /*same thing as above, just for things less than, rathur than greater than*/
352: if((rgb_avg((*img).data[y_check][x_check]) < cur_threash_val)
353: && (back_ground > 0))
354: return TRUE;
355:
356: return FALSE;
357: }
358:
359: coord neighborhood_point(int x_coord, int y_coord, int dir)
360: {
361: coord temp = {x_coord, y_coord};
362:
363: if(dir == EAST)
364: temp.x++;
365: else if(dir == NORTHEAST)
366: {
367: temp.x++;
368: temp.y++;
369: }
370: else if(dir == NORTH)
371: temp.y++;
372: else if(dir == NORTHWEST)
373: {
374: temp.x--;
375: temp.y++;
376: }
377: else if(dir == WEST)
378: temp.x--;
379: else if(dir == SOUTHWEST)
380: {
381: temp.x--;
382: temp.y--;
383: }
384: else if(dir == SOUTH)
385: temp.y--;
386: else if(dir == SOUTHEAST)
387: {
388: temp.x++;
389: temp.y--;
390: }
391:
392: return temp;
393: }
394:
395: /*determines the chain code for a starting pixel*/
396: /*this chain code uses 8 connectivity*/
397: /*Note: There are many different coordinate systems at work in this function.*/
398: /*The (*img).data[][] are column major and have are therefore [y][x] or [j][i]*//* This is also asuming (0,0) is bottom left, where the other code assumes
399: /* top left is (0, 0). If it looks strange, look harder!!!*/
400: /*Preconditions:
401: 1st parameter: pointer to the pgm image being used.
402: 2nd parameter: integer value containing the current x coordinate.
403: 3rd parameter: integer value containing the current y coordinate.
404: 4th parameter: integer value containing the current direction code.
405: 5th parameter: pointer to the last node of the chain code.
406: 6th parameter: pointer to the first node of the chain code.*/
407: /*This function assumes the (0, 0) point is in the lower left*/
408:
409: int chaincode(PGMImage *img, int x, int y, int dir,
410: struct chainCode** last, struct chainCode** first)
411: {
412: int i; /*loop counting*/
413: int next /*next direction to check*/, finished /*finished flag*/;
414: coord next_point_to_check; /*next_point_to_check What else?*/
415:
416: next = (dir + 5) % 8; /*better initail choice?*/
417:
418: /*printf("next: %d x: %d y: %d\n", next, x, y);*/
419: for(i = 0; i < 8; i++)
420: {
421: /*determine the next point to check*/
422: next_point_to_check = neighborhood_point(x, y, next);
423:
424: if(checkThings(next_point_to_check.x, next_point_to_check.y, img))
425: {
426: /*setCPixel(next_point_to_check.x, next_point_to_check.y, blue);*/
427:
428: /*create the new node to go last in the chain*/
429: createNode(first, last, next_point_to_check.x,
430: next_point_to_check.y, next);
431:
432: /*if the next chaincode function in the recursion or the current state
433: is the final state of the the chain code; recursively returns DONE
434: back through all the levels to stop the chain code.*/
435: if(checkCode(*first, x, y, next_point_to_check.x,
436: next_point_to_check.y, dir))
437: {
438: return NONE;
439: }
440:
441: if(NONE == chaincode(img, next_point_to_check.x,
442: next_point_to_check.y, next, last, first))
443: return NONE;
444: }
445:
446: /*set next for next iteration*/
447: next = (next + 1) % 8;
448: }
449: return FALSE;
450: }
451:
452: /*returns true if the point is already in one of the chains, false otherwise*/
453: int alreadyFound(int initThreashFlag, int i, int j, chainCode** found)
454: {
455: int k; /*loop counting*/
456: chainCode* temp; /*temporary node pointer*/
457:
458: /*while there are codes to check...*/
459: for(k = 0; (temp = (found[k])) && k < MAX_NUMBER_OF_CHAINS; k++)
460: {
461: while(temp) /*...check them.*/
462: {
463: /*if point has already been found*/
464: if((temp->location.x == i) && (temp->location.y == j))
465: {
466: return TRUE;
467: break;
468: }
469: temp = temp->next;
470: }
471: }
472:
473: return FALSE;
474: }
475:
476: /*saves a chain code to file. Was usefull during debuging now is just
477: a cool thing to leave in*/
478: /*1st: pointer to beginning of a chaincode
479: 2nd: the index of the chain code for destiqushing the 'chain' files*/
480: void saveChainCode(chainCode* saveChain, int count)
481: {
482: struct chainCode* temp = saveChain;
483: char filename[12];
484: FILE* outfile;
485: sprintf(filename, "chain%d", count);
486: outfile = fopen(filename, "w"); /*output file for chaincode*/
487: /*printf("Writing chain code to file %s.\n", filename);*/
488:
489: while(temp)
490: {
491:
492: fprintf(outfile, "%d %d %d\n",temp->location.x,temp->location.y,
493: temp->code);
494: temp = temp->next;
495: }
496: fclose(outfile);
497: }
498:
499: chainCode** showChain(PGMImage *original)
500: {
501: int i, j; /*loop counting*/
502: int count = 0; /*array index holder*/
503: int initThreashFlag = img_pxl_avg(original);
504: /*beginning points to an array of pointers. Each pointer in the array is
505: a pointer to the first node of MAX_NUMBER_OF_CHAINS number of chain
506: codes*/
507: struct chainCode** beginning, *chain = NULL;
508:
509: /*allocate an array of pointers to chainCodes, then initalize their
510: values to NULL*/
511: beginning = (chainCode**)
512: malloc(MAX_NUMBER_OF_CHAINS * sizeof(chainCode*));
513: memset(beginning, 0, MAX_NUMBER_OF_CHAINS * sizeof(chainCode*));
514:
515: cur_threash_val = initThreashFlag; /*set global variables*/
516: back_ground = background(initThreashFlag, original);
517:
518: /*search image until a pixel is found with threasholded value of the
519: object. i & j will then contain the starting coordinate.*/
520: for(i = 0; i < (*original).width; i++) /*x direction*/
521: {
522: for(j = (*original).height - 1; j >= 0; j--) /*y direction*/
523: {
524: /*skip to the next iteration if pixel isn't "good" enough*/
525: if(!checkThings(i, j, original))
526: continue;
527:
528: /*skip to the next iteration, which will be at the top of the next
529: collumn. This is true when the pixel has already been found in
530: one of the chain codes.*/
531: else if(alreadyFound(initThreashFlag, i, j, beginning))
532: break;
533:
534: else
535: {
536: /*printf("chaincode: %d\n", count);*/
537: /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/
538: chain = NULL; /*reset this to seperate the chaincodes*/
539:
540: /*find the chaincode for the current starting pixel*/
541: chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]);
542: if(beginning[count] != NULL) /*avoid writing zero length chains*/
543: {
544: saveChainCode(beginning[count], count);
545: count++; /*advance the beginning counter*/
546: }
547:
548: /*force end of loops, leaving code when finished looping
549: to still execute*/
550: if(count >= MAX_NUMBER_OF_CHAINS)
551: i = (*original).width;
552:
553: break; /*check the next collumn*/
554: }
555: }
556: }
557: printf("\nDone finding chain code(s). %d were found.\n", count);
558: return beginning;
559: }
560:
561: /*frees the memory that the chain code(s) are using*/
562: void free_chaincode(chainCode** pointer)
563: {
564: int i; /*loop counting*/
565: chainCode* temp, *to_free;
566:
567: for(i = 0; pointer[i] && i < MAX_CHAINS; i++)/*for each chaincode*/
568: {
569: temp = pointer[i];
570: while(temp) /*for each node*/
571: {
572: to_free = temp;
573: temp = temp->next;
574: free(to_free);
575: }
576: }
577:
578: free(pointer); /*free the array of pointers to chaincodes*/
579: }
580:
581: /*****BOUNDRY BOX**********************************************************
582: **********************************************************************/
583:
584: /*takes two coordinates as x and y pairs and returns the distence betweem them
585: as a decimal*/
586: float findDist(int x1, int y1, int x2, int y2)
587: {
588: return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
589: }
590:
591: /*1st param: The array of coords that the first point of the major axis is
592: returned in.
593: 2nd: The array of coords that the second point of the major axis is
594: returned in.
595: 3rd: The array of chain codes that are searched through to find the major
596: axes.*/
597: /* Note: the ending condition is when a NULL chainCodes value is reached.
598: Thusly, it works like a string requiring it to have the last legal value
599: followed by a null value.*/
600: void findFirstTwoCorners(coord corner1[], coord corner2[],
601: chainCode** chainCodes)
602: {
603: int i; /*loop counting*/
604: chainCode *temp, *search;
605: double max_dist, test_dist;
606:
607: /*printf("\nFinding first 2 corners.\n");*/
608:
609: /*as long as there are codes to check, keep checking. Note: the ending
610: condition is when a NULL chainCodes value is reached. Thusly, it works
611: like a string requiring it to have the last legal value followed by a
612: null value.*/
613: for(i = 0; (temp = chainCodes[i]) && (i < MAX_CHAINS); i++)
614: {
615: max_dist = 0.0; /*reset this for each iteration*/
616:
617: /*printf("checking list: %d\n", i);*/
618:
619: while(temp) /*while there are still nodes to check in the chain*/
620: {
621: search = temp; /*set the faster moving search pointer to temp,
622: this increases the effiecency a lot compared to
623: setting it equal to the first node..*/
624: while(search)
625: {
626: /*setCPixel(temp->location.x, temp->location.y, green);*/
627:
628: /*determine if found a new maximum distance between two locations*/
629: if((test_dist = findDist(search->location.x, search->location.y,
630: temp->location.x, temp->location.y)) > max_dist)
631: {
632: max_dist = test_dist;
633: corner1[i].x = temp->location.x;
634: corner1[i].y = temp->location.y;
635: corner2[i].x = search->location.x;
636: corner2[i].y = search->location.y;
637: }
638: search = search->next;
639: }
640: temp = temp->next;
641: }
642: /*printf("point1: %d %d\n", max1[i].x, max1[i].y);
643: printf("point2: %d %d\n", max2[i].x, max2[i].y);*/
644: }
645: }
646:
647: /*1st param: Array of coords for the first corner of each chain code.
648: 2nd param: Array of coords for the second corner of each chain code.
649: The first two parameters should equal the first two parameters "returned"
650: from the findFirstTwoCorners() function.
651: 3rd: Array of coords "returned" with the third corners.
652: 4th: Array of coords "returned" with the fourth corners.
653: 5th: Pointer pointing to the array of chaincode pointers, obtained from
654: showChain().*/
655: void findSecondTwoCorners(coord corner1[], coord corner2[], coord corner3[],
656: coord corner4[], chainCode** chain_code_array)
657: {
658: int i; /*loop counting*/
659: chainCode* temp;
660: float temp_dist1, temp_dist2; /*distance between point and each corner*/
661: coord canidate_coord1, temp_coord;
662: float canidate_dist1, max_dist;
663: int corner_count;
664:
665: /*printf("\nFinding last 2 corners.\n\n");*/
666:
667: /*for each chain code find the corners*/
668: for(i = 0; chain_code_array[i] && i < MAX_CHAINS; i++)
669: {
670: temp = chain_code_array[i];
671:
672: /*reset these for the next chain code*/
673: max_dist = 0.0;
674: corner_count = 1;
675:
676: while(temp) /*while there are nodes in the chain code to check*/
677: {
678: /*setCPixel(temp->location.x, temp->location.y, color1);*/
679:
680: /*determine the first canidate coord for corner 3/4*/
681: if(((temp->location.x == corner1[i].x)
682: && (temp->location.y == corner1[i].y))
683: || ((temp->location.x == corner2[i].x)
684: && (temp->location.y == corner2[i].y)))
685: {
686: /*if this corner found is the first of the two allready known
687: corners, then set the first canidate coord data and reset data
688: to find the next canidate corner point*/
689: if(corner_count == 1)
690: {
691: canidate_coord1.x = temp_coord.x;
692: canidate_coord1.y = temp_coord.y;
693: canidate_dist1 = max_dist;
694:
695: corner_count = 2; /*set for next corner*/
696: max_dist = 0.0;
697: }
698: else if(corner_count == 2)
699: {
700: /*the second canidate is always a corner*/
701: corner4[i].x = temp_coord.x;
702: corner4[i].y = temp_coord.y;
703:
704: max_dist = 0.0; /*set for next corner canidate*/
705: }
706: }
707:
708: /*calculate the distance between the current point being checked and
709: each corner point*/
710: temp_dist1 = findDist(corner1[i].x, corner1[i].y, temp->location.x,
711: temp->location.y);
712: temp_dist2 = findDist(corner2[i].x, corner2[i].y, temp->location.x,
713: temp->location.y);
714:
715: /*if the current point is the furthest away sofar, store this point
716: untill it is overridden or becomes a canidate point*/
717: if((temp_dist1 + temp_dist2) > max_dist)
718: {
719: temp_coord.x = temp->location.x;
720: temp_coord.y = temp->location.y;
721:
722: max_dist = (temp_dist1 + temp_dist2);
723: }
724:
725: temp = temp->next; /*advance*/
726: }
727:
728: /*from the three canidate coords find the two real corners.*/
729: /*the second canidate will always be a corner, must test 1 vs 3, where
730: three is in the variables temp_coord and max_dist.*/
731: if(canidate_dist1 > max_dist) /*first canidate*/
732: {
733: corner3[i].x = canidate_coord1.x;
734: corner3[i].y = canidate_coord1.y;
735: }
736: else /*third canidate*/
737: {
738: corner3[i].x = temp_coord.x;
739: corner3[i].y = temp_coord.y;
740: }
741: /*printf("corner3: (%d, %d) corner4: (%d, %d)\n", corner3[i].x,
742: corner3[i].y, corner4[i].x, corner4[i].y);*/
743: }
744: }
745:
746: /*takes a pointer to an image, and a pointer pointing to an array of
747: chain codes pointers, here each chainCode pointer needs to be accessed
748: by calculating the memory address.*/
749: void showBound(PGMImage *original, chainCode** chainCodes)
750: {
751: int i;
752:
753: /*find the first two corners. they will be across a diagnal.*/
754: findFirstTwoCorners(corner1, corner2, chainCodes);
755: /*find the second two corners. they will be across a diagnal too.*/
756: findSecondTwoCorners(corner1, corner2, corner3, corner4, chainCodes);
757: /*
758: for(i = 0; chainCodes[i] && i < MAX_CHAINS; i++)
759: {
760: setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow);
761: setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow);
762: setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow);
763: setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow);
764: setCPixel(corner1[i].x, corner1[i].y, purple);
765: setCPixel(corner2[i].x, corner2[i].y, purple);
766: setCPixel(corner3[i].x, corner3[i].y, purple);
767: setCPixel(corner4[i].x, corner4[i].y, purple);
768: }*/
769: }
770:
771: /**********************File I/O functions*******************************/
772: /***********************************************************************/
773:
774: /*Gets an ascii color pgm image file (type P3).*/
775: void getPGMfile (char filename[], PGMImage *img)
776: {
777: FILE *in_file;
778: char ch;
779: int row, col, type;
780:
781: in_file = fopen(filename, "r");
782: if (in_file == NULL)
783: {
784: fprintf(stderr, "Error: Unable to open file %s\n\n", filename);
785: exit(8);
786: }
787:
788: printf("\nReading image file: %s\n", filename);
789:
790: /*determine pgm image type (only type three can be used)*/
791: ch = getc(in_file);
792: if(ch != 'P')
793: {
794: printf("ERROR(1): Not valid pgm/ppm file type\n");
795: exit(1);
796: }
797: ch = getc(in_file);
798: /*convert the one digit integer character to integer(48 == '0')*/
799: type = ch - 48;
800: if((type != 3) && (type != 6))
801: {
802: printf("ERROR(2): Not valid pgm/ppm file type\n");
803: exit(1);
804: }
805:
806: while(getc(in_file) != '\n'); /* skip to end of line*/
807:
808: while (getc(in_file) == '#'); /* skip comments lines */
809: {
810: while (getc(in_file) != '\n'); /* skip to end of line */
811: }
812:
813: fseek(in_file, -1, SEEK_CUR); /* backup one character */
814:
815: fscanf(in_file,"%d", &((*img).width));
816: fscanf(in_file,"%d", &((*img).height));
817: fscanf(in_file,"%d", &((*img).maxVal));
818:
819: printf("\n width = %d",(*img).width);
820: printf("\n height = %d",(*img).height);
821: printf("\n maxVal = %d",(*img).maxVal);
822: printf("\n");
823:
824: if (((*img).width > MAX) || ((*img).height > MAX))
825: {
826: printf("\n\n***ERROR - image too big for current image structure***\n\n");
827: exit(1);
828: }
829:
830: if(type == 3) /*uncompressed ascii file*/
831: {
832: for (row=(*img).height-1; row>=0; row--)
833: for (col=0; col<(*img).width; col++)
834: {
835: fscanf(in_file,"%d", &((*img).data[row][col].red));
836: fscanf(in_file,"%d", &((*img).data[row][col].green));
837: fscanf(in_file,"%d", &((*img).data[row][col].blue));
838: }
839: }
840: else if(type == 6) /*compressed file*/
841: {
842: while(getc(in_file) != '\n'); /*skip to end of line*/
843:
844: for (row=(*img).height-1; row>=0; row--)
845: for (col=0; col<(*img).width; col++)
846: {
847: (*img).data[row][col].red = getc(in_file);
848: (*img).data[row][col].green = getc(in_file);
849: (*img).data[row][col].blue = getc(in_file);
850: }
851: }
852:
853: fclose(in_file);
854: printf("\nDone reading file.\n");
855: }
856:
857:
858: void save(PGMImage *img)
859: {
860: int i, j, nr, nc, k;
861: int red, green, blue;
862: FILE *iop;
863:
864: nr = img->height;
865: nc = img->width;
866:
867: iop = fopen("image1.pgm", "w");
868: fprintf(iop, "P3\n");
869: fprintf(iop, "%d %d\n", nc, nr);
870: fprintf(iop, "255\n");
871:
872: k = 1;
873: for(i = nr - 1; i >= 0; i--)
874: {
875: for(j = 0; j < nc; j++)
876: {
877: red = img->data[i][j].red;
878: green = img->data[i][j].green;
879: blue = img->data[i][j].blue;
880: if(red < 0)
881: {
882: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
883: printf(" Setting red to zero\n");
884: red = 0;
885: }
886: if(green < 0)
887: {
888: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
889: printf(" Setting green to zero\n");
890: green = 0;
891: }
892: if(blue < 0)
893: {
894: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
895: printf(" Setting green to zero\n");
896: blue = 0;
897: }
898: if(red > 255)
899: {
900: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
901: printf(" Setting red to 255\n");
902: red = 255;
903: }
904: if(green > 255)
905: {
906: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
907: printf(" Setting green to 255\n");
908: green = 255;
909: }
910: if(blue > 255)
911: {
912: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
913: printf(" Setting blue to 255\n");
914: blue = 255;
915: }
916:
917: if(k % 10)
918: {
919: fprintf(iop, "%d ", red);
920: fprintf(iop, "%d ", green);
921: fprintf(iop, "%d ", blue);
922: }
923: else /*for newline*/
924: {
925: fprintf(iop, "%d\n", red);
926: fprintf(iop, "%d\n", green);
927: fprintf(iop, "%d\n", blue);
928: }
929: k++;
930: }
931: }
932: fprintf(iop, "\n");
933: fclose(iop);
934: }
935:
936:
937: /****Calculation & drawing functions of the image translations**********
938: ***********************************************************************/
939:
940: void showColor (PGMImage *img)
941: {
942: int i, j; /*loop counting: i = y, j = x*/
943:
944: GLubyte checkImage[(*img).height][(*img).width][3];
945:
946: for(i = 0; i < (*img).height; i++)
947: {
948: for(j = 0; j < (*img).width; j++)
949: {
950: checkImage[i][j][0] = (GLubyte) (*img).data[i][j].red;
951: checkImage[i][j][1] = (GLubyte) (*img).data[i][j].green;
952: checkImage[i][j][2] = (GLubyte) (*img).data[i][j].blue;
953: }
954: }
955:
956: glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
957: glRasterPos2f(-1, -1);
958: glDrawPixels((*img).width, (*img).height, GL_RGB,
959: GL_UNSIGNED_BYTE, checkImage);
960:
961: /*first check for non-null pointer, next check for dereferenced pointers
962: in the array of head pointers and lastly make sure things stay in
963: bound of the max incase all MAX_CHAINS number of chains are used.*/
964: /*draw_abstract_lines is the global that holds the number of "objects"
965: to draw abstract information for*/
966: for(i = 0; i < draw_abstract_lines && i < MAX_CHAINS; i++)
967: {
968: setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow);
969: setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow);
970: setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow);
971: setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow);
972: setCPixel(corner1[i].x, corner1[i].y, purple);
973: setCPixel(corner2[i].x, corner2[i].y, purple);
974: setCPixel(corner3[i].x, corner3[i].y, purple);
975: setCPixel(corner4[i].x, corner4[i].y, purple);
976: }
977:
978: if(draw_abstract_board >= 0)
979: {
980: setCLines(corner1[draw_abstract_board].x,
981: corner1[draw_abstract_board].y,
982: corner3[draw_abstract_board].x,
983: corner3[draw_abstract_board].y,blue);
984: setCLines(corner4[draw_abstract_board].x,
985: corner4[draw_abstract_board].y,
986: corner2[draw_abstract_board].x,
987: corner2[draw_abstract_board].y,blue);
988: setCLines(corner3[draw_abstract_board].x,
989: corner3[draw_abstract_board].y,
990: corner2[draw_abstract_board].x,
991: corner2[draw_abstract_board].y,blue);
992: setCLines(corner4[draw_abstract_board].x,
993: corner4[draw_abstract_board].y,
994: corner1[draw_abstract_board].x,
995: corner1[draw_abstract_board].y,blue);
996: setCPixel(corner1[draw_abstract_board].x,
997: corner1[draw_abstract_board].y, red);
998: setCPixel(corner2[draw_abstract_board].x,
999: corner2[draw_abstract_board].y, red);
1000: setCPixel(corner3[draw_abstract_board].x,
1001: corner3[draw_abstract_board].y, red);
1002: setCPixel(corner4[draw_abstract_board].x,
1003: corner4[draw_abstract_board].y, red);
1004: }
1005: glFlush();
1006: }
1007:
1008: void camera_correction(PGMImage* new_img, PGMImage* org_img)
1009: {
1010: int row, col, img_row, img_col; /*loop counting*/
1011:
1012: /*camera parameters*/
1013: float height = 30; /*height of camera in cm*/
1014: float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/
1015: float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/
1016:
1017: /*temporary varaibles*/
1018: float angular_height_corr;
1019: float angular_side_corr;
1020: int x_coord, y_coord;
1021:
1022: memset(new_img, 0, sizeof(PGMImage));
1023: (*new_img).height = (*org_img).height;
1024: (*new_img).width = (*org_img).width;
1025: (*new_img).maxVal = (*org_img).maxVal;
1026:
1027: for (row=(*org_img).height-1; row>=0; row--)
1028: for (col=0; col<(*org_img).width; col++)
1029: {
1030: /*img_row -= (*org_img).height / 2;
1031: img_col = col - (*org_img).width / 2;*/
1032:
1033: angular_height_corr =
1034: (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1));
1035: angular_side_corr =
1036: (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1));
1037:
1038: angular_height_corr /= 2;
1039: /*angular_side_corr /= 2;*/
1040: /*height *= 2;*/
1041: height = 150;
1042:
1043: x_coord = (int)
1044: (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr));
1045: y_coord = (int)
1046: (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr));
1047:
1048: /*x_coord += (*org_img).width / 2;*/
1049: y_coord += (*org_img).height / 2;
1050:
1051: /*printf("org: (%d, %d) new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/
1052:
1053: pxlcpy(new_img, y_coord, x_coord, org_img, row, col);
1054: }
1055: }
1056:
1057: void new_corr(PGMImage* new_img, PGMImage* org_img)
1058: {
1059: /*i and j are the left half, k and l are the right half*/
1060: float i, k; /*loop counting*/
1061: int j, l, row; /*loop counting*/
1062: int old_i, old_k;
1063:
1064: float ins_s = 2; /*insert constant starting value*/
1065: float ins_k = ins_s; /*insert constant*/
1066:
1067: /*The halfway marks in the width.*/
1068: int mid_width_left = ((*new_img).width / 2) - 1;
1069: int mid_width_right = ((*new_img).width / 2);
1070:
1071: /*just to be thourough clear the memory and reset maxes*/
1072: memset(new_img, 0, sizeof(PGMImage));
1073: (*new_img).height = (*org_img).height;
1074: (*new_img).width = (*org_img).width;
1075: (*new_img).maxVal = (*org_img).maxVal;
1076:
1077: /*Loop through each row from top to bottom...*/
1078: for(row = ((*new_img).height - 1); row >= 0; row--)
1079: {
1080: /*...reset moire interference removal counter...*/
1081: old_i = ((*new_img).width / 2) - 1;
1082: old_k = ((*new_img).width / 2);
1083:
1084: /*...so each half is ajusted to remove perspective effect...*/
1085: for(i = j = mid_width_left, k = l = mid_width_right
1086: ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width
1087: ; i -= ins_k, j--, k += ins_k, l++)
1088: {
1089: for(;old_i >= (int)i; old_i--) /*...in the left half...*/
1090: pxlcpy(new_img, row, old_i, org_img, row, j);
1091: for(;old_k <= (int)k; old_k++) /*...in the right half.*/
1092: pxlcpy(new_img, row, old_k, org_img, row, l);
1093: }
1094: /*Move the new image x_coord pixel counter to next new image pixel*/
1095: ins_k -= ((ins_s - 1.0) / (*new_img).height);
1096: }
1097: }
1098:
1099: void color_to_gray(PGMImage* new_img, PGMImage* org_img)
1100: {
1101: int row, col; /*loop counting*/
1102: RGB_INT cur_pxl; /*current pixel*/
1103:
1104: (*new_img).height = (*org_img).height;
1105: (*new_img).width = (*org_img).width;
1106: (*new_img).maxVal = (*org_img).maxVal;
1107:
1108: /*Starting with the top row...*/
1109: for(row = (*new_img).height - 1; row >= 0; row--)
1110: for(col = 0; col < (*new_img).width - 1; col++)
1111: {
1112: cur_pxl = (*org_img).data[row][col]; /*more readable*/
1113:
1114: /*convert each RGB to the average of the original*/
1115: (*new_img).data[row][col].red = rgb_avg(cur_pxl);
1116: (*new_img).data[row][col].green = rgb_avg(cur_pxl);
1117: (*new_img).data[row][col].blue = rgb_avg(cur_pxl);
1118: }
1119: }
1120:
1121: void moravec(PGMImage* new_img, PGMImage* org_img)
1122: {
1123: int row, col; /*loop counting*/
1124: int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1125: int running_sum;
1126: float K = .5; /*.125 according to org. formula, but .5 is brighter*/
1127: int max_val = 0, row_max, col_max; /* max porportion value in image*/
1128:
1129: memset(new_img, 0, sizeof(PGMImage));
1130: (*new_img).height = (*org_img).height;
1131: (*new_img).width = (*org_img).width;
1132: (*new_img).maxVal = (*org_img).maxVal;
1133:
1134: /*starting at the top row*/
1135: for(row = (*new_img).height - 1 - 1; row > 0; row--)
1136: for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/
1137: {
1138: i = row;
1139: j = col;
1140: running_sum = 0;
1141:
1142: /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1143: for(k = i - 1; k <= i + 1; k++) /*row*/
1144: for(l = j - 1; l <= j + 1; l++) /*column*/
1145: running_sum += abs(rgb_avg((*org_img).data[k][l]) -
1146: rgb_avg((*org_img).data[i][j]));
1147:
1148: /*assign the new pixel value*/
1149: (*new_img).data[row][col].red = (int)(K * running_sum);
1150: (*new_img).data[row][col].green = (int)(K * running_sum);
1151: (*new_img).data[row][col].blue = (int)(K * running_sum);
1152: }
1153: }
1154:
1155: /*returns the number of objects found*/
1156: int detect_corners(PGMImage* org_img)
1157: {
1158: int i; /*temporarily holds number of chaincodes*/
1159:
1160: glPointSize(4); /*make points more visible, if desired*/
1161: glLineWidth(4);
1162:
1163: chain_codes = showChain(org_img);
1164: showBound(org_img, chain_codes);
1165:
1166: /*when this stops, i holds the number of chaincodes*/
1167: for(i = 0; (i < MAX_CHAINS) && chain_codes[i]; i++);
1168:
1169: free_chaincode(chain_codes);
1170:
1171: return i;
1172: }
1173:
1174: /*determines which object is the game board and determine moves made in
1175: the game.*/
1176: /*takes the number of object corners (equal to # of chaincodes) as param.*/
1177: int detect_game(int num_of_corners)
1178: {
1179: float length2to4[MAX_CHAINS], length1to3[MAX_CHAINS]; /*side pairs*/
1180: float length1to4[MAX_CHAINS], length2to3[MAX_CHAINS]; /*side pairs*/
1181:
1182: float error24to13[MAX_CHAINS], error14to23[MAX_CHAINS];
1183:
1184: int i; /*loop counting*/
1185: float denom_check; /*make sure denominators are not zero*/
1186:
1187: /*the most likely object (0 to num_of_corners) that is to be considered
1188: as the board. The float is the error associated with this object.*/
1189: int most_likely = -1;
1190: float ml_error = FLT_MAX; /*just to make sure*/
1191:
1192: for(i = 0; i < num_of_corners; i++)
1193: {
1194: /*since points 1 & 2 are at a diagnal, and 3 & 4 are at a diagnol,
1195: then the slopes between 2 and 4 and 1 and three should be close
1196: in value.*/
1197: length2to4[i] = findDist(corner2[i].x, corner2[i].y, corner4[i].x,
1198: corner4[i].y);
1199: length1to3[i] = findDist(corner1[i].x, corner1[i].y, corner3[i].x,
1200: corner3[i].y);
1201:
1202: /*the other side pair*/
1203: length1to4[i] = findDist(corner1[i].x, corner1[i].y, corner4[i].x,
1204: corner4[i].y);
1205:
1206: length2to3[i] = findDist(corner2[i].x, corner2[i].y, corner3[i].x,
1207: corner3[i].y);
1208:
1209:
1210: denom_check = fabs((length2to4[i] + length1to3[i]) / 2);
1211: if(denom_check == 0)
1212: {
1213: /*the only way to possibly pull this off is if one point is
1214: is considered more than one corner. This is most likely
1215: to happen where the chain was only two or three nodes long.*/
1216: /*Just set the error to the maximum value obtained from float.h,
1217: since such a small chain is not what we are looking for.*/
1218:
1219: error24to13[i] = FLT_MAX;
1220: }
1221: else
1222: error24to13[i] = fabs(length2to4[i] - length1to3[i]) / denom_check;
1223: /*fabs((length2to4[i] + length1to3[i]) / 2);*/
1224:
1225: denom_check = fabs((length1to4[i] + length2to3[i]) / 2);
1226: if(denom_check == 0)
1227: {
1228: /*the only way to possibly pull this off is if one point is
1229: is considered more than one corner. This is most likely
1230: to happen where the chain was only two or three nodes long.*/
1231: /*Just set the error to the maximum value obtained from float.h,
1232: since such a small chain is not what we are looking for.*/
1233:
1234: error14to23[i] = FLT_MAX;
1235: }
1236: else
1237: error14to23[i] = fabs(length1to4[i] - length2to3[i]) / denom_check;
1238: /*fabs((length1to4[i] + length2to3[i]) / 2);*/
1239:
1240: /*determine if the current object is considered the most likely to
1241: be the ttt board so far.*/
1242: if(ml_error > ((error24to13[i] + error14to23[i]) / 2))
1243: {
1244: most_likely = i;
1245: ml_error = ((error24to13[i] + error14to23[i]) / 2);
1246: }
1247: }
1248:
1249: printf("Object %d is most likely the board with %f\%% error.\n",
1250: most_likely, ml_error * 100);
1251:
1252: return most_likely;
1253: }
1254:
1255:
1256: /* =================================================================
1257: * Callback functions.
1258: *
1259: * color = displayed graphics in window
1260: * menu = menu event handling
1261: * keyboard = deyboard event handling
1262: * ----------------------------------------------------------------- */
1263: void color(void)
1264: {
1265: /*glClear (GL_COLOR_BUFFER_BIT);*/
1266:
1267: /* printf("\nDrawing Original image...\n");*/
1268: showColor(img_cur);
1269:
1270: /*glFlush();*/
1271: }
1272:
1273: void buffer()
1274: {
1275: draw_abstract_lines = detect_corners(img_cur);
1276:
1277: glutPostRedisplay();
1278: }
1279:
1280: #define RESTART 0
1281: #define CAMERA_CORRECTION 1
1282: #define X2_C_CORR 2
1283: #define NEW_CORR 3
1284: #define COLOR_TO_GRAY 4
1285: #define MORAVEC 5
1286: #define CORNERS 6
1287: #define BUFFERS 7
1288: #define GAME 8
1289:
1290: void menu(int selection)
1291: {
1292: if(selection == RESTART)
1293: {
1294: memcpy(img1, img0, sizeof(PGMImage));
1295: img_cur = img0;
1296: draw_abstract_lines = -1;
1297: draw_abstract_board = -1;
1298: }
1299: if(selection == CAMERA_CORRECTION)
1300: {
1301: printf("Starting camera correction\n");
1302: camera_correction(img1, img0);
1303: img_cur = img1;
1304: draw_abstract_lines = -1;
1305: draw_abstract_board = -1;
1306: }
1307: if(selection == X2_C_CORR)
1308: {
1309: printf("Starting camera correction\n");
1310: camera_correction(img1, img0);
1311: camera_correction(img2, img1);
1312: img_cur = img2;
1313: draw_abstract_lines = -1;
1314: draw_abstract_board = -1;
1315: }
1316: if(selection == NEW_CORR)
1317: {
1318: new_corr(img1, img0);
1319: img_cur = img1;
1320: draw_abstract_lines = -1;
1321: draw_abstract_board = -1;
1322: }
1323: if(selection == COLOR_TO_GRAY)
1324: {
1325: color_to_gray(img1, img0);
1326: img_cur = img1;
1327: draw_abstract_lines = -1;
1328: draw_abstract_board = -1;
1329: }
1330: if(selection == MORAVEC)
1331: {
1332: moravec(img1, img0);
1333: img_cur = img1;
1334: draw_abstract_lines = -1;
1335: draw_abstract_board = -1;
1336: }
1337: if(selection == CORNERS)
1338: {
1339: draw_abstract_lines = detect_corners(img_cur);
1340: }
1341: if(selection == BUFFERS)
1342: {
1343:
1344: if(is_buffered == FALSE)
1345: {
1346: glutIdleFunc(buffer);
1347: is_buffered = TRUE;
1348: }
1349: else
1350: {
1351: glutIdleFunc(NULL);
1352: is_buffered = FALSE;
1353: }
1354: }
1355: if(selection == GAME)
1356: {
1357: draw_abstract_board = detect_game(detect_corners(img_cur));
1358: }
1359:
1360: glutPostRedisplay();
1361: }
1362:
1363: void keyboard(unsigned char key, int x, int y)
1364: {
1365: switch (key)
1366: {
1367: case 27:
1368: exit(0);
1369: break;
1370: }
1371: }
1372:
1373: void mouse(int button, int state, int x, int y)
1374: {
1375: char temp[50];
1376:
1377: if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
1378: {
1379: sprintf(temp, "(x, y): (%d, %d) red: %d green: %d blue: %d\n",
1380: x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red,
1381: (*img_cur).data[VSIZE - y][x].green,
1382: (*img_cur).data[VSIZE - y][x].blue);
1383: setCRect(0, 0, 200, 12, black);
1384: glColor3f(1.0, 0.0, 0.0);
1385: drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp);
1386: glFlush();
1387: }
1388: }
1389:
1390:
1391: /* =================================================================
1392: * init() & parse_command_line()
1393: * initalize none-OpenGL related things.
1394: * ----------------------------------------------------------------- */
1395:
1396: /*set global flag variables from things specified at commandline.*/
1397: /*return the filename specified, if none specified exit().*/
1398: char* parse_command_line(int argc, char** argv)
1399: {
1400: /*parse the command line*/
1401: if(argc == 1)
1402: {
1403: printf("To few parameters.\n");
1404: printf("Usage: research <file.pgm>\n");
1405: exit(1);
1406: }
1407: else if(argc == 2)
1408: {
1409: return argv[1];
1410: }
1411: else
1412: {
1413: printf("To many parameters.\n");
1414: printf("Usage: research <file.pgm>\n");
1415: exit(1);
1416: }
1417: }
1418:
1419: char* init (int argc, char** argv)
1420: {
1421: char* PGMfileName;/*pointer to the string containing the filename*/
1422:
1423: /*parse the command line*/
1424: PGMfileName = parse_command_line(argc, argv);
1425:
1426: /*
1427: * Read in image file. - note: sets our global values, too.
1428: * ----------------------------------------------------------------- */
1429:
1430: img0 = (PGMImage*) malloc(sizeof(PGMImage));
1431: getPGMfile(PGMfileName, img0);
1432: HSIZE = (*img0).width;
1433: VSIZE = (*img0).height;
1434: MVAL = (*img0).maxVal;
1435:
1436: img_cur = img0; /*VERY IMPORTANT to set this*/
1437:
1438: /*allocate memory for second image*/
1439: img1 = (PGMImage*) malloc(sizeof(PGMImage));
1440: memcpy(img1, img0, sizeof(PGMImage));
1441: /*(*img1).width = HSIZE;
1442: (*img1).height = VSIZE;
1443: (*img1).maxVal = 255;*/
1444:
1445: img2 = (PGMImage*) malloc(sizeof(PGMImage));
1446: memcpy(img2, img0, sizeof(PGMImage));
1447:
1448: memset(corner1, 0, sizeof(coord) * MAX_CHAINS);
1449: memset(corner2, 0, sizeof(coord) * MAX_CHAINS);
1450: memset(corner3, 0, sizeof(coord) * MAX_CHAINS);
1451: memset(corner4, 0, sizeof(coord) * MAX_CHAINS);
1452:
1453: return PGMfileName;
1454: }
1455:
1456:
1457: int main(int argc, char** argv)
1458: {
1459: char* PGMfileName;
1460: int WindowID; /*unique window id, there is only one used*/
1461: int i; /*looping variable*/
1462:
1463: /*
1464: * Call our init function to define non-OpenGL related things.
1465: * Have init return a pointer to the filename, used to display the
1466: * filename in the titlebar of the window.
1467: * ----------------------------------------------------------------- */
1468: PGMfileName = init (argc, argv);
1469:
1470: /*
1471: * Initialize the glut package.
1472: * ----------------------------------------------------------------- */
1473: glutInit(&argc, argv);
1474: glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
1475:
1476: /*
1477: * Define a new window (its size, position and title).
1478: * ----------------------------------------------------------------- */
1479: glutInitWindowSize (HSIZE, VSIZE); /*size*/
1480: glutInitWindowPosition (10, 10); /*position*/
1481: WindowID = glutCreateWindow (PGMfileName); /*title*/
1482: glutSetWindow(WindowID);
1483: glutDisplayFunc(color);
1484:
1485: /*
1486: * select clearing color - white
1487: */
1488: glClearColor (1.0, 1.0, 1.0, 0.0);
1489:
1490: /*
1491: * initialize viewport values
1492: */
1493: glMatrixMode(GL_PROJECTION);
1494: glLoadIdentity();
1495: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
1496:
1497: /*add menus*/
1498: glutCreateMenu(menu);
1499: glutAddMenuEntry("Restart", RESTART);
1500: /* glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION);
1501: glutAddMenuEntry("2x C. Corr.", X2_C_CORR);*/
1502: glutAddMenuEntry("new corr", NEW_CORR);
1503: glutAddMenuEntry("color to gray", COLOR_TO_GRAY);
1504: glutAddMenuEntry("moravec", MORAVEC);
1505: glutAddMenuEntry("corners", CORNERS);
1506: glutAddMenuEntry("toggle buffering", BUFFERS);
1507: glutAddMenuEntry("detect game", GAME);
1508: glutAttachMenu(GLUT_RIGHT_BUTTON);
1509:
1510: glutMouseFunc(mouse);
1511: glutKeyboardFunc(keyboard);
1512: glutMainLoop();
1513:
1514: /*
1515: * When we reach here, we've left the event loop and are ready to
1516: * exit.
1517: * ----------------------------------------------------------------- */
1518: return 0;
1519: }
1520:
1521:
1522:
1523:
1524:
1525:
1526:
1527:
1528:
1529:
1530:
1531:
1532: