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