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