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