1:  #include < GL/glut.h >
2:  #include < stdlib.h >
3:  #include < stdio.h >
4:  #include < string.h >
5:  #include < math.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:  /*#ifdef __STDC__
18:  typedef int bool;
19:  #endif*/
20:  
21:  #ifdef MAX_CHAINS
22:  #error "MAX_CHAINS found"
23:  #endif
24:  
25:  /*cartesian coordinate type*/
26:  typedef struct {int x;
27:                  int y;}coord;  
28:  
29:  /*RGB color struct with floats*/ 
30:  /*typedef struct {float red;
31:                  float green;
32:                  float blue;
33:                 }RGB;
34:  */
35:  /*RGB color struct with ints*/  
36:  typedef struct {int red;
37:                  int green;
38:                  int blue;
39:                 }RGB_INT;
40:  
41:  /*number of chain codes stored*/  
42:  /*#define MAX_CHAINS 0010*/
43:  const int MAX_CHAINS = 10;
44:  
45:  /*These constant values are the chain code directions*/
46:  #define NONE      -1
47:  #define EAST      0
48:  #define NORTHEAST 1
49:  #define NORTH     2
50:  #define NORTHWEST 3
51:  #define WEST      4  
52:  #define SOUTHWEST 5
53:  #define SOUTH     6
54:  #define SOUTHEAST 7
55:  
56:  typedef struct chainCode* chain_t;
57:  typedef struct chainCode
58:  {
59:    chain_t prev;
60:    int code;    
61:    coord location; /*absolute pixel location for starting point*/
62:    chain_t next;
63:  }chainCode; /*This struct can be refered to by: struct chainCode or chainCode*/
64:  
65:  struct PGMstructure 
66:  {
67:    int maxVal;
68:    int width;
69:    int height;
70:    RGB_INT data[MAX][MAX];
71:  };
72:  
73:  typedef struct PGMstructure PGMImage;
74:  
75:  /*Evil globals, but not do-able otherwise.*/
76:  static PGMImage *img_cur;
77:  static PGMImage *img0; /*original*/
78:  static PGMImage *img1; /*current*/
79:  static PGMImage *img2; /*current*/
80:  static int HSIZE;
81:  static int VSIZE;
82:  static int MVAL;
83:  
84:  
85:  
86:  
87:  /**************Drawing funcitions************************************/
88:  /********************************************************************/
89:  
90:  void setCPixel(int ix, int iy, RGB_INT color)
91:  /*Same as setIPixel except that the last parameter is an RGB color*/
92:  {
93:    float x = (ix*2.0)/HSIZE - 1.0;
94:    float y = (iy*2.0)/VSIZE - 1.0;
95:  
96:    float red = (float)color.red/(float)MVAL;
97:    float green = (float)color.green/(float)MVAL;
98:    float blue = (float)color.blue/(float)MVAL;
99:  
100:    glColor3f(red, green, blue);
101:    
102:    glBegin(GL_POINTS); 
103:       glVertex2f (x, y);
104:    glEnd();
105:  }
106:  
107:  void setCLines(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
108:  /*Similar as setIPixel except that this one draws a line between the first set
109:    of points given and the second set in the RGB color specified*/
110:  {
111:    float x1 = (ix1*2.0)/HSIZE - 1.0;
112:    float y1 = (iy1*2.0)/VSIZE - 1.0;
113:    float x2 = (ix2*2.0)/HSIZE - 1.0;
114:    float y2 = (iy2*2.0)/VSIZE - 1.0;
115:   
116:    float red = (float)color.red/(float)MVAL;
117:    float green = (float)color.green/(float)MVAL;
118:    float blue = (float)color.blue/(float)MVAL;
119:  
120:    glColor3f(red, green, blue);
121:  
122:    glBegin(GL_LINES);
123:      glVertex2f (x1, y1);
124:      glVertex2f (x2, y2);
125:    glEnd();
126:  }
127:  
128:  void setCRect(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
129:  /*Similar as setIPixel except that this one draws a line between the first set
130:    of points given and the second set in the RGB color specified*/
131:  {
132:    float x1 = (ix1*2.0)/HSIZE - 1.0;
133:    float y1 = (iy1*2.0)/VSIZE - 1.0;
134:    float x2 = (ix2*2.0)/HSIZE - 1.0;
135:    float y2 = (iy2*2.0)/VSIZE - 1.0;
136:   
137:    float red = (float)color.red/(float)MVAL;
138:    float green = (float)color.green/(float)MVAL;
139:    float blue = (float)color.blue/(float)MVAL;
140:  
141:    glColor3f(red, green, blue);
142:  
143:    glBegin(GL_POLYGON);
144:      glVertex2f (x1, y1);
145:      glVertex2f (x1, y2);
146:      glVertex2f (x2, y2);
147:      glVertex2f (x2, y1);
148:    glEnd();
149:  }
150:  
151:  void pxlcpy(PGMImage *dest, int dest_row, int dest_col,
152:  	    PGMImage *src, int src_row, int src_col)
153:  {
154:    /*make sure values are within bounds*/
155:    if(dest_col  > 0 && dest_col <  (*dest).width
156:       && dest_row  > 0 && dest_row <  (*dest).height
157:       && src_col  > 0 && src_col <  (*src).width
158:       && src_row  > 0 && src_row <  (*src).height)
159:    {
160:      (*dest).data[dest_row][dest_col].red =
161:        (*src).data[src_row][src_col].red;
162:  
163:      (*dest).data[dest_row][dest_col].green =
164:        (*src).data[src_row][src_col].green;
165:  
166:      (*dest).data[dest_row][dest_col].blue =
167:        (*src).data[src_row][src_col].blue;
168:    }
169:  } 
170:  
171:  int rgb_avg(RGB_INT cur_pxl)
172:  {
173:     /*convert each RGB to the average of the original*/
174:     return ((cur_pxl.red + cur_pxl.green + cur_pxl.blue) / 3);
175:  }
176:  
177:  /*1st: pixel one of type RGB_INT
178:  2nd: pixel one of type RGB_INT
179:  3rd: differnce allowed to be considered "equal" or close enough*/
180:  int pxlcmp (RGB_INT pxl1, RGB_INT pxl2, int range)
181:  {
182:    return ((abs((rgb_avg(pxl1) - rgb_avg(pxl2)))) <  range);
183:  }
184:  
185:  /* ================================================================= 
186:   * drawString - outputs a string of characters to the graphics port
187:   *
188:   *   x, y:      defines the starting location to draw the text
189:   *               note: this point is the lower left anchor of
190:   *                     the first character - a character's decending
191:   *                     portion would be drawn below this point.
192:   *   theFont:   points to the glut font to be used
193:   *   theString: holds the string to be output -- up to 255 ch
194:   * ----------------------------------------------------------------- */
195:  void drawString(int ix, int iy, void *theFont, char theString[256])
196:  {
197:     float x = (ix*2.0)/HSIZE - 1.0;
198:     float y = (iy*2.0)/VSIZE - 1.0;
199:     int i;
200:     glRasterPos2f(x, y);
201:     for (i = 0; theString[i] != '\0'; i++) /* draw the chars one at a time */
202:       glutBitmapCharacter(theFont, theString[i]);
203:  }
204:  
205:  /******CHAIN CODE************************************************
206:  ****************************************************************/
207:  
208:  /*returns NONE if the chain code loops around itself, otherwise false*/
209:  int checkCode(struct chainCode* beginning, int x_current, int y_current,
210:  	      int x_check, int y_check, int dir)
211:  {
212:     struct chainCode* currentNode = beginning;
213:  
214:     while(currentNode && currentNode- >next)
215:     {
216:        if((currentNode- >location.x == x_current) &&
217:           (currentNode- >location.y == y_current) &&
218:           (currentNode- >code == dir) &&
219:           (currentNode- >next- >location.x == x_check) &&
220:           (currentNode- >next- >location.y == y_check))
221:           return NONE;
222:        else
223:           currentNode = currentNode- >next;
224:     }
225:     return FALSE;
226:  
227:  }
228:  
229:  RGB_INT chainColor = {0, 0, 255};
230:  
231:  /*This function is the intermediate function call during the recursion of the
232:  chain code calculation.
233:  Preconditions:
234:  1st parameter: integer value containing the current direction code.
235:  2nd parameter: integer value containing the potentially new direction code.
236:  3rd parameter: integer value containing the current x coordinate.
237:  4th parameter: integer value containing the current y coordinate.
238:  5th parameter: pointer to the linked list of the chain code.
239:  6th parameter: pointer to the pgm image being used.
240:  Postconditions:  The pixel is drawn and if the checked pixel is a boarder pixel
241:     true is returned, otherwise false is returned.*/
242:  int checkThings(int *dir, int next, int x_current, int y_current, int x_check,
243:     int y_check, struct chainCode **theChain, PGMImage *img,
244:     struct chainCode **beginning)
245:  {
246:     struct chainCode *temp;
247:  
248:     printf("cur: (%d, %d)  check: (%d, %d)  dir: %d  ",
249:  	  x_current, y_current, x_check, y_check, *dir);
250:     printf("pxl_avg org: %d  pxl_chk org: %d\n",
251:  	  rgb_avg((*img).data[y_current][x_current]),
252:  	  rgb_avg((*img).data[y_check][x_check]));
253:        
254:     /*check for being in bounds*/
255:     if((x_check <  0) || (y_check <  0) || (x_check  >= (*img).width) ||
256:        (y_check  >= (*img).height))
257:        return FALSE;
258:  
259:     /*test condition for the end.*/
260:     else if(checkCode(*beginning, x_current, y_current, x_check, y_check,
261:  		     *dir) == NONE)
262:     {
263:        *dir = NONE;
264:        return FALSE;
265:     }
266:  
267:     /*tests if the next pixel is a boundry pixel.  If so does stuff*/
268:     if(pxlcmp((*img).data[y_current][x_current],
269:  	     (*img).data[y_check][x_check], 30))
270:     {
271:        setCPixel(x_check, y_check, chainColor);
272:        glFlush();
273:        *dir = next;
274:  printf("here\n");
275:        temp = (chain_t)malloc(sizeof(struct chainCode));
276:  printf("here2\n");
277:        temp- >next = NULL;
278:        temp- >code = *dir;
279:        temp- >location.x = x_check;
280:        temp- >location.y = y_check;
281:        temp- >prev = *theChain;
282:        if(*theChain)
283:           (*theChain)- >next = temp;  /*now this is a good thing to set.*/
284:        *theChain = temp;  /*advance one*/
285:  
286:        if(*beginning == NULL)
287:           *beginning = *theChain;/*set this for the first node in the list once*/       
288:        return TRUE;   
289:     }
290:     return FALSE;
291:  }  
292:  
293:  /*determines the chain code for a starting pixel*/
294:  /*this chain code uses 8 connectivity*/
295:  /*Note: There are many different coordinate systems at work in this function.*/
296:  /*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
297:  /*   top left is (0, 0).  If it looks strange, look harder!!!*/
298:  /*Preconditions:
299:  1st parameter: pointer to the pgm image being used.
300:  2nd parameter: integer value containing the current x coordinate.
301:  3rd parameter: integer value containing the current y coordinate.
302:  4th parameter: integer value containing the current direction code.
303:  5th parameter: pointer to the linked list of the chain code.
304:  6th parameter: pointer to the linked list of the chain code.*/
305:  /*This function assumes the (0, 0) point is in the lower left*/
306:           
307:  int chaincode(PGMImage *img, int x, int y, int dir,
308:     struct chainCode** theChain, struct chainCode** beginning)   
309:  {
310:     int i; /*loop counting*/
311:     int initial, next, finished;
312:      
313:     /*   if(dir % 2)   /*if dir is odd*/
314:     /* initial = (dir + 6) % 8;
315:     else          /*if dir is even*/
316:     /* initial = (dir + 7) % 8;*/
317:  
318:     initial = (dir + 5) % 8; /*better initail choice?*/
319:  
320:     next = initial; /*set the next direction to search*/
321:  printf("next: %d  x: %d  y: %d\n", next, x, y);   
322:     for(i = 0; i <  8; i++)
323:     {
324:        if(next == EAST)
325:        {
326:           if(checkThings(&dir, EAST, x, y, x + 1, y, theChain, img, beginning))
327:              finished = chaincode(img, x + 1, y, dir, theChain, beginning);
328:        }
329:        else if(next == NORTHEAST)
330:        {
331:           
332:           if(checkThings(&dir, NORTHEAST,  x, y, x + 1, y + 1, theChain, img,
333:              beginning))  
334:              finished = chaincode(img, x + 1, y + 1, dir, theChain, beginning);
335:        }
336:        else if(next == NORTH)   
337:        {  
338:           if(checkThings(&dir, NORTH,  x, y, x, y + 1, theChain, img,
339:              beginning))
340:              finished = chaincode(img, x, y + 1, dir, theChain, beginning);
341:        }
342:        else if(next == NORTHWEST)
343:        {
344:           if(checkThings(&dir, NORTHWEST,  x, y, x - 1, y + 1, theChain, img,
345:              beginning))  
346:              finished = chaincode(img, x - 1, y + 1, dir, theChain, beginning);
347:        }
348:        else if(next == WEST)
349:        {
350:           if(checkThings(&dir, WEST,  x, y, x - 1, y, theChain, img, beginning))
351:              finished = chaincode(img, x - 1, y, dir, theChain, beginning);
352:        }
353:        else if(next == SOUTHWEST)
354:        {  
355:           if(checkThings(&dir, SOUTHWEST,  x, y, x - 1, y - 1, theChain, img,
356:              beginning))  
357:              finished = chaincode(img, x - 1, y - 1, dir, theChain, beginning);
358:        }
359:        else if(next == SOUTH)   
360:        {  
361:           if(checkThings(&dir, SOUTH,  x, y, x, y - 1, theChain, img,beginning))
362:              finished = chaincode(img, x, y - 1, dir, theChain, beginning);
363:        }
364:        else if(next == SOUTHEAST)
365:        {
366:           if(checkThings(&dir, SOUTHEAST,  x, y, x + 1, y - 1, theChain, img,
367:              beginning))
368:              finished = chaincode(img, x + 1, y - 1, dir, theChain, beginning);
369:        }
370:         
371:        /*if the next chaincode function in the recursion or the current state
372:           is the final state of the the chain code; recursively returns DONE
373:           back through all the levels to stop the chain code.*/
374:        if(dir == NONE || finished == NONE)
375:           return NONE;
376:  
377:        /*set next for next iteration*/
378:        next = (next + 1) % 8;
379:     }
380:              
381:  }
382:  
383:  /*returns true if the point is already in one of the chains, false otherwise*/
384:  int alreadyFound(int initThreashFlag, int i, int j, PGMImage* img,
385:     struct chainCode** found, int count)
386:  {
387:     int k;
388:     struct chainCode* temp;
389:           /*this if statement determines if a pixel is not the background*/
390:           if(initThreashFlag <  rgb_avg((*img).data[j][i])) /*collumn major*/
391:           {
392:              /*Now search to determine if the pixel has been found already*/
393:              for(k = 0; k < = count; k++)
394:              {
395:                 temp = (found[k]);
396:                 while(temp)
397:                 {/* if point has already been found*/
398:                    if((temp- >location.x == i) && (temp- >location.y == j))
399:                    {
400:                       j = 0; /*does this work?*/
401:                       return TRUE;
402:                       break;
403:                    } 
404:                    temp = temp- >next;
405:                 }
406:              }
407:           }
408:     return FALSE;
409:  }
410:  
411:  /*saves a chain code to file.  Was usefull during debuging now is just
412:    a cool thing to leave in*/
413:  /*1st: pointer to beginning of a chaincode
414:  2nd: the index of the chain code for destiqushing the 'chain' files*/
415:  void saveChainCode(chainCode* saveChain, int count)
416:  {
417:     struct chainCode* temp = saveChain;
418:     char filename[12];
419:     FILE* outfile;
420:     sprintf(filename, "chain%d", count);
421:     outfile = fopen(filename, "w");   /*output file for chaincode*/
422:     printf("Writing chain code to file %s.\n", filename);
423:  
424:     while(temp)
425:     {
426:     
427:        fprintf(outfile, "%d  %d  %d\n",temp- >location.x,temp- >location.y,
428:           temp- >code);
429:        temp = temp- >next;
430:     }
431:     fclose(outfile);
432:  }
433:  
434:  chainCode** showChain(PGMImage *original)
435:  {
436:     int i, j;  /*loop counting*/
437:     int count = 0; /*array index holder*/
438:     int initThreashFlag = 128, foundFlag = TRUE;
439:     RGB_INT /*chainColor = {255, 0, 255},*/ tempColor = {255, 0, 0};
440:     struct chainCode** beginning, *chain = NULL, *temp, *next_tmep, *temp_loop;
441:     beginning = (chainCode**)
442:       malloc(MAX_CHAINS * sizeof(chainCode*));
443:     
444:     /*Need a temporary threasholded image*/
445:     /*PGMImage *threashed = (PGMImage*) malloc(sizeof(PGMImage));
446:      */               
447:     glPointSize(4); /*make points more visible*/
448:               
449:     /*showThreashold(original, threashed);*/
450:     
451:     /*Use starting pixel as defualt.  This is partially based on the fact that
452:     most likely a corner will be background and not an object.*/
453:     /*the image assumes that (0, 0) is in the bottom left, I assume that
454:       (0, 0) is in the upper left.  This is handled here.*/
455:     /*initThreashFlag = (*threashed).data[(*threashed).height - 1][0];*/
456:  
457:     for(i = 0; i <  10; i++) beginning[i] = NULL;/*initailize pointer array.*/  
458:     
459:     /*search image until a pixel is found with threasholded value of the
460:     object.  i & j will then contain the starting coordinate.*/
461:     for(i = 0; i <  (*original).width; i++) /*x direction*/
462:     {
463:        for(j = (*original).height - 1; j  >= 0; j--) /*y direction*/
464:        {
465:           /*skip to the next iteration if pixel isn't "good" enough*/
466:           if(rgb_avg((*original).data[j][i]) <  initThreashFlag)
467:           {
468:              continue;
469:           }        
470:           /*skip to the next iteration, which will be at the top of the next
471:             collumn*/
472:           else if(alreadyFound(initThreashFlag, i, j, original, beginning,
473:                  count))
474:           {
475:              j = 0; /*reseting to make this the last iteration without reseting
476:                         search to the top of next collumn*/
477:              continue;
478:           }
479:           else
480:           {
481:  /*printf("chaincode: %d\n", count);*/
482:             /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/
483:              chain = NULL; /*reset this to seperate the chaincodes*/
484:  
485:  chainColor.blue = (128 + 10 * count) * (count % 2);
486:  chainColor.green =(128 + 10 * count) * (count % 3);
487:  chainColor.red =(128 + 10 * count);
488:              /*find the chaincode for the current starting pixel*/
489:              chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]);
490:  
491:  	    if(beginning[count] != NULL) /*avoid writing zero length chains*/
492:  	    {
493:  	       saveChainCode(beginning[count], count);
494:  	       count++; /*advance the beginning counter*/
495:  	    }
496:  
497:  	    /*force end of loops, leaving code when finished looping
498:  	      to still execute*/
499:  	    if(count  >= MAX_CHAINS)
500:  	       i = (*original).width;
501:  
502:              j = 0; /*reset search to start at top on next pass.  This the
503:                       setting for stopping condition for the current j loop.*/
504:              break; /*Quick fix?*/
505:           }
506:        }   
507:     }
508:     printf("Done finding chain code(s).  %d were found.\n", count);
509:     return beginning;
510:  }
511:  
512:  
513:  /**********************File I/O functions*******************************/
514:  /***********************************************************************/
515:  
516:  /*Gets an ascii color pgm image file (type P3).*/
517:  void getPGMfile (char filename[], PGMImage *img)
518:  {
519:    FILE *in_file;
520:    char ch;
521:    int row, col;
522:  
523:    in_file = fopen(filename, "r");
524:    if (in_file == NULL)
525:    {
526:      fprintf(stderr, "Error: Unable to open file %s\n\n", filename);
527:      exit(8);
528:    }
529:  
530:    printf("\nReading image file: %s", filename);
531:    
532:    do                                        /* skip header identifier */
533:      ch = getc(in_file);
534:    while (ch != '\n');
535:  
536:    do                                        /* skip comments lines    */
537:    {
538:      while (ch != '\n') ch = getc(in_file);  /*  flush to end of line  */
539:      ch = getc(in_file);
540:    } while (ch == '#');
541:   
542:    fseek(in_file, -1, SEEK_CUR);             /* backup one character   */
543:  
544:    fscanf(in_file,"%d", &((*img).width));
545:    fscanf(in_file,"%d", &((*img).height));
546:    fscanf(in_file,"%d", &((*img).maxVal));
547:  
548:    printf("\n width  = %d",(*img).width);
549:    printf("\n height = %d",(*img).height);
550:    printf("\n maxVal = %d",(*img).maxVal);
551:    printf("\n");
552:   
553:    if (((*img).width  > MAX) || ((*img).height  > MAX))
554:    {
555:      printf("\n\n***ERROR - image too big for current image structure***\n\n");
556:      exit(0);
557:    }
558:  
559:    for (row=(*img).height-1; row >=0; row--)
560:      for (col=0; col< (*img).width; col++)
561:      {
562:        fscanf(in_file,"%d", &((*img).data[row][col].red) );
563:        fscanf(in_file,"%d", &((*img).data[row][col].green));
564:        fscanf(in_file,"%d", &((*img).data[row][col].blue));
565:      }
566:    fclose(in_file);
567:    printf("\nDone reading file.\n");
568:  }
569:  
570:  
571:  void save(PGMImage *img)
572:  {
573:     int i, j, nr, nc, k;
574:     int red, green, blue;
575:     FILE *iop;
576:  
577:     nr = img- >height;
578:     nc = img- >width;
579:      
580:     iop = fopen("image1.pgm", "w");
581:     fprintf(iop, "P3\n");
582:     fprintf(iop, "%d %d\n", nc, nr);
583:     fprintf(iop, "255\n");
584:      
585:     k = 1;
586:     for(i = nr - 1; i  >= 0; i--)
587:     {
588:        for(j = 0; j <  nc; j++)
589:        {
590:           red = img- >data[i][j].red;
591:           green = img- >data[i][j].green;
592:           blue = img- >data[i][j].blue;
593:           if(red <  0)
594:           {
595:              printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
596:              printf("           Setting red to zero\n");
597:              red = 0;
598:           }
599:           if(green <  0)   
600:           {
601:              printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
602:              printf("           Setting green to zero\n");
603:              green = 0;
604:           }
605:           if(blue <  0)   
606:           {
607:              printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
608:              printf("           Setting green to zero\n");
609:              blue = 0;
610:           }
611:           if(red  > 255) 
612:           {   
613:              printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
614:              printf("           Setting red to 255\n");
615:              red = 255;
616:           }
617:           if(green  > 255)
618:           {
619:              printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
620:              printf("           Setting green to 255\n");
621:              green = 255;
622:           }
623:           if(blue  > 255)
624:           {
625:              printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
626:              printf("           Setting blue to 255\n");
627:              blue = 255;
628:           }
629:  
630:           if(k % 10)
631:           {
632:              fprintf(iop, "%d ", red);
633:              fprintf(iop, "%d ", green);
634:              fprintf(iop, "%d ", blue);
635:           }
636:           else /*for newline*/
637:           {
638:              fprintf(iop, "%d\n", red);
639:              fprintf(iop, "%d\n", green);
640:              fprintf(iop, "%d\n", blue);
641:           }
642:           k++;
643:        }
644:     }
645:     fprintf(iop, "\n");
646:     fclose(iop);
647:  }
648:  
649:  
650:  
651:  
652:  /****Calculation & drawing functions of the image translations**********
653:  ***********************************************************************/
654:              
655:            
656:  void showColor (PGMImage *img)
657:  {
658:     int row, col; /*y, x*/
659:     /*for (row=(*img).height-1; row >=0; row--)
660:        for (col=0; col< (*img).width; col++)
661:        {
662:  	 
663:  	 setCPixel(col, row, (*img).data[row][col]);
664:  	 }*/
665:  
666:     int i, j; /*loop counting: i = x, j = y*/
667:     int mid_width = ((*img).width / 2);
668:     int mid_height = ((*img).height / 2);
669:  
670:     for(i = 0; i <  mid_width / 2; i++)
671:     {
672:        for(j = 0; j <  mid_height; j++)
673:        {
674:  	/*inorder they are:
675:  	  bottom left, bottom middle right, top left, top m right,
676:  	  bottom middle left, bottom right, top middle left, top right.*/
677:  
678:  	 setCPixel(i, j, (*img).data[j][i]);
679:  	 setCPixel(i + mid_width, j, (*img).data[j][i + mid_width]);
680:  	 setCPixel(i, j + mid_height, (*img).data[j + mid_height][i]);
681:  	 setCPixel(i + mid_width, j + mid_height,
682:  		   (*img).data[j + mid_height][i + mid_width]);
683:  
684:  	 setCPixel(mid_width - i - 1, j,
685:  		   (*img).data[j][mid_width - i - 1]);
686:  	 setCPixel((*img).width - i - 1, j,
687:  		   (*img).data[j][(*img).width - i - 1]);
688:  	 setCPixel(mid_width - i - 1, (*img).height - j - 1,
689:  		   (*img).data[(*img).height - j - 1][mid_width - i - 1]);
690:  	 setCPixel((*img).width - i - 1, (*img).height - j - 1,
691:  		   (*img).data[(*img).height - j - 1][(*img).width - i - 1]);
692:        }
693:      }
694:      glFlush();
695:  }
696:  
697:  void camera_correction(PGMImage* new_img, PGMImage* org_img)
698:  {
699:     int row, col, img_row, img_col; /*loop counting*/
700:  
701:     /*camera parameters*/
702:     float height = 30; /*height of camera in cm*/
703:     float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/
704:     float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/
705:     
706:     /*temporary varaibles*/
707:     float angular_height_corr;
708:     float angular_side_corr;
709:     int x_coord, y_coord;
710:  
711:     memset(new_img, 0, sizeof(PGMImage));
712:     (*new_img).height = (*org_img).height;
713:     (*new_img).width = (*org_img).width;
714:     (*new_img).maxVal = (*org_img).maxVal;
715:  
716:     for (row=(*org_img).height-1; row >=0; row--)
717:        for (col=0; col< (*org_img).width; col++)
718:        {
719:  	/*img_row -= (*org_img).height / 2;
720:  	  img_col = col - (*org_img).width / 2;*/
721:  
722:  	 angular_height_corr = 
723:     (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1));
724:  	 angular_side_corr =
725:     (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1));
726:  
727:  	 angular_height_corr /= 2;
728:  	 /*angular_side_corr /= 2;*/
729:           /*height *= 2;*/
730:  	 height = 150;
731:  
732:  	 x_coord = (int)
733:  	   (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr));
734:  	 y_coord = (int)
735:  	   (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr));
736:  
737:  	 /*x_coord += (*org_img).width / 2;*/
738:  	 y_coord += (*org_img).height / 2;
739:  
740:  	 /*printf("org: (%d, %d)  new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/
741:  
742:  	 pxlcpy(new_img, y_coord, x_coord, org_img, row, col);
743:        }
744:  }
745:  
746:  void new_corr(PGMImage* new_img, PGMImage* org_img)
747:  {
748:     /*i and j are the left half, k and l are the right half*/
749:     float i, k; /*loop counting*/
750:     int j, l, row; /*loop counting*/
751:     int old_i, old_k;
752:  
753:     float ins_s = 2; /*insert constant starting value*/
754:     float ins_k = ins_s; /*insert constant*/
755:  
756:     /*The halfway marks in the width.*/
757:     int mid_width_left = ((*new_img).width / 2) - 1;
758:     int mid_width_right = ((*new_img).width / 2);
759:     
760:     /*just to be thourough clear the memory and reset maxes*/
761:     memset(new_img, 0, sizeof(PGMImage));
762:     (*new_img).height = (*org_img).height;
763:     (*new_img).width = (*org_img).width;
764:     (*new_img).maxVal = (*org_img).maxVal;
765:  
766:     /*Loop through each row from top to bottom...*/
767:     for(row = ((*new_img).height - 1); row  >= 0; row--)
768:     {
769:        /*...reset moire interference removal counter...*/
770:        old_i = ((*new_img).width / 2) - 1;
771:        old_k = ((*new_img).width / 2);
772:  
773:        /*...so each half is ajusted to remove perspective effect...*/
774:        for(i = j = mid_width_left, k = l = mid_width_right
775:  	    ; i  >= 0, j  >= 0, k <  (*new_img).width, l <  (*new_img).width
776:  	    ; i -= ins_k, j--, k += ins_k, l++)
777:        {
778:  	 for(;old_i  >= (int)i; old_i--)  /*...in the left half...*/ 
779:  	    pxlcpy(new_img, row, old_i, org_img, row, j);
780:  	 for(;old_k < = (int)k; old_k++)  /*...in the right half.*/
781:  	    pxlcpy(new_img, row, old_k, org_img, row, l);
782:        }
783:        /*Move the new image x_coord pixel counter to next new image pixel*/
784:        ins_k -= ((ins_s - 1.0) / (*new_img).height);
785:     }
786:  }
787:  
788:  void color_to_gray(PGMImage* new_img, PGMImage* org_img)
789:  {
790:     int row, col; /*loop counting*/
791:     RGB_INT cur_pxl; /*current pixel*/
792:  
793:     (*new_img).height = (*org_img).height;
794:     (*new_img).width = (*org_img).width;
795:     (*new_img).maxVal = (*org_img).maxVal;
796:  
797:     /*Starting with the top row...*/
798:     for(row = (*new_img).height - 1; row  >= 0; row--)
799:        for(col = 0; col <  (*new_img).width - 1; col++)
800:        {
801:  	 cur_pxl = (*org_img).data[row][col]; /*more readable*/
802:  	
803:  	 /*convert each RGB to the average of the original*/
804:  	 (*new_img).data[row][col].red =  rgb_avg(cur_pxl);
805:  	 (*new_img).data[row][col].green =  rgb_avg(cur_pxl);
806:  	 (*new_img).data[row][col].blue =  rgb_avg(cur_pxl);
807:        }
808:  }
809:  
810:  void moravec(PGMImage* new_img, PGMImage* org_img)
811:  {
812:     int row, col; /*loop counting*/
813:     int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
814:     int running_sum;
815:     float K = .5; /*.125 according to org. formula, but .5 is brighter*/
816:     int max_val = 0, row_max, col_max; /* max porportion value in image*/
817:  
818:     memset(new_img, 0, sizeof(PGMImage));
819:     (*new_img).height = (*org_img).height;
820:     (*new_img).width = (*org_img).width;
821:     (*new_img).maxVal = (*org_img).maxVal;
822:  
823:     /*starting at the top row*/
824:     for(row = (*new_img).height - 1 - 1; row  > 0; row--)
825:        for(col = 1; col <  (*new_img).width - 1; col++) /*left col start*/
826:        {
827:  	 i = row;
828:  	 j = col;
829:  	 running_sum = 0;
830:  
831:  	 /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
832:  	 for(k = i - 1; k < = i + 1; k++) /*row*/
833:  	   for(l = j - 1; l < = j + 1; l++) /*column*/
834:  	     running_sum += abs(rgb_avg((*org_img).data[k][l]) -
835:  				rgb_avg((*org_img).data[i][j]));
836:  
837:  	 /*assign the new pixel value*/
838:  	 (*new_img).data[row][col].red = (int)(K * running_sum);
839:  	 (*new_img).data[row][col].green = (int)(K * running_sum);
840:  	 (*new_img).data[row][col].blue = (int)(K * running_sum);
841:        } 
842:  }
843:  
844:  void detect_corners(PGMImage* org_img)
845:  {
846:     struct chainCode **chain_codes;
847:  
848:     chain_codes = showChain(org_img);
849:  }
850:  
851:  /* =================================================================
852:   * Callback functions.
853:   *
854:   * color = displayed graphics in window
855:   * menu = menu event handling
856:   * keyboard = deyboard event handling
857:   * ----------------------------------------------------------------- */
858:  void color(void)
859:  {
860:    /*glClear (GL_COLOR_BUFFER_BIT);*/
861:     
862:     /*  printf("\nDrawing Original image...\n");*/
863:    showColor(img_cur);
864:     
865:    /*glFlush();*/
866:  }
867:  
868:  #define RESTART 0
869:  #define CAMERA_CORRECTION 1
870:  #define X2_C_CORR 2
871:  #define NEW_CORR 3
872:  #define COLOR_TO_GRAY 4
873:  #define MORAVEC 5
874:  #define CORNERS 6
875:  
876:  void menu(int selection)
877:  {
878:     if(selection == RESTART)   
879:     {
880:        memcpy(img1, img0, sizeof(PGMImage));
881:        img_cur = img0;
882:     }
883:     if(selection == CAMERA_CORRECTION)
884:     {
885:        printf("Starting camera correction\n");
886:        camera_correction(img1, img0);
887:        img_cur = img1;
888:      }
889:      if(selection == X2_C_CORR)
890:      {
891:         printf("Starting camera correction\n");
892:         camera_correction(img1, img0);
893:         camera_correction(img2, img1);
894:         img_cur = img2;
895:      }
896:      if(selection == NEW_CORR)
897:      {
898:         new_corr(img1, img0);
899:         img_cur = img1;
900:      }
901:      if(selection == COLOR_TO_GRAY)
902:      {
903:         color_to_gray(img1, img0);
904:         img_cur = img1;
905:      }
906:      if(selection == MORAVEC)
907:      {
908:         moravec(img1, img0);
909:         img_cur = img1;
910:      }
911:      if(selection == CORNERS)
912:      {
913:        /*new_corr(img1, img0);*/
914:         /*moravec(img2, img1);*/
915:         showColor(img0);
916:         detect_corners(img0);
917:         img_cur = img0;
918:         return;
919:      }
920:      /*glClear (GL_COLOR_BUFFER_BIT);*/
921:      showColor(img_cur);
922:      glutPostRedisplay();
923:  }
924:  
925:  void keyboard(unsigned char key, int x, int y)
926:  { 
927:     switch (key)
928:     {
929:        case 27: 
930:           exit(0);
931:           break;
932:     }
933:  }
934:  
935:  void mouse(int button, int state, int x, int y)
936:  {
937:    char temp[50];
938:    RGB_INT erase = {0, 0, 0};
939:  
940:    if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
941:    {
942:       sprintf(temp, "(x, y): (%d, %d)  red: %d green: %d blue: %d\n",
943:  	     x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red,
944:  	     (*img_cur).data[VSIZE - y][x].green,
945:  	     (*img_cur).data[VSIZE - y][x].blue);
946:       setCRect(0, 0, 200, 12, erase);
947:       glColor3f(1.0, 0.0, 0.0);
948:       drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp);
949:       glFlush();
950:    }
951:  }
952:    
953:  /* =================================================================
954:   * init - initializes graphics viewport
955:   *
956:   * You should not have to change this function for the first few
957:   * projects we have. It will become more important when we move to
958:   * 3D graphics.
959:   * ----------------------------------------------------------------- */
960:  void init (void)
961:  {
962:    
963:  /*
964:   * select clearing color - white
965:   */
966:     glClearColor (1.0, 1.0, 1.0, 0.0);
967:  
968:  /*
969:   * initialize viewport values
970:   */
971:     glMatrixMode(GL_PROJECTION);
972:     glLoadIdentity();
973:     glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
974:  
975:     /*add menus*/
976:     glutCreateMenu(menu);
977:     glutAddMenuEntry("Restart", RESTART);
978:     glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION);
979:     glutAddMenuEntry("2x C. Corr.", X2_C_CORR);
980:     glutAddMenuEntry("new corr", NEW_CORR);
981:     glutAddMenuEntry("color to gray", COLOR_TO_GRAY);
982:     glutAddMenuEntry("moravec", MORAVEC);
983:     glutAddMenuEntry("corners", CORNERS);
984:     glutAttachMenu(GLUT_RIGHT_BUTTON);
985:  }
986:   
987:  int main(int argc, char** argv)
988:  {
989:     char PGMfileName[MAX_FILE_LENGTH];
990:     
991:     int WindowID;
992:  
993:     int i;  /*looping variable*/
994:      
995:     /*parse the command line*/  
996:     if(argc == 1)
997:     {
998:        printf("To few parameters.\n");
999:        printf("Usage: research < file.pgm >\n");
1000:        exit(1);
1001:     }
1002:     else if(argc == 2)
1003:        strcpy(PGMfileName, argv[1]);
1004:     else
1005:     {
1006:        printf("To many parameters.\n");
1007:        printf("Usage: research < file.pgm >\n");
1008:        exit(1);
1009:     }
1010:  /*
1011:   * Read in image file. - note: sets our global values, too.
1012:   * ----------------------------------------------------------------- */
1013:               
1014:     img0 = (PGMImage*) malloc(sizeof(PGMImage));
1015:     getPGMfile(PGMfileName, img0);
1016:     HSIZE = (*img0).width;
1017:     VSIZE = (*img0).height;
1018:     MVAL = (*img0).maxVal;
1019:  
1020:     img_cur = img0; /*VERY IMPORTANT to set this*/
1021:              
1022:     /*allocate memory for second image*/
1023:     img1 = (PGMImage*) malloc(sizeof(PGMImage));
1024:     memcpy(img1, img0, sizeof(PGMImage));
1025:     /*(*img1).width = HSIZE;
1026:     (*img1).height = VSIZE;
1027:     (*img1).maxVal = 255;*/
1028:               
1029:     img2 = (PGMImage*) malloc(sizeof(PGMImage));
1030:     memcpy(img2, img0, sizeof(PGMImage));
1031:              
1032:  /*
1033:   * Initialize the glut package.
1034:   * ----------------------------------------------------------------- */
1035:     glutInit(&argc, argv);
1036:     glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
1037:  /*           
1038:   * Define a new window (its size, position and title).
1039:   * ----------------------------------------------------------------- */
1040:        glutInitWindowSize (HSIZE, VSIZE);  /*size*/
1041:        glutInitWindowPosition (10, 10);    /*position*/
1042:        WindowID = glutCreateWindow (PGMfileName); /*title*/
1043:        glutSetWindow(WindowID);
1044:        glutDisplayFunc(color);
1045:        
1046:  /*  
1047:   * Call our init function to define viewing parameters.
1048:   * ----------------------------------------------------------------- */
1049:     init ();
1050:     
1051:     glutMouseFunc(mouse);
1052:     glutKeyboardFunc(keyboard); 
1053:     glutMainLoop();
1054:  
1055:  /*  
1056:   * When we reach here, we've left the event loop and are ready to
1057:   * exit.
1058:   * ----------------------------------------------------------------- */
1059:     return 0;
1060:  }
1061:  
1062:  
1063:  
1064:  
1065:  
1066:  
1067:  
1068:  
1069:  
1070:  
1071:  
1072:  
1073: