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