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: