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