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