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 white = {255, 255, 255};
77: const RGB_INT yellow = {255, 255, 0};
78: const RGB_INT purple = {255, 0, 255};
79: const RGB_INT cyan = {0, 255, 255};
80: const RGB_INT red = {255, 0, 0};
81: const RGB_INT green = {0, 255, 0};
82: const RGB_INT blue = {0, 0, 255};
83: const RGB_INT black = {0, 0, 0};
84:
85: int cur_threash_val; /*for speed optimization of chain code recursion*/
86: int cur_chain_count, back_ground;
87:
88: /**************Drawing funcitions************************************/
89: /********************************************************************/
90:
91: void setCPixel(int ix, int iy, RGB_INT color)
92: /*Same as setIPixel except that the last parameter is an RGB color*/
93: {
94: float x = (ix*2.0)/HSIZE - 1.0;
95: float y = (iy*2.0)/VSIZE - 1.0;
96:
97: float red = (float)color.red/(float)MVAL;
98: float green = (float)color.green/(float)MVAL;
99: float blue = (float)color.blue/(float)MVAL;
100:
101: glColor3f(red, green, blue);
102:
103: glBegin(GL_POINTS);
104: glVertex2f (x, y);
105: glEnd();
106: }
107:
108: void setCLines(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
109: /*Similar as setIPixel except that this one draws a line between the first set
110: of points given and the second set in the RGB color specified*/
111: {
112: float x1 = (ix1*2.0)/HSIZE - 1.0;
113: float y1 = (iy1*2.0)/VSIZE - 1.0;
114: float x2 = (ix2*2.0)/HSIZE - 1.0;
115: float y2 = (iy2*2.0)/VSIZE -~ 1.0;
116:
117: float red = (float)color.red/(float)MVAL;
118: float green = (float)color.green/(float)MVAL;
119: float blue = (float)color.blue/(float)MVAL;
120:
121: glColor3f(red, green, blue);
122:
123: glBegin(GL_LINES);
124: glVertex2f (x1, y1);
125: glVertex2f (x2, y2);
126: glEnd();
127: }
128:
129: void setCRect(int ix1, int iy1, int ix2, int iy2, RGB_INT color)
130: /*Similar as setIPixel except that this one draws a line between the first set
131: of points given and the second set in the RGB color specified*/
132: {
133: float x1 = (ix1*2.0)/HSIZE - 1.0;
134: float y1 = (iy1*2.0)/VSIZE - 1.0;
135: float x2 = (ix2*2.0)/HSIZE - 1.0;
136: float y2 = (iy2*2.0)/VSIZE - 1.0;
137:
138: float red = (float)color.red/(float)MVAL;
139: float green = (float)color.green/(float)MVAL;
140: float blue = (float)color.blue/(float)MVAL;
141:
142: glColor3f(red, green, blue);
143:
144: glBegin(GL_POLYGON);
145: glVertex2f (x1, y1);
146: glVertex2f (x1, y2);
147: glVertex2f (x2, y2);
148: glVertex2f (x2, y1);
149: glEnd();
150: }
151:
152: void pxlcpy(PGMImage *dest, int dest_row, int dest_col,
153: PGMImage *src, int src_row, int src_col)
154: {
155: /*make sure values are within bounds*/
156: if(dest_col > 0 && dest_col < (*dest).width
157: && dest_row > 0 && dest_row < (*dest).height
158: && src_col > 0 && src_col < (*src).width
159: && src_row > 0 && src_row < (*src).height)
160: {
161: (*dest).data[dest_row][dest_col].red =
162: (*src).data[src_row][src_col].red;
163:
164: (*dest).data[dest_row][dest_col].green =
165: (*src).data[src_row][src_col].green;
166:
167: (*dest).data[dest_row][dest_col].blue =
168: (*src).data[src_row][src_col].blue;
169: }
170: }
171:
172: int rgb_avg(RGB_INT cur_pxl)
173: {
174: /*convert each RGB to the average of the original*/
175: return ((cur_pxl.red + cur_pxl.green + cur_pxl.blue) / 3);
176: }
177:
178: /*1st: pixel one of type RGB_INT
179: 2nd: pixel one of type RGB_INT
180: 3rd: differnce allowed to be considered "equal" or close enough*/
181: int pxlcmp (RGB_INT pxl1, RGB_INT pxl2, int range)
182: {
183: return ((abs((rgb_avg(pxl1) - rgb_avg(pxl2)))) < range);
184: }
185:
186: /* =================================================================
187: * drawString - outputs a string of characters to the graphics port
188: *
189: * x, y: defines the starting location to draw the text
190: * note: this point is the lower left anchor of
191: * the first character - a character's decending
192: * portion would be drawn below this point.
193: * theFont: points to the glut font to be used
194: * theString: holds the string to be output -- up to 255 ch
195: * ----------------------------------------------------------------- */
196: void drawString(int ix, int iy, void *theFont, char theString[256])
197: {
198: float x = (ix*2.0)/HSIZE - 1.0;
199: float y = (iy*2.0)/VSIZE - 1.0;
200: int i;
201: glRasterPos2f(x, y);
202: for (i = 0; theString[i] != '\0'; i++) /* draw the chars one at a time */
203: glutBitmapCharacter(theFont, theString[i]);
204: }
205:
206: /******CHAIN CODE************************************************
207: ****************************************************************/
208:
209: int createNode(chainCode** first, chainCode** last, int new_x, int new_y,
210: int new_dir)
211: {
212: chainCode* temp;
213:
214: if(!(temp = (chain_t)malloc(sizeof(struct chainCode))))
215: {
216: printf("error creating node\n");
217: return FALSE;
218: }
219:
220: temp->next = NULL;
221: temp->code = new_dir;
222: temp->location.x = new_x;
223: temp->location.y = new_y;
224: temp->prev = *last;
225: if(*last)
226: (*last)->next = temp; /*now this is a good thing to set.*/
227: *last = temp; /*advance one*/
228:
229: if(*first == NULL)
230: *first = *last;/*set this for the first node in the list once*/
231:
232: return TRUE;
233: }
234:
235: /*returns TRUE if the chain code loops around itself, otherwise false*/
236: int checkCode(chainCode* first, int x_current, int y_current,
237: int x_check, int y_check, int dir)
238: {
239: struct chainCode* currentNode = first;
240:
241: while(currentNode && currentNode->next)
242: {
243: /*check two consedutive points*/
244: if((currentNode->location.x == x_current) &&
245: (currentNode->location.y == y_current) &&
246: (currentNode->code == dir) &&
247: (currentNode->next->location.x == x_check) &&
248: (currentNode->next->location.y == y_check) &&
249: (currentNode->next->next)) /*don't count the new node already*/
250: {
251: return TRUE; /*The chain code end looped around*/
252: }
253: else
254: currentNode = currentNode->next;
255: }
256: return FALSE;
257: }
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, blue);*/
359:
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: cur_threash_val = initThreashFlag; /*set global variables*/
448: back_ground = background(initThreashFlag, original);
449:
450: /*search image until a pixel is found with threasholded value of the
451: object. i & j will then contain the starting coordinate.*/
452: for(i = 0; i < (*original).width; i++) /*x direction*/
453: {
454: for(j = (*original).height - 1; j >= 0; j--) /*y direction*/
455: {
456: /*skip to the next iteration if pixel isn't "good" enough*/
457: if(!checkThings(i, j, original))
458: continue;
459:
460: /*skip to the next iteration, which will be at the top of the next
461: collumn. This is true when the pixel has already been found in
462: one of the chain codes.*/
463: else if(alreadyFound(initThreashFlag, i, j, beginning))
464: break;
465:
466: else
467: {
468: /*printf("chaincode: %d\n", count);*/
469: /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/
470: chain = NULL; /*reset this to seperate the chaincodes*/
471:
472: /*find the chaincode for the current starting pixel*/
473: chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]);
474: if(beginning[count] != NULL) /*avoid writing zero length chains*/
475: {
476: saveChainCode(beginning[count], count);
477: count++; /*advance the beginning counter*/
478: cur_chain_count = count;
479: }
480:
481: /*force end of loops, leaving code when finished looping
482: to still execute*/
483: if(count >= MAX_NUMBER_OF_CHAINS)
484: i = (*original).width;
485:
486: /*j = 0;*/ /*reset search to start at top on next pass. This the
487: setting for stopping condition for the current j loop.*/
488: break; /*Quick fix?*/
489: }
490: }
491: }
492: printf("Done finding chain code(s). %d were found.\n", count);
493: return beginning;
494: }
495:
496: /*****BOUNDRY BOX**********************************************************
497: **********************************************************************/
498:
499: /*takes two coordinates as x and y pairs and returns the distence betweem them
500: as a decimal*/
501: float findDist(int x1, int y1, int x2, int y2)
502: {
503: return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
504: }
505:
506: /*1st param: The array of coords that the first point of the major axis is
507: returned in.
508: 2nd: The array of coords that the second point of the major axis is
509: returned in.
510: 3rd: The array of chain codes that are searched through to find the major
511: axes.*/
512: /* Note: the ending condition is when a NULL chainCodes value is reached.
513: Thusly, it works like a string requiring it to have the last legal value
514: followed by a null value.*/
515: void findFirstTwoCorners(coord corner1[], coord corner2[],
516: chainCode** chainCodes)
517: {
518: int i; /*loop counting*/
519: chainCode *temp, *search;
520: double max_dist, test_dist;
521:
522: printf("\nFinding first 2 corners.\n");
523:
524: /*as long as there are codes to check, keep checking. Note: the ending
525: condition is when a NULL chainCodes value is reached. Thusly, it works
526: like a string requiring it to have the last legal value followed by a
527: null value.*/
528: for(i = 0; (temp = chainCodes[i]) && (i < MAX_CHAINS); i++)
529: {
530: max_dist = 0.0; /*reset this for each iteration*/
531:
532: /*printf("checking list: %d\n", i);*/
533:
534: while(temp) /*while there are still nodes to check in the chain*/
535: {
536: search = temp; /*set the faster moving search pointer to temp,
537: this increases the effiecency a lot compared to
538: setting it equal to the first node..*/
539: while(search)
540: {
541: /*setCPixel(temp->location.x, temp->location.y, green);*/
542:
543: /*determine if found a new maximum distance between two locations*/
544: if((test_dist = findDist(search->location.x, search->location.y,
545: temp->location.x, temp->location.y)) > max_dist)
546: {
547: max_dist = test_dist;
548: corner1[i].x = temp->location.x;
549: corner1[i].y = temp->location.y;
550: corner2[i].x = search->location.x;
551: corner2[i].y = search->location.y;
552: }
553: search = search->next;
554: }
555: temp = temp->next;
556: }
557: /*printf("point1: %d %d\n", max1[i].x, max1[i].y);
558: printf("point2: %d %d\n", max2[i].x, max2[i].y);*/
559: }
560: }
561:
562: /*1st param: Array of coords for the first corner of each chain code.
563: 2nd param: Array of coords for the second corner of each chain code.
564: The first two parameters should equal the first two parameters "returned"
565: from the findFirstTwoCorners() function.
566: 3rd: Array of coords "returned" with the third corners.
567: 4th: Array of coords "returned" with the fourth corners.
568: 5th: Pointer pointing to the array of chaincode pointers, obtained from
569: showChain().*/
570: void findSecondTwoCorners(coord corner1[], coord corner2[], coord corner3[],
571: coord corner4[], chainCode** chain_code_array)
572: {
573: int i; /*loop counting*/
574: chainCode* temp;
575: float temp_dist1, temp_dist2; /*distance between point and each corner*/
576: coord canidate_coord1, temp_coord;
577: float canidate_dist1, max_dist;
578: int corner_count;
579:
580: printf("\nFinding last 2 corners.\n");
581:
582: /*for each chain code find the corners*/
583: for(i = 0; chain_code_array[i] && i < MAX_CHAINS; i++)
584: {
585: temp = chain_code_array[i];
586:
587: /*reset these for the next chain code*/
588: max_dist = 0.0;
589: corner_count = 1;
590:
591: while(temp) /*while there are nodes in the chain code to check*/
592: {
593: /*setCPixel(temp->location.x, temp->location.y, color1);*/
594:
595: /*determine the first canidate coord for corner 3/4*/
596: if(((temp->location.x == corner1[i].x)
597: && (temp->location.y == corner1[i].y))
598: || ((temp->location.x == corner2[i].x)
599: && (temp->location.y == corner2[i].y)))
600: {
601: /*if this corner found is the first of the two allready known
602: corners, then set the first canidate coord data and reset data
603: to find the next canidate corner point*/
604: if(corner_count == 1)
605: {
606: canidate_coord1.x = temp_coord.x;
607: canidate_coord1.y = temp_coord.y;
608: canidate_dist1 = max_dist;
609:
610: corner_count = 2; /*set for next corner*/
611: max_dist = 0.0;
612: }
613: else if(corner_count == 2)
614: {
615: /*the second canidate is always a corner*/
616: corner4[i].x = temp_coord.x;
617: corner4[i].y = temp_coord.y;
618:
619: max_dist = 0.0; /*set for next corner canidate*/
620: }
621: }
622:
623: /*calculate the distance between the current point being checked and
624: each corner point*/
625: temp_dist1 = findDist(corner1[i].x, corner1[i].y, temp->location.x,
626: temp->location.y);
627: temp_dist2 = findDist(corner2[i].x, corner2[i].y, temp->location.x,
628: temp->location.y);
629:
630: /*if the current point is the furthest away sofar, store this point
631: untill it is overridden or becomes a canidate point*/
632: if((temp_dist1 + temp_dist2) > max_dist)
633: {
634: temp_coord.x = temp->location.x;
635: temp_coord.y = temp->location.y;
636:
637: max_dist = (temp_dist1 + temp_dist2);
638: }
639:
640: temp = temp->next; /*advance*/
641: }
642:
643: /*from the three canidate coords find the two real corners.*/
644: /*the second canidate will always be a corner, must test 1 vs 3, where
645: three is in the variables temp_coord and max_dist.*/
646: if(canidate_dist1 > max_dist) /*first canidate*/
647: {
648: corner3[i].x = canidate_coord1.x;
649: corner3[i].y = canidate_coord1.y;
650: }
651: else /*third canidate*/
652: {
653: corner3[i].x = temp_coord.x;
654: corner3[i].y = temp_coord.y;
655: }
656: /*printf("corner3: (%d, %d) corner4: (%d, %d)\n", corner3[i].x,
657: corner3[i].y, corner4[i].x, corner4[i].y);*/
658: }
659: }
660:
661: /*takes a pointer to an image, and a pointer pointing to an array of
662: chain codes pointers, here each chainCode pointer needs to be accessed
663: by calculating the memory address.*/
664: void showBound(PGMImage *original, chainCode** chainCodes)
665: {
666: int i;
667: /*hold the points farthest away from each other for each object*/
668: coord corner1[MAX_CHAINS], corner2[MAX_CHAINS];
669: coord corner3[MAX_CHAINS], corner4[MAX_CHAINS];
670:
671: /*find the first two corners. they will be across a diagnal.*/
672: findFirstTwoCorners(corner1, corner2, chainCodes);
673: /*find the second two corners. they will be across a diagnal too.*/
674: findSecondTwoCorners(corner1, corner2, corner3, corner4, chainCodes);
675:
676: for(i = 0; chainCodes[i] && i < MAX_CHAINS; i++) /*for each chaincode*/
677: {
678: /*draw the boundry box*/
679: setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow);
680: setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow);
681: setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow);
682: setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow);
683: setCPixel(corner1[i].x, corner1[i].y, purple);
684: setCPixel(corner2[i].x, corner2[i].y, purple);
685: setCPixel(corner3[i].x, corner3[i].y, purple);
686: setCPixel(corner4[i].x, corner4[i].y, purple);
687: }
688: }
689:
690:
691: /**********************Support functions*******************************/
692: /***********************************************************************/
693:
694: /*Returns average (with RGB avg) pixel value for the image passed in.*/
695: int img_pxl_avg(PGMImage* img)
696: {
697: int i, j; /*loop counting*/
698: int sum = 0;
699:
700: for(i = 0; i < (*img).height; i++)/*collumn*/
701: for(j = 0; j < (*img).width; j++)/*row*/
702: sum += rgb_avg((*img).data[i][j]);
703:
704: return (sum / ((*img).height * (*img).height));
705: }
706:
707: /*return >0 if number of pixels is greater than img. pxl. avg., return <0 if
708: number of pixesl is less than img. pxl. avg. and return zero of equal*/
709: int background(int treash_value, PGMImage* img)
710: {
711: int i, j; /*loop counting*/
712: int pxl_less = 0, pxl_more = 0;
713:
714: for(i = 0; i < (*img).height; i++)/*collumn*/
715: for(j = 0; j < (*img).width; j++)/*row*/
716: {
717: if(rgb_avg((*img).data[i][j]) < treash_value)
718: pxl_less++;
719:
720: if(rgb_avg((*img).data[i][j]) > treash_value)
721: pxl_more++;
722: }
723:
724: if(pxl_less > pxl_more)
725: return -1;
726: else if(pxl_less < pxl_more)
727: return 1;
728: else
729: return 0;
730: }
731:
732: /**********************File I/O functions*******************************/
733: /***********************************************************************/
734:
735: /*Gets an ascii color pgm image file (type P3).*/
736: void getPGMfile (char filename[], PGMImage *img)
737: {
738: FILE *in_file;
739: char ch;
740: int row, col;
741:
742: in_file = fopen(filename, "r");
743: if (in_file == NULL)
744: {
745: fprintf(stderr, "Error: Unable to open file %s\n\n", filename);
746: exit(8);
747: }
748:
749: printf("\nReading image file: %s", filename);
750:
751: do /* skip header identifier */
752: ch = getc(in_file);
753: while (ch != '\n');
754:
755: do /* skip comments lines */
756: {
757: while (ch != '\n') ch = getc(in_file); /* flush to end of line */
758: ch = getc(in_file);
759: } while (ch == '#');
760:
761: fseek(in_file, -1, SEEK_CUR); /* backup one character */
762:
763: fscanf(in_file,"%d", &((*img).width));
764: fscanf(in_file,"%d", &((*img).height));
765: fscanf(in_file,"%d", &((*img).maxVal));
766:
767: printf("\n width = %d",(*img).width);
768: printf("\n height = %d",(*img).height);
769: printf("\n maxVal = %d",(*img).maxVal);
770: printf("\n");
771:
772: if (((*img).width > MAX) || ((*img).height > MAX))
773: {
774: printf("\n\n***ERROR - image too big for current image structure***\n\n");
775: exit(0);
776: }
777:
778: for (row=(*img).height-1; row>=0; row--)
779: for (col=0; col<(*img).width; col++)
780: {
781: fscanf(in_file,"%d", &((*img).data[row][col].red) );
782: fscanf(in_file,"%d", &((*img).data[row][col].green));
783: fscanf(in_file,"%d", &((*img).data[row][col].blue));
784: }
785: fclose(in_file);
786: printf("\nDone reading file.\n");
787: }
788:
789:
790: void save(PGMImage *img)
791: {
792: int i, j, nr, nc, k;
793: int red, green, blue;
794: FILE *iop;
795:
796: nr = img->height;
797: nc = img->width;
798:
799: iop = fopen("image1.pgm", "w");
800: fprintf(iop, "P3\n");
801: fprintf(iop, "%d %d\n", nc, nr);
802: fprintf(iop, "255\n");
803:
804: k = 1;
805: for(i = nr - 1; i >= 0; i--)
806: {
807: for(j = 0; j < nc; j++)
808: {
809: red = img->data[i][j].red;
810: green = img->data[i][j].green;
811: blue = img->data[i][j].blue;
812: if(red < 0)
813: {
814: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
815: printf(" Setting red to zero\n");
816: red = 0;
817: }
818: if(green < 0)
819: {
820: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
821: printf(" Setting green to zero\n");
822: green = 0;
823: }
824: if(blue < 0)
825: {
826: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
827: printf(" Setting green to zero\n");
828: blue = 0;
829: }
830: if(red > 255)
831: {
832: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
833: printf(" Setting red to 255\n");
834: red = 255;
835: }
836: if(green > 255)
837: {
838: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
839: printf(" Setting green to 255\n");
840: green = 255;
841: }
842: if(blue > 255)
843: {
844: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
845: printf(" Setting blue to 255\n");
846: blue = 255;
847: }
848:
849: if(k % 10)
850: {
851: fprintf(iop, "%d ", red);
852: fprintf(iop, "%d ", green);
853: fprintf(iop, "%d ", blue);
854: }
855: else /*for newline*/
856: {
857: fprintf(iop, "%d\n", red);
858: fprintf(iop, "%d\n", green);
859: fprintf(iop, "%d\n", blue);
860: }
861: k++;
862: }
863: }
864: fprintf(iop, "\n");
865: fclose(iop);
866: }
867:
868:
869:
870:
871: /****Calculation & drawing functions of the image translations**********
872: ***********************************************************************/
873:
874:
875: void showColor (PGMImage *img)
876: {
877: int row, col; /*y, x*/
878: /*for (row=(*img).height-1; row>=0; row--)
879: for (col=0; col<(*img).width; col++)
880: {
881:
882: setCPixel(col, row, (*img).data[row][col]);
883: }*/
884:
885: int i, j; /*loop counting: i = x, j = y*/
886: int mid_width = ((*img).width / 2);
887: int mid_height = ((*img).height / 2);
888:
889: for(i = 0; i < mid_width / 2; i++)
890: {
891: for(j = 0; j < mid_height; j++)
892: {
893: /*inorder they are:
894: bottom left, bottom middle right, top left, top m right,
895: bottom middle left, bottom right, top middle left, top right.*/
896:
897: setCPixel(i, j, (*img).data[j][i]);
898: setCPixel(i + mid_width, j, (*img).data[j][i + mid_width]);
899: setCPixel(i, j + mid_height, (*img).data[j + mid_height][i]);
900: setCPixel(i + mid_width, j + mid_height,
901: (*img).data[j + mid_height][i + mid_width]);
902:
903: setCPixel(mid_width - i - 1, j,
904: (*img).data[j][mid_width - i - 1]);
905: setCPixel((*img).width - i - 1, j,
906: (*img).data[j][(*img).width - i - 1]);
907: setCPixel(mid_width - i - 1, (*img).height - j - 1,
908: (*img).data[(*img).height - j - 1][mid_width - i - 1]);
909: setCPixel((*img).width - i - 1, (*img).height - j - 1,
910: (*img).data[(*img).height - j - 1][(*img).width - i - 1]);
911: }
912: }
913: glFlush();
914: }
915:
916: void camera_correction(PGMImage* new_img, PGMImage* org_img)
917: {
918: int row, col, img_row, img_col; /*loop counting*/
919:
920: /*camera parameters*/
921: float height = 30; /*height of camera in cm*/
922: float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/
923: float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/
924:
925: /*temporary varaibles*/
926: float angular_height_corr;
927: float angular_side_corr;
928: int x_coord, y_coord;
929:
930: memset(new_img, 0, sizeof(PGMImage));
931: (*new_img).height = (*org_img).height;
932: (*new_img).width = (*org_img).width;
933: (*new_img).maxVal = (*org_img).maxVal;
934:
935: for (row=(*org_img).height-1; row>=0; row--)
936: for (col=0; col<(*org_img).width; col++)
937: {
938: /*img_row -= (*org_img).height / 2;
939: img_col = col - (*org_img).width / 2;*/
940:
941: angular_height_corr =
942: (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1));
943: angular_side_corr =
944: (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1));
945:
946: angular_height_corr /= 2;
947: /*angular_side_corr /= 2;*/
948: /*height *= 2;*/
949: height = 150;
950:
951: x_coord = (int)
952: (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr));
953: y_coord = (int)
954: (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr));
955:
956: /*x_coord += (*org_img).width / 2;*/
957: y_coord += (*org_img).height / 2;
958:
959: /*printf("org: (%d, %d) new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/
960:
961: pxlcpy(new_img, y_coord, x_coord, org_img, row, col);
962: }
963: }
964:
965: void new_corr(PGMImage* new_img, PGMImage* org_img)
966: {
967: /*i and j are the left half, k and l are the right half*/
968: float i, k; /*loop counting*/
969: int j, l, row; /*loop counting*/
970: int old_i, old_k;
971:
972: float ins_s = 2; /*insert constant starting value*/
973: float ins_k = ins_s; /*insert constant*/
974:
975: /*The halfway marks in the width.*/
976: int mid_width_left = ((*new_img).width / 2) - 1;
977: int mid_width_right = ((*new_img).width / 2);
978:
979: /*just to be thourough clear the memory and reset maxes*/
980: memset(new_img, 0, sizeof(PGMImage));
981: (*new_img).height = (*org_img).height;
982: (*new_img).width = (*org_img).width;
983: (*new_img).maxVal = (*org_img).maxVal;
984:
985: /*Loop through each row from top to bottom...*/
986: for(row = ((*new_img).height - 1); row >= 0; row--)
987: {
988: /*...reset moire interference removal counter...*/
989: old_i = ((*new_img).width / 2) - 1;
990: old_k = ((*new_img).width / 2);
991:
992: /*...so each half is ajusted to remove perspective effect...*/
993: for(i = j = mid_width_left, k = l = mid_width_right
994: ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width
995: ; i -= ins_k, j--, k += ins_k, l++)
996: {
997: for(;old_i >= (int)i; old_i--) /*...in the left half...*/
998: pxlcpy(new_img, row, old_i, org_img, row, j);
999: for(;old_k <= (int)k; old_k++) /*...in the right half.*/
1000: pxlcpy(new_img, row, old_k, org_img, row, l);
1001: }
1002: /*Move the new image x_coord pixel counter to next new image pixel*/
1003: ins_k -= ((ins_s - 1.0) / (*new_img).height);
1004: }
1005: }
1006:
1007: void color_to_gray(PGMImage* new_img, PGMImage* org_img)
1008: {
1009: int row, col; /*loop counting*/
1010: RGB_INT cur_pxl; /*current pixel*/
1011:
1012: (*new_img).height = (*org_img).height;
1013: (*new_img).width = (*org_img).width;
1014: (*new_img).maxVal = (*org_img).maxVal;
1015:
1016: /*Starting with the top row...*/
1017: for(row = (*new_img).height - 1; row >= 0; row--)
1018: for(col = 0; col < (*new_img).width - 1; col++)
1019: {
1020: cur_pxl = (*org_img).data[row][col]; /*more readable*/
1021:
1022: /*convert each RGB to the average of the original*/
1023: (*new_img).data[row][col].red = rgb_avg(cur_pxl);
1024: (*new_img).data[row][col].green = rgb_avg(cur_pxl);
1025: (*new_img).data[row][col].blue = rgb_avg(cur_pxl);
1026: }
1027: }
1028:
1029: void moravec(PGMImage* new_img, PGMImage* org_img)
1030: {
1031: int row, col; /*loop counting*/
1032: int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1033: int running_sum;
1034: float K = .5; /*.125 according to org. formula, but .5 is brighter*/
1035: int max_val = 0, row_max, col_max; /* max porportion value in image*/
1036:
1037: memset(new_img, 0, sizeof(PGMImage));
1038: (*new_img).height = (*org_img).height;
1039: (*new_img).width = (*org_img).width;
1040: (*new_img).maxVal = (*org_img).maxVal;
1041:
1042: /*starting at the top row*/
1043: for(row = (*new_img).height - 1 - 1; row > 0; row--)
1044: for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/
1045: {
1046: i = row;
1047: j = col;
1048: running_sum = 0;
1049:
1050: /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1051: for(k = i - 1; k <= i + 1; k++) /*row*/
1052: for(l = j - 1; l <= j + 1; l++) /*column*/
1053: running_sum += abs(rgb_avg((*org_img).data[k][l]) -
1054: rgb_avg((*org_img).data[i][j]));
1055:
1056: /*assign the new pixel value*/
1057: (*new_img).data[row][col].red = (int)(K * running_sum);
1058: (*new_img).data[row][col].green = (int)(K * running_sum);
1059: (*new_img).data[row][col].blue = (int)(K * running_sum);
1060: }
1061: }
1062:
1063: void detect_corners(PGMImage* org_img)
1064: {
1065: /*pointer to an array of pointers which point to the first nodes in each of
1066: the chain codes.*/
1067: chainCode **chain_codes;
1068:
1069: glPointSize(4); /*make points more visible, if desired*/
1070: glLineWidth(4);
1071:
1072: chain_codes = showChain(org_img);
1073: showBound(org_img, chain_codes);
1074:
1075: glFlush();/*force drawing*/
1076: }
1077:
1078: /* =================================================================
1079: * Callback functions.
1080: *
1081: * color = displayed graphics in window
1082: * menu = menu event handling
1083: * keyboard = deyboard event handling
1084: * ----------------------------------------------------------------- */
1085: void color(void)
1086: {
1087: /*glClear (GL_COLOR_BUFFER_BIT);*/
1088:
1089: /* printf("\nDrawing Original image...\n");*/
1090: showColor(img_cur);
1091:
1092: /*glFlush();*/
1093: }
1094:
1095: #define RESTART 0
1096: #define CAMERA_CORRECTION 1
1097: #define X2_C_CORR 2
1098: #define NEW_CORR 3
1099: #define COLOR_TO_GRAY 4
1100: #define MORAVEC 5
1101: #define CORNERS 6
1102:
1103: void menu(int selection)
1104: {
1105: if(selection == RESTART)
1106: {
1107: memcpy(img1, img0, sizeof(PGMImage));
1108: img_cur = img0;
1109: }
1110: if(selection == CAMERA_CORRECTION)
1111: {
1112: printf("Starting camera correction\n");
1113: camera_correction(img1, img0);
1114: img_cur = img1;
1115: }
1116: if(selection == X2_C_CORR)
1117: {
1118: printf("Starting camera correction\n");
1119: camera_correction(img1, img0);
1120: camera_correction(img2, img1);
1121: img_cur = img2;
1122: }
1123: if(selection == NEW_CORR)
1124: {
1125: new_corr(img1, img0);
1126: img_cur = img1;
1127: }
1128: if(selection == COLOR_TO_GRAY)
1129: {
1130: color_to_gray(img1, img0);
1131: img_cur = img1;
1132: }
1133: if(selection == MORAVEC)
1134: {
1135: moravec(img1, img0);
1136: img_cur = img1;
1137: }
1138: if(selection == CORNERS)
1139: {
1140: printf("img avg: %d\n", img_pxl_avg(img0));
1141: new_corr(img1, img0);
1142: /*moravec(img2, img1);*/
1143: showColor(img1);
1144: detect_corners(img1);
1145: img_cur = img1;
1146: return;
1147: }
1148: /*glClear (GL_COLOR_BUFFER_BIT);*/
1149: showColor(img_cur);
1150: glutPostRedisplay();
1151: }
1152:
1153: void keyboard(unsigned char key, int x, int y)
1154: {
1155: switch (key)
1156: {
1157: case 27:
1158: exit(0);
1159: break;
1160: }
1161: }
1162:
1163: void mouse(int button, int state, int x, int y)
1164: {
1165: char temp[50];
1166:
1167: if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
1168: {
1169: sprintf(temp, "(x, y): (%d, %d) red: %d green: %d blue: %d\n",
1170: x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red,
1171: (*img_cur).data[VSIZE - y][x].green,
1172: (*img_cur).data[VSIZE - y][x].blue);
1173: setCRect(0, 0, 200, 12, black);
1174: glColor3f(1.0, 0.0, 0.0);
1175: drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp);
1176: glFlush();
1177: }
1178: }
1179:
1180: /* =================================================================
1181: * init - initializes graphics viewport
1182: *
1183: * You should not have to change this function for the first few
1184: * projects we have. It will become more important when we move to
1185: * 3D graphics.
1186: * ----------------------------------------------------------------- */
1187: void init (void)
1188: {
1189:
1190: /*
1191: * select clearing color - white
1192: */
1193: glClearColor (1.0, 1.0, 1.0, 0.0);
1194:
1195: /*
1196: * initialize viewport values
1197: */
1198: glMatrixMode(GL_PROJECTION);
1199: glLoadIdentity();
1200: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
1201:
1202: /*add menus*/
1203: glutCreateMenu(menu);
1204: glutAddMenuEntry("Restart", RESTART);
1205: glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION);
1206: glutAddMenuEntry("2x C. Corr.", X2_C_CORR);
1207: glutAddMenuEntry("new corr", NEW_CORR);
1208: glutAddMenuEntry("color to gray", COLOR_TO_GRAY);
1209: glutAddMenuEntry("moravec", MORAVEC);
1210: glutAddMenuEntry("corners", CORNERS);
1211: glutAttachMenu(GLUT_RIGHT_BUTTON);
1212: }
1213:
1214: int main(int argc, char** argv)
1215: {
1216: char PGMfileName[MAX_FILE_LENGTH];
1217:
1218: int WindowID;
1219:
1220: int i; /*looping variable*/
1221:
1222: /*parse the command line*/
1223: if(argc == 1)
1224: {
1225: printf("To few parameters.\n");
1226: printf("Usage: research <file.pgm>\n");
1227: exit(1);
1228: }
1229: else if(argc == 2)
1230: strcpy(PGMfileName, argv[1]);
1231: else
1232: {
1233: printf("To many parameters.\n");
1234: printf("Usage: research <file.pgm>\n");
1235: exit(1);
1236: }
1237: /*
1238: * Read in image file. - note: sets our global values, too.
1239: * ----------------------------------------------------------------- */
1240:
1241: img0 = (PGMImage*) malloc(sizeof(PGMImage));
1242: getPGMfile(PGMfileName, img0);
1243: HSIZE = (*img0).width;
1244: VSIZE = (*img0).height;
1245: MVAL = (*img0).maxVal;
1246:
1247: img_cur = img0; /*VERY IMPORTANT to set this*/
1248:
1249: /*allocate memory for second image*/
1250: img1 = (PGMImage*) malloc(sizeof(PGMImage));
1251: memcpy(img1, img0, sizeof(PGMImage));
1252: /*(*img1).width = HSIZE;
1253: (*img1).height = VSIZE;
1254: (*img1).maxVal = 255;*/
1255:
1256: img2 = (PGMImage*) malloc(sizeof(PGMImage));
1257: memcpy(img2, img0, sizeof(PGMImage));
1258:
1259: /*
1260: * Initialize the glut package.
1261: * ----------------------------------------------------------------- */
1262: glutInit(&argc, argv);
1263: glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
1264: /*
1265: * Define a new window (its size, position and title).
1266: * ----------------------------------------------------------------- */
1267: glutInitWindowSize (HSIZE, VSIZE); /*size*/
1268: glutInitWindowPosition (10, 10); /*position*/
1269: WindowID = glutCreateWindow (PGMfileName); /*title*/
1270: glutSetWindow(WindowID);
1271: glutDisplayFunc(color);
1272:
1273: /*
1274: * Call our init function to define viewing parameters.
1275: * ----------------------------------------------------------------- */
1276: init ();
1277:
1278: glutMouseFunc(mouse);
1279: glutKeyboardFunc(keyboard);
1280: glutMainLoop();
1281:
1282: /*
1283: * When we reach here, we've left the event loop and are ready to
1284: * exit.
1285: * ----------------------------------------------------------------- */
1286: return 0;
1287: }
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
1296:
1297:
1298:
1299:
1300: