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: if(rgb_avg((*img).data[y_check][x_check]) > img_pxl_avg(img))
271: {
272: setCPixel(x_check, y_check, chainColor);
273: glFlush();
274: *dir = next;
275: temp = (chain_t)malloc(sizeof(struct chainCode));
276: temp->next = NULL;
277: temp->code = *dir;
278: temp->location.x = x_check;
279: temp->location.y = y_check;
280: temp->prev = *theChain;
281: if(*theChain)
282: (*theChain)->next = temp; /*now this is a good thing to set.*/
283: *theChain = temp; /*advance one*/
284:
285: if(*beginning == NULL)
286: *beginning = *theChain;/*set this for the first node in the list once*/
287: return TRUE;
288: }
289: return FALSE;
290: }
291:
292: /*determines the chain code for a starting pixel*/
293: /*this chain code uses 8 connectivity*/
294: /*Note: There are many different coordinate systems at work in this function.*/
295: /*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
296: /* top left is (0, 0). If it looks strange, look harder!!!*/
297: /*Preconditions:
298: 1st parameter: pointer to the pgm image being used.
299: 2nd parameter: integer value containing the current x coordinate.
300: 3rd parameter: integer value containing the current y coordinate.
301: 4th parameter: integer value containing the current direction code.
302: 5th parameter: pointer to the linked list of the chain code.
303: 6th parameter: pointer to the linked list of the chain code.*/
304: /*This function assumes the (0, 0) point is in the lower left*/
305:
306: int chaincode(PGMImage *img, int x, int y, int dir,
307: struct chainCode** theChain, struct chainCode** beginning)
308: {
309: int i; /*loop counting*/
310: int initial, next, finished;
311:
312: /* if(dir % 2) /*if dir is odd*/
313: /* initial = (dir + 6) % 8;
314: else /*if dir is even*/
315: /* initial = (dir + 7) % 8;*/
316:
317: initial = (dir + 5) % 8; /*better initail choice?*/
318:
319: next = initial; /*set the next direction to search*/
320: /*printf("next: %d x: %d y: %d\n", next, x, y); */
321: for(i = 0; i < 8; i++)
322: {
323: if(next == EAST)
324: {
325: if(checkThings(&dir, EAST, x, y, x + 1, y, theChain, img, beginning))
326: finished = chaincode(img, x + 1, y, dir, theChain, beginning);
327: }
328: else if(next == NORTHEAST)
329: {
330:
331: if(checkThings(&dir, NORTHEAST, x, y, x + 1, y + 1, theChain, img,
332: beginning))
333: finished = chaincode(img, x + 1, y + 1, dir, theChain, beginning);
334: }
335: else if(next == NORTH)
336: {
337: if(checkThings(&dir, NORTH, x, y, x, y + 1, theChain, img,
338: beginning))
339: finished = chaincode(img, x, y + 1, dir, theChain, beginning);
340: }
341: else if(next == NORTHWEST)
342: {
343: if(checkThings(&dir, NORTHWEST, x, y, x - 1, y + 1, theChain, img,
344: beginning))
345: finished = chaincode(img, x - 1, y + 1, dir, theChain, beginning);
346: }
347: else if(next == WEST)
348: {
349: if(checkThings(&dir, WEST, x, y, x - 1, y, theChain, img, beginning))
350: finished = chaincode(img, x - 1, y, dir, theChain, beginning);
351: }
352: else if(next == SOUTHWEST)
353: {
354: if(checkThings(&dir, SOUTHWEST, x, y, x - 1, y - 1, theChain, img,
355: beginning))
356: finished = chaincode(img, x - 1, y - 1, dir, theChain, beginning);
357: }
358: else if(next == SOUTH)
359: {
360: if(checkThings(&dir, SOUTH, x, y, x, y - 1, theChain, img,beginning))
361: finished = chaincode(img, x, y - 1, dir, theChain, beginning);
362: }
363: else if(next == SOUTHEAST)
364: {
365: if(checkThings(&dir, SOUTHEAST, x, y, x + 1, y - 1, theChain, img,
366: beginning))
367: finished = chaincode(img, x + 1, y - 1, dir, theChain, beginning);
368: }
369:
370: /*if the next chaincode function in the recursion or the current state
371: is the final state of the the chain code; recursively returns DONE
372: back through all the levels to stop the chain code.*/
373: if(dir == NONE || finished == NONE)
374: return NONE;
375:
376: /*set next for next iteration*/
377: next = (next + 1) % 8;
378: }
379:
380: }
381:
382: /*returns true if the point is already in one of the chains, false otherwise*/
383: int alreadyFound(int initThreashFlag, int i, int j, PGMImage* img,
384: struct chainCode** found, int count)
385: {
386: int k;
387: struct chainCode* temp;
388: /*this if statement determines if a pixel is not the background*/
389: if(initThreashFlag < rgb_avg((*img).data[j][i])) /*collumn major*/
390: {
391: /*Now search to determine if the pixel has been found already*/
392: for(k = 0; k <= count; k++)
393: {
394: temp = (found[k]);
395: while(temp)
396: {/* if point has already been found*/
397: if((temp->location.x == i) && (temp->location.y == j))
398: {
399: j = 0; /*does this work?*/
400: return TRUE;
401: break;
402: }
403: temp = temp->next;
404: }
405: }
406: }
407: return FALSE;
408: }
409:
410: /*saves a chain code to file. Was usefull during debuging now is just
411: a cool thing to leave in*/
412: /*1st: pointer to beginning of a chaincode
413: 2nd: the index of the chain code for destiqushing the 'chain' files*/
414: void saveChainCode(chainCode* saveChain, int count)
415: {
416: struct chainCode* temp = saveChain;
417: char filename[12];
418: FILE* outfile;
419: sprintf(filename, "chain%d", count);
420: outfile = fopen(filename, "w"); /*output file for chaincode*/
421: printf("Writing chain code to file %s.\n", filename);
422:
423: while(temp)
424: {
425:
426: fprintf(outfile, "%d %d %d\n",temp->location.x,temp->location.y,
427: temp->code);
428: temp = temp->next;
429: }
430: fclose(outfile);
431: }
432:
433: chainCode** showChain(PGMImage *original)
434: {
435: int i, j; /*loop counting*/
436: int count = 0; /*array index holder*/
437: int initThreashFlag = img_pxl_avg(original), foundFlag = TRUE;
438: RGB_INT /*chainColor = {255, 0, 255},*/ tempColor = {255, 0, 0};
439: struct chainCode** beginning, *chain = NULL, *temp, *next_tmep, *temp_loop;
440: beginning = (chainCode**)
441: malloc(MAX_CHAINS * sizeof(chainCode*));
442:
443: /*Need a temporary threasholded image*/
444: /*PGMImage *threashed = (PGMImage*) malloc(sizeof(PGMImage));
445: */
446: glPointSize(4); /*make points more visible*/
447:
448: /*showThreashold(original, threashed);*/
449:
450: /*Use starting pixel as defualt. This is partially based on the fact that
451: most likely a corner will be background and not an object.*/
452: /*the image assumes that (0, 0) is in the bottom left, I assume that
453: (0, 0) is in the upper left. This is handled here.*/
454: /*initThreashFlag = (*threashed).data[(*threashed).height - 1][0];*/
455:
456: for(i = 0; i < 10; i++) beginning[i] = NULL;/*initailize pointer array.*/
457:
458: /*search image until a pixel is found with threasholded value of the
459: object. i & j will then contain the starting coordinate.*/
460: for(i = 0; i < (*original).width; i++) /*x direction*/
461: {
462: for(j = (*original).height - 1; j >= 0; j--) /*y direction*/
463: {
464: /*skip to the next iteration if pixel isn't "good" enough*/
465: if(rgb_avg((*original).data[j][i]) < initThreashFlag)
466: {
467: continue;
468: }
469: /*skip to the next iteration, which will be at the top of the next
470: collumn*/
471: else if(alreadyFound(initThreashFlag, i, j, original, beginning,
472: count))
473: {
474: j = 0; /*reseting to make this the last iteration without reseting
475: search to the top of next collumn*/
476: continue;
477: }
478: else
479: {
480: /*printf("chaincode: %d\n", count);*/
481: /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/
482: chain = NULL; /*reset this to seperate the chaincodes*/
483:
484: chainColor.blue = (128 + 10 * count) * (count % 2);
485: chainColor.green =(128 + 10 * count) * (count % 3);
486: chainColor.red =(128 + 10 * count);
487: /*find the chaincode for the current starting pixel*/
488: chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]);
489:
490: if(beginning[count] != NULL) /*avoid writing zero length chains*/
491: {
492: saveChainCode(beginning[count], count);
493: count++; /*advance the beginning counter*/
494: }
495:
496: /*force end of loops, leaving code when finished looping
497: to still execute*/
498: if(count >= MAX_CHAINS)
499: i = (*original).width;
500:
501: j = 0; /*reset search to start at top on next pass. This the
502: setting for stopping condition for the current j loop.*/
503: break; /*Quick fix?*/
504: }
505: }
506: }
507: printf("Done finding chain code(s). %d were found.\n", count);
508: return beginning;
509: }
510:
511: /**********************Support functions*******************************/
512: /***********************************************************************/
513:
514: /*Returns average (with RGB avg) pixel value for the image passed in.*/
515: int img_pxl_avg(PGMImage* img)
516: {
517: int i, j; /*loop counting*/
518: int sum = 0;
519:
520: for(i = 0; i < (*img).height; i++)
521: for(j = 0; j < (*img).height; j++)
522: sum += rgb_avg((*img).data[i][j]);
523:
524: return (sum / ((*img).height * (*img).height));
525: }
526:
527:
528: /**********************File I/O functions*******************************/
529: /***********************************************************************/
530:
531: /*Gets an ascii color pgm image file (type P3).*/
532: void getPGMfile (char filename[], PGMImage *img)
533: {
534: FILE *in_file;
535: char ch;
536: int row, col;
537:
538: in_file = fopen(filename, "r");
539: if (in_file == NULL)
540: {
541: fprintf(stderr, "Error: Unable to open file %s\n\n", filename);
542: exit(8);
543: }
544:
545: printf("\nReading image file: %s", filename);
546:
547: do /* skip header identifier */
548: ch = getc(in_file);
549: while (ch != '\n');
550:
551: do /* skip comments lines */
552: {
553: while (ch != '\n') ch = getc(in_file); /* flush to end of line */
554: ch = getc(in_file);
555: } while (ch == '#');
556:
557: fseek(in_file, -1, SEEK_CUR); /* backup one character */
558:
559: fscanf(in_file,"%d", &((*img).width));
560: fscanf(in_file,"%d", &((*img).height));
561: fscanf(in_file,"%d", &((*img).maxVal));
562:
563: printf("\n width = %d",(*img).width);
564: printf("\n height = %d",(*img).height);
565: printf("\n maxVal = %d",(*img).maxVal);
566: printf("\n");
567:
568: if (((*img).width > MAX) || ((*img).height > MAX))
569: {
570: printf("\n\n***ERROR - image too big for current image structure***\n\n");
571: exit(0);
572: }
573:
574: for (row=(*img).height-1; row>=0; row--)
575: for (col=0; col<(*img).width; col++)
576: {
577: fscanf(in_file,"%d", &((*img).data[row][col].red) );
578: fscanf(in_file,"%d", &((*img).data[row][col].green));
579: fscanf(in_file,"%d", &((*img).data[row][col].blue));
580: }
581: fclose(in_file);
582: printf("\nDone reading file.\n");
583: }
584:
585:
586: void save(PGMImage *img)
587: {
588: int i, j, nr, nc, k;
589: int red, green, blue;
590: FILE *iop;
591:
592: nr = img->height;
593: nc = img->width;
594:
595: iop = fopen("image1.pgm", "w");
596: fprintf(iop, "P3\n");
597: fprintf(iop, "%d %d\n", nc, nr);
598: fprintf(iop, "255\n");
599:
600: k = 1;
601: for(i = nr - 1; i >= 0; i--)
602: {
603: for(j = 0; j < nc; j++)
604: {
605: red = img->data[i][j].red;
606: green = img->data[i][j].green;
607: blue = img->data[i][j].blue;
608: if(red < 0)
609: {
610: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
611: printf(" Setting red to zero\n");
612: red = 0;
613: }
614: if(green < 0)
615: {
616: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
617: printf(" Setting green to zero\n");
618: green = 0;
619: }
620: if(blue < 0)
621: {
622: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
623: printf(" Setting green to zero\n");
624: blue = 0;
625: }
626: if(red > 255)
627: {
628: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
629: printf(" Setting red to 255\n");
630: red = 255;
631: }
632: if(green > 255)
633: {
634: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
635: printf(" Setting green to 255\n");
636: green = 255;
637: }
638: if(blue > 255)
639: {
640: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
641: printf(" Setting blue to 255\n");
642: blue = 255;
643: }
644:
645: if(k % 10)
646: {
647: fprintf(iop, "%d ", red);
648: fprintf(iop, "%d ", green);
649: fprintf(iop, "%d ", blue);
650: }
651: else /*for newline*/
652: {
653: fprintf(iop, "%d\n", red);
654: fprintf(iop, "%d\n", green);
655: fprintf(iop, "%d\n", blue);
656: }
657: k++;
658: }
659: }
660: fprintf(iop, "\n");
661: fclose(iop);
662: }
663:
664:
665:
666:
667: /****Calculation & drawing functions of the image translations**********
668: ***********************************************************************/
669:
670:
671: void showColor (PGMImage *img)
672: {
673: int row, col; /*y, x*/
674: /*for (row=(*img).height-1; row>=0; row--)
675: for (col=0; col<(*img).width; col++)
676: {
677:
678: setCPixel(col, row, (*img).data[row][col]);
679: }*/
680:
681: int i, j; /*loop counting: i = x, j = y*/
682: int mid_width = ((*img).width / 2);
683: int mid_height = ((*img).height / 2);
684:
685: for(i = 0; i < mid_width / 2; i++)
686: {
687: for(j = 0; j < mid_height; j++)
688: {
689: /*inorder they are:
690: bottom left, bottom middle right, top left, top m right,
691: bottom middle left, bottom right, top middle left, top right.*/
692:
693: setCPixel(i, j, (*img).data[j][i]);
694: setCPixel(i + mid_width, j, (*img).data[j][i + mid_width]);
695: setCPixel(i, j + mid_height, (*img).data[j + mid_height][i]);
696: setCPixel(i + mid_width, j + mid_height,
697: (*img).data[j + mid_height][i + mid_width]);
698:
699: setCPixel(mid_width - i - 1, j,
700: (*img).data[j][mid_width - i - 1]);
701: setCPixel((*img).width - i - 1, j,
702: (*img).data[j][(*img).width - i - 1]);
703: setCPixel(mid_width - i - 1, (*img).height - j - 1,
704: (*img).data[(*img).height - j - 1][mid_width - i - 1]);
705: setCPixel((*img).width - i - 1, (*img).height - j - 1,
706: (*img).data[(*img).height - j - 1][(*img).width - i - 1]);
707: }
708: }
709: glFlush();
710: }
711:
712: void camera_correction(PGMImage* new_img, PGMImage* org_img)
713: {
714: int row, col, img_row, img_col; /*loop counting*/
715:
716: /*camera parameters*/
717: float height = 30; /*height of camera in cm*/
718: float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/
719: float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/
720:
721: /*temporary varaibles*/
722: float angular_height_corr;
723: float angular_side_corr;
724: int x_coord, y_coord;
725:
726: memset(new_img, 0, sizeof(PGMImage));
727: (*new_img).height = (*org_img).height;
728: (*new_img).width = (*org_img).width;
729: (*new_img).maxVal = (*org_img).maxVal;
730:
731: for (row=(*org_img).height-1; row>=0; row--)
732: for (col=0; col<(*org_img).width; col++)
733: {
734: /*img_row -= (*org_img).height / 2;
735: img_col = col - (*org_img).width / 2;*/
736:
737: angular_height_corr =
738: (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1));
739: angular_side_corr =
740: (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1));
741:
742: angular_height_corr /= 2;
743: /*angular_side_corr /= 2;*/
744: /*height *= 2;*/
745: height = 150;
746:
747: x_coord = (int)
748: (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr));
749: y_coord = (int)
750: (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr));
751:
752: /*x_coord += (*org_img).width / 2;*/
753: y_coord += (*org_img).height / 2;
754:
755: /*printf("org: (%d, %d) new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/
756:
757: pxlcpy(new_img, y_coord, x_coord, org_img, row, col);
758: }
759: }
760:
761: void new_corr(PGMImage* new_img, PGMImage* org_img)
762: {
763: /*i and j are the left half, k and l are the right half*/
764: float i, k; /*loop counting*/
765: int j, l, row; /*loop counting*/
766: int old_i, old_k;
767:
768: float ins_s = 2; /*insert constant starting value*/
769: float ins_k = ins_s; /*insert constant*/
770:
771: /*The halfway marks in the width.*/
772: int mid_width_left = ((*new_img).width / 2) - 1;
773: int mid_width_right = ((*new_img).width / 2);
774:
775: /*just to be thourough clear the memory and reset maxes*/
776: memset(new_img, 0, sizeof(PGMImage));
777: (*new_img).height = (*org_img).height;
778: (*new_img).width = (*org_img).width;
779: (*new_img).maxVal = (*org_img).maxVal;
780:
781: /*Loop through each row from top to bottom...*/
782: for(row = ((*new_img).height - 1); row >= 0; row--)
783: {
784: /*...reset moire interference removal counter...*/
785: old_i = ((*new_img).width / 2) - 1;
786: old_k = ((*new_img).width / 2);
787:
788: /*...so each half is ajusted to remove perspective effect...*/
789: for(i = j = mid_width_left, k = l = mid_width_right
790: ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width
791: ; i -= ins_k, j--, k += ins_k, l++)
792: {
793: for(;old_i >= (int)i; old_i--) /*...in the left half...*/
794: pxlcpy(new_img, row, old_i, org_img, row, j);
795: for(;old_k <= (int)k; old_k++) /*...in the right half.*/
796: pxlcpy(new_img, row, old_k, org_img, row, l);
797: }
798: /*Move the new image x_coord pixel counter to next new image pixel*/
799: ins_k -= ((ins_s - 1.0) / (*new_img).height);
800: }
801: }
802:
803: void color_to_gray(PGMImage* new_img, PGMImage* org_img)
804: {
805: int row, col; /*loop counting*/
806: RGB_INT cur_pxl; /*current pixel*/
807:
808: (*new_img).height = (*org_img).height;
809: (*new_img).width = (*org_img).width;
810: (*new_img).maxVal = (*org_img).maxVal;
811:
812: /*Starting with the top row...*/
813: for(row = (*new_img).height - 1; row >= 0; row--)
814: for(col = 0; col < (*new_img).width - 1; col++)
815: {
816: cur_pxl = (*org_img).data[row][col]; /*more readable*/
817:
818: /*convert each RGB to the average of the original*/
819: (*new_img).data[row][col].red = rgb_avg(cur_pxl);
820: (*new_img).data[row][col].green = rgb_avg(cur_pxl);
821: (*new_img).data[row][col].blue = rgb_avg(cur_pxl);
822: }
823: }
824:
825: void moravec(PGMImage* new_img, PGMImage* org_img)
826: {
827: int row, col; /*loop counting*/
828: int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
829: int running_sum;
830: float K = .5; /*.125 according to org. formula, but .5 is brighter*/
831: int max_val = 0, row_max, col_max; /* max porportion value in image*/
832:
833: memset(new_img, 0, sizeof(PGMImage));
834: (*new_img).height = (*org_img).height;
835: (*new_img).width = (*org_img).width;
836: (*new_img).maxVal = (*org_img).maxVal;
837:
838: /*starting at the top row*/
839: for(row = (*new_img).height - 1 - 1; row > 0; row--)
840: for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/
841: {
842: i = row;
843: j = col;
844: running_sum = 0;
845:
846: /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
847: for(k = i - 1; k <= i + 1; k++) /*row*/
848: for(l = j - 1; l <= j + 1; l++) /*column*/
849: running_sum += abs(rgb_avg((*org_img).data[k][l]) -
850: rgb_avg((*org_img).data[i][j]));
851:
852: /*assign the new pixel value*/
853: (*new_img).data[row][col].red = (int)(K * running_sum);
854: (*new_img).data[row][col].green = (int)(K * running_sum);
855: (*new_img).data[row][col].blue = (int)(K * running_sum);
856: }
857: }
858:
859: void detect_corners(PGMImage* org_img)
860: {
861: struct chainCode **chain_codes;
862:
863: chain_codes = showChain(org_img);
864: }
865:
866: /* =================================================================
867: * Callback functions.
868: *
869: * color = displayed graphics in window
870: * menu = menu event handling
871: * keyboard = deyboard event handling
872: * ----------------------------------------------------------------- */
873: void color(void)
874: {
875: /*glClear (GL_COLOR_BUFFER_BIT);*/
876:
877: /* printf("\nDrawing Original image...\n");*/
878: showColor(img_cur);
879:
880: /*glFlush();*/
881: }
882:
883: #define RESTART 0
884: #define CAMERA_CORRECTION 1
885: #define X2_C_CORR 2
886: #define NEW_CORR 3
887: #define COLOR_TO_GRAY 4
888: #define MORAVEC 5
889: #define CORNERS 6
890:
891: void menu(int selection)
892: {
893: if(selection == RESTART)
894: {
895: memcpy(img1, img0, sizeof(PGMImage));
896: img_cur = img0;
897: }
898: if(selection == CAMERA_CORRECTION)
899: {
900: printf("Starting camera correction\n");
901: camera_correction(img1, img0);
902: img_cur = img1;
903: }
904: if(selection == X2_C_CORR)
905: {
906: printf("Starting camera correction\n");
907: camera_correction(img1, img0);
908: camera_correction(img2, img1);
909: img_cur = img2;
910: }
911: if(selection == NEW_CORR)
912: {
913: new_corr(img1, img0);
914: img_cur = img1;
915: }
916: if(selection == COLOR_TO_GRAY)
917: {
918: color_to_gray(img1, img0);
919: img_cur = img1;
920: }
921: if(selection == MORAVEC)
922: {
923: moravec(img1, img0);
924: img_cur = img1;
925: }
926: if(selection == CORNERS)
927: {
928: printf("img avg: %d\n", img_pxl_avg(img0));
929: /*new_corr(img1, img0);*/
930: /*moravec(img2, img1);*/
931: showColor(img0);
932: detect_corners(img0);
933: img_cur = img0;
934: return;
935: }
936: /*glClear (GL_COLOR_BUFFER_BIT);*/
937: showColor(img_cur);
938: glutPostRedisplay();
939: }
940:
941: void keyboard(unsigned char key, int x, int y)
942: {
943: switch (key)
944: {
945: case 27:
946: exit(0);
947: break;
948: }
949: }
950:
951: void mouse(int button, int state, int x, int y)
952: {
953: char temp[50];
954: RGB_INT erase = {0, 0, 0};
955:
956: if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
957: {
958: sprintf(temp, "(x, y): (%d, %d) red: %d green: %d blue: %d\n",
959: x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red,
960: (*img_cur).data[VSIZE - y][x].green,
961: (*img_cur).data[VSIZE - y][x].blue);
962: setCRect(0, 0, 200, 12, erase);
963: glColor3f(1.0, 0.0, 0.0);
964: drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp);
965: glFlush();
966: }
967: }
968:
969: /* =================================================================
970: * init - initializes graphics viewport
971: *
972: * You should not have to change this function for the first few
973: * projects we have. It will become more important when we move to
974: * 3D graphics.
975: * ----------------------------------------------------------------- */
976: void init (void)
977: {
978:
979: /*
980: * select clearing color - white
981: */
982: glClearColor (1.0, 1.0, 1.0, 0.0);
983:
984: /*
985: * initialize viewport values
986: */
987: glMatrixMode(GL_PROJECTION);
988: glLoadIdentity();
989: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
990:
991: /*add menus*/
992: glutCreateMenu(menu);
993: glutAddMenuEntry("Restart", RESTART);
994: glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION);
995: glutAddMenuEntry("2x C. Corr.", X2_C_CORR);
996: glutAddMenuEntry("new corr", NEW_CORR);
997: glutAddMenuEntry("color to gray", COLOR_TO_GRAY);
998: glutAddMenuEntry("moravec", MORAVEC);
999: glutAddMenuEntry("corners", CORNERS);
1000: glutAttachMenu(GLUT_RIGHT_BUTTON);
1001: }
1002:
1003: int main(int argc, char** argv)
1004: {
1005: char PGMfileName[MAX_FILE_LENGTH];
1006:
1007: int WindowID;
1008:
1009: int i; /*looping variable*/
1010:
1011: /*parse the command line*/
1012: if(argc == 1)
1013: {
1014: printf("To few parameters.\n");
1015: printf("Usage: research <file.pgm>\n");
1016: exit(1);
1017: }
1018: else if(argc == 2)
1019: strcpy(PGMfileName, argv[1]);
1020: else
1021: {
1022: printf("To many parameters.\n");
1023: printf("Usage: research <file.pgm>\n");
1024: exit(1);
1025: }
1026: /*
1027: * Read in image file. - note: sets our global values, too.
1028: * ----------------------------------------------------------------- */
1029:
1030: img0 = (PGMImage*) malloc(sizeof(PGMImage));
1031: getPGMfile(PGMfileName, img0);
1032: HSIZE = (*img0).width;
1033: VSIZE = (*img0).height;
1034: MVAL = (*img0).maxVal;
1035:
1036: img_cur = img0; /*VERY IMPORTANT to set this*/
1037:
1038: /*allocate memory for second image*/
1039: img1 = (PGMImage*) malloc(sizeof(PGMImage));
1040: memcpy(img1, img0, sizeof(PGMImage));
1041: /*(*img1).width = HSIZE;
1042: (*img1).height = VSIZE;
1043: (*img1).maxVal = 255;*/
1044:
1045: img2 = (PGMImage*) malloc(sizeof(PGMImage));
1046: memcpy(img2, img0, sizeof(PGMImage));
1047:
1048: /*
1049: * Initialize the glut package.
1050: * ----------------------------------------------------------------- */
1051: glutInit(&argc, argv);
1052: glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
1053: /*
1054: * Define a new window (its size, position and title).
1055: * ----------------------------------------------------------------- */
1056: glutInitWindowSize (HSIZE, VSIZE); /*size*/
1057: glutInitWindowPosition (10, 10); /*position*/
1058: WindowID = glutCreateWindow (PGMfileName); /*title*/
1059: glutSetWindow(WindowID);
1060: glutDisplayFunc(color);
1061:
1062: /*
1063: * Call our init function to define viewing parameters.
1064: * ----------------------------------------------------------------- */
1065: init ();
1066:
1067: glutMouseFunc(mouse);
1068: glutKeyboardFunc(keyboard);
1069: glutMainLoop();
1070:
1071: /*
1072: * When we reach here, we've left the event loop and are ready to
1073: * exit.
1074: * ----------------------------------------------------------------- */
1075: return 0;
1076: }
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089: