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: /*frees the memory that the chain code(s) are using*/
547: void free_chaincode(chainCode** pointer)
548: {
549: int i; /*loop counting*/
550: chainCode* temp, *to_free;
551:
552: for(i = 0; pointer[i] && i < MAX_CHAINS; i++)/*for each chaincode*/
553: {
554: temp = pointer[i];
555: while(temp) /*for each node*/
556: {
557: to_free = temp;
558: temp = temp->next;
559: free(to_free);
560: }
561: }
562:
563: free(pointer); /*free the array of pointers to chaincodes*/
564: }
565:
566: /*****BOUNDRY BOX**********************************************************
567: **********************************************************************/
568:
569: /*takes two coordinates as x and y pairs and returns the distence betweem them
570: as a decimal*/
571: float findDist(int x1, int y1, int x2, int y2)
572: {
573: return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
574: }
575:
576: /*1st param: The array of coords that the first point of the major axis is
577: returned in.
578: 2nd: The array of coords that the second point of the major axis is
579: returned in.
580: 3rd: The array of chain codes that are searched through to find the major
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 findFirstTwoCorners(coord corner1[], coord corner2[],
586: chainCode** chainCodes)
587: {
588: int i; /*loop counting*/
589: chainCode *temp, *search;
590: double max_dist, test_dist;
591:
592: printf("\nFinding first 2 corners.\n");
593:
594: /*as long as there are codes to check, keep checking. Note: the ending
595: condition is when a NULL chainCodes value is reached. Thusly, it works
596: like a string requiring it to have the last legal value followed by a
597: null value.*/
598: for(i = 0; (temp = chainCodes[i]) && (i < MAX_CHAINS); i++)
599: {
600: max_dist = 0.0; /*reset this for each iteration*/
601:
602: /*printf("checking list: %d\n", i);*/
603:
604: while(temp) /*while there are still nodes to check in the chain*/
605: {
606: search = temp; /*set the faster moving search pointer to temp,
607: this increases the effiecency a lot compared to
608: setting it equal to the first node..*/
609: while(search)
610: {
611: /*setCPixel(temp->location.x, temp->location.y, green);*/
612:
613: /*determine if found a new maximum distance between two locations*/
614: if((test_dist = findDist(search->location.x, search->location.y,
615: temp->location.x, temp->location.y)) > max_dist)
616: {
617: max_dist = test_dist;
618: corner1[i].x = temp->location.x;
619: corner1[i].y = temp->location.y;
620: corner2[i].x = search->location.x;
621: corner2[i].y = search->location.y;
622: }
623: search = search->next;
624: }
625: temp = temp->next;
626: }
627: /*printf("point1: %d %d\n", max1[i].x, max1[i].y);
628: printf("point2: %d %d\n", max2[i].x, max2[i].y);*/
629: }
630: }
631:
632: /*1st param: Array of coords for the first corner of each chain code.
633: 2nd param: Array of coords for the second corner of each chain code.
634: The first two parameters should equal the first two parameters "returned"
635: from the findFirstTwoCorners() function.
636: 3rd: Array of coords "returned" with the third corners.
637: 4th: Array of coords "returned" with the fourth corners.
638: 5th: Pointer pointing to the array of chaincode pointers, obtained from
639: showChain().*/
640: void findSecondTwoCorners(coord corner1[], coord corner2[], coord corner3[],
641: coord corner4[], chainCode** chain_code_array)
642: {
643: int i; /*loop counting*/
644: chainCode* temp;
645: float temp_dist1, temp_dist2; /*distance between point and each corner*/
646: coord canidate_coord1, temp_coord;
647: float canidate_dist1, max_dist;
648: int corner_count;
649:
650: printf("\nFinding last 2 corners.\n");
651:
652: /*for each chain code find the corners*/
653: for(i = 0; chain_code_array[i] && i < MAX_CHAINS; i++)
654: {
655: temp = chain_code_array[i];
656:
657: /*reset these for the next chain code*/
658: max_dist = 0.0;
659: corner_count = 1;
660:
661: while(temp) /*while there are nodes in the chain code to check*/
662: {
663: /*setCPixel(temp->location.x, temp->location.y, color1);*/
664:
665: /*determine the first canidate coord for corner 3/4*/
666: if(((temp->location.x == corner1[i].x)
667: && (temp->location.y == corner1[i].y))
668: || ((temp->location.x == corner2[i].x)
669: && (temp->location.y == corner2[i].y)))
670: {
671: /*if this corner found is the first of the two allready known
672: corners, then set the first canidate coord data and reset data
673: to find the next canidate corner point*/
674: if(corner_count == 1)
675: {
676: canidate_coord1.x = temp_coord.x;
677: canidate_coord1.y = temp_coord.y;
678: canidate_dist1 = max_dist;
679:
680: corner_count = 2; /*set for next corner*/
681: max_dist = 0.0;
682: }
683: else if(corner_count == 2)
684: {
685: /*the second canidate is always a corner*/
686: corner4[i].x = temp_coord.x;
687: corner4[i].y = temp_coord.y;
688:
689: max_dist = 0.0; /*set for next corner canidate*/
690: }
691: }
692:
693: /*calculate the distance between the current point being checked and
694: each corner point*/
695: temp_dist1 = findDist(corner1[i].x, corner1[i].y, temp->location.x,
696: temp->location.y);
697: temp_dist2 = findDist(corner2[i].x, corner2[i].y, temp->location.x,
698: temp->location.y);
699:
700: /*if the current point is the furthest away sofar, store this point
701: untill it is overridden or becomes a canidate point*/
702: if((temp_dist1 + temp_dist2) > max_dist)
703: {
704: temp_coord.x = temp->location.x;
705: temp_coord.y = temp->location.y;
706:
707: max_dist = (temp_dist1 + temp_dist2);
708: }
709:
710: temp = temp->next; /*advance*/
711: }
712:
713: /*from the three canidate coords find the two real corners.*/
714: /*the second canidate will always be a corner, must test 1 vs 3, where
715: three is in the variables temp_coord and max_dist.*/
716: if(canidate_dist1 > max_dist) /*first canidate*/
717: {
718: corner3[i].x = canidate_coord1.x;
719: corner3[i].y = canidate_coord1.y;
720: }
721: else /*third canidate*/
722: {
723: corner3[i].x = temp_coord.x;
724: corner3[i].y = temp_coord.y;
725: }
726: /*printf("corner3: (%d, %d) corner4: (%d, %d)\n", corner3[i].x,
727: corner3[i].y, corner4[i].x, corner4[i].y);*/
728: }
729: }
730:
731: /*takes a pointer to an image, and a pointer pointing to an array of
732: chain codes pointers, here each chainCode pointer needs to be accessed
733: by calculating the memory address.*/
734: void showBound(PGMImage *original, chainCode** chainCodes)
735: {
736: int i;
737:
738: /*find the first two corners. they will be across a diagnal.*/
739: findFirstTwoCorners(corner1, corner2, chainCodes);
740: /*find the second two corners. they will be across a diagnal too.*/
741: findSecondTwoCorners(corner1, corner2, corner3, corner4, chainCodes);
742: /*
743: for(i = 0; chainCodes[i] && i < MAX_CHAINS; i++)
744: {
745: setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow);
746: setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow);
747: setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow);
748: setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow);
749: setCPixel(corner1[i].x, corner1[i].y, purple);
750: setCPixel(corner2[i].x, corner2[i].y, purple);
751: setCPixel(corner3[i].x, corner3[i].y, purple);
752: setCPixel(corner4[i].x, corner4[i].y, purple);
753: }*/
754: }
755:
756: /**********************File I/O functions*******************************/
757: /***********************************************************************/
758:
759: /*Gets an ascii color pgm image file (type P3).*/
760: void getPGMfile (char filename[], PGMImage *img)
761: {
762: FILE *in_file;
763: char ch;
764: int row, col;
765:
766: in_file = fopen(filename, "r");
767: if (in_file == NULL)
768: {
769: fprintf(stderr, "Error: Unable to open file %s\n\n", filename);
770: exit(8);
771: }
772:
773: printf("\nReading image file: %s", filename);
774:
775: do /* skip header identifier */
776: ch = getc(in_file);
777: while (ch != '\n');
778:
779: do /* skip comments lines */
780: {
781: while (ch != '\n') ch = getc(in_file); /* flush to end of line */
782: ch = getc(in_file);
783: } while (ch == '#');
784:
785: fseek(in_file, -1, SEEK_CUR); /* backup one character */
786:
787: fscanf(in_file,"%d", &((*img).width));
788: fscanf(in_file,"%d", &((*img).height));
789: fscanf(in_file,"%d", &((*img).maxVal));
790:
791: printf("\n width = %d",(*img).width);
792: printf("\n height = %d",(*img).height);
793: printf("\n maxVal = %d",(*img).maxVal);
794: printf("\n");
795:
796: if (((*img).width > MAX) || ((*img).height > MAX))
797: {
798: printf("\n\n***ERROR - image too big for current image structure***\n\n");
799: exit(0);
800: }
801:
802: for (row=(*img).height-1; row>=0; row--)
803: for (col=0; col<(*img).width; col++)
804: {
805: fscanf(in_file,"%d", &((*img).data[row][col].red) );
806: fscanf(in_file,"%d", &((*img).data[row][col].green));
807: fscanf(in_file,"%d", &((*img).data[row][col].blue));
808: }
809: fclose(in_file);
810: printf("\nDone reading file.\n");
811: }
812:
813:
814: void save(PGMImage *img)
815: {
816: int i, j, nr, nc, k;
817: int red, green, blue;
818: FILE *iop;
819:
820: nr = img->height;
821: nc = img->width;
822:
823: iop = fopen("image1.pgm", "w");
824: fprintf(iop, "P3\n");
825: fprintf(iop, "%d %d\n", nc, nr);
826: fprintf(iop, "255\n");
827:
828: k = 1;
829: for(i = nr - 1; i >= 0; i--)
830: {
831: for(j = 0; j < nc; j++)
832: {
833: red = img->data[i][j].red;
834: green = img->data[i][j].green;
835: blue = img->data[i][j].blue;
836: if(red < 0)
837: {
838: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
839: printf(" Setting red to zero\n");
840: red = 0;
841: }
842: if(green < 0)
843: {
844: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
845: printf(" Setting green to zero\n");
846: green = 0;
847: }
848: if(blue < 0)
849: {
850: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
851: printf(" Setting green to zero\n");
852: blue = 0;
853: }
854: if(red > 255)
855: {
856: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j);
857: printf(" Setting red to 255\n");
858: red = 255;
859: }
860: if(green > 255)
861: {
862: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j);
863: printf(" Setting green to 255\n");
864: green = 255;
865: }
866: if(blue > 255)
867: {
868: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j);
869: printf(" Setting blue to 255\n");
870: blue = 255;
871: }
872:
873: if(k % 10)
874: {
875: fprintf(iop, "%d ", red);
876: fprintf(iop, "%d ", green);
877: fprintf(iop, "%d ", blue);
878: }
879: else /*for newline*/
880: {
881: fprintf(iop, "%d\n", red);
882: fprintf(iop, "%d\n", green);
883: fprintf(iop, "%d\n", blue);
884: }
885: k++;
886: }
887: }
888: fprintf(iop, "\n");
889: fclose(iop);
890: }
891:
892:
893: /****Calculation & drawing functions of the image translations**********
894: ***********************************************************************/
895:
896: void error(char* message)
897: {
898: printf("%s\n");
899: exit(1);
900: }
901:
902: void showColor (PGMImage *img)
903: {
904: int i, j; /*loop counting: i = y, j = x*/
905:
906: GLubyte checkImage[(*img).height][(*img).width][3];
907:
908: for(i = 0; i < (*img).height; i++)
909: {
910: for(j = 0; j < (*img).width; j++)
911: {
912: checkImage[i][j][0] = (GLubyte) (*img).data[i][j].red;
913: checkImage[i][j][1] = (GLubyte) (*img).data[i][j].green;
914: checkImage[i][j][2] = (GLubyte) (*img).data[i][j].blue;
915: }
916: }
917: glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
918:
919: glDrawPixels((*img).width, (*img).height, GL_RGB,
920: GL_UNSIGNED_BYTE, checkImage);
921:
922: /*first check for non-null pointer, next check for dereferenced pointers
923: in the array of head pointers and lastly make sure things stay in
924: bound of the max incase all MAX_CHAINS number of chains are used.*/
925: for(i = 0; chain_codes && chain_codes[i] && i < MAX_CHAINS; i++)
926: {
927: setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow);
928: setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow);
929: setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow);
930: setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow);
931: setCPixel(corner1[i].x, corner1[i].y, purple);
932: setCPixel(corner2[i].x, corner2[i].y, purple);
933: setCPixel(corner3[i].x, corner3[i].y, purple);
934: setCPixel(corner4[i].x, corner4[i].y, purple);
935: }
936:
937: glFlush();
938: }
939:
940: void camera_correction(PGMImage* new_img, PGMImage* org_img)
941: {
942: int row, col, img_row, img_col; /*loop counting*/
943:
944: /*camera parameters*/
945: float height = 30; /*height of camera in cm*/
946: float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/
947: float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/
948:
949: /*temporary varaibles*/
950: float angular_height_corr;
951: float angular_side_corr;
952: int x_coord, y_coord;
953:
954: memset(new_img, 0, sizeof(PGMImage));
955: (*new_img).height = (*org_img).height;
956: (*new_img).width = (*org_img).width;
957: (*new_img).maxVal = (*org_img).maxVal;
958:
959: for (row=(*org_img).height-1; row>=0; row--)
960: for (col=0; col<(*org_img).width; col++)
961: {
962: /*img_row -= (*org_img).height / 2;
963: img_col = col - (*org_img).width / 2;*/
964:
965: angular_height_corr =
966: (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1));
967: angular_side_corr =
968: (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1));
969:
970: angular_height_corr /= 2;
971: /*angular_side_corr /= 2;*/
972: /*height *= 2;*/
973: height = 150;
974:
975: x_coord = (int)
976: (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr));
977: y_coord = (int)
978: (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr));
979:
980: /*x_coord += (*org_img).width / 2;*/
981: y_coord += (*org_img).height / 2;
982:
983: /*printf("org: (%d, %d) new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/
984:
985: pxlcpy(new_img, y_coord, x_coord, org_img, row, col);
986: }
987: }
988:
989: void new_corr(PGMImage* new_img, PGMImage* org_img)
990: {
991: /*i and j are the left half, k and l are the right half*/
992: float i, k; /*loop counting*/
993: int j, l, row; /*loop counting*/
994: int old_i, old_k;
995:
996: float ins_s = 2; /*insert constant starting value*/
997: float ins_k = ins_s; /*insert constant*/
998:
999: /*The halfway marks in the width.*/
1000: int mid_width_left = ((*new_img).width / 2) - 1;
1001: int mid_width_right = ((*new_img).width / 2);
1002:
1003: /*just to be thourough clear the memory and reset maxes*/
1004: memset(new_img, 0, sizeof(PGMImage));
1005: (*new_img).height = (*org_img).height;
1006: (*new_img).width = (*org_img).width;
1007: (*new_img).maxVal = (*org_img).maxVal;
1008:
1009: /*Loop through each row from top to bottom...*/
1010: for(row = ((*new_img).height - 1); row >= 0; row--)
1011: {
1012: /*...reset moire interference removal counter...*/
1013: old_i = ((*new_img).width / 2) - 1;
1014: old_k = ((*new_img).width / 2);
1015:
1016: /*...so each half is ajusted to remove perspective effect...*/
1017: for(i = j = mid_width_left, k = l = mid_width_right
1018: ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width
1019: ; i -= ins_k, j--, k += ins_k, l++)
1020: {
1021: for(;old_i >= (int)i; old_i--) /*...in the left half...*/
1022: pxlcpy(new_img, row, old_i, org_img, row, j);
1023: for(;old_k <= (int)k; old_k++) /*...in the right half.*/
1024: pxlcpy(new_img, row, old_k, org_img, row, l);
1025: }
1026: /*Move the new image x_coord pixel counter to next new image pixel*/
1027: ins_k -= ((ins_s - 1.0) / (*new_img).height);
1028: }
1029: }
1030:
1031: void color_to_gray(PGMImage* new_img, PGMImage* org_img)
1032: {
1033: int row, col; /*loop counting*/
1034: RGB_INT cur_pxl; /*current pixel*/
1035:
1036: (*new_img).height = (*org_img).height;
1037: (*new_img).width = (*org_img).width;
1038: (*new_img).maxVal = (*org_img).maxVal;
1039:
1040: /*Starting with the top row...*/
1041: for(row = (*new_img).height - 1; row >= 0; row--)
1042: for(col = 0; col < (*new_img).width - 1; col++)
1043: {
1044: cur_pxl = (*org_img).data[row][col]; /*more readable*/
1045:
1046: /*convert each RGB to the average of the original*/
1047: (*new_img).data[row][col].red = rgb_avg(cur_pxl);
1048: (*new_img).data[row][col].green = rgb_avg(cur_pxl);
1049: (*new_img).data[row][col].blue = rgb_avg(cur_pxl);
1050: }
1051: }
1052:
1053: void moravec(PGMImage* new_img, PGMImage* org_img)
1054: {
1055: int row, col; /*loop counting*/
1056: int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1057: int running_sum;
1058: float K = .5; /*.125 according to org. formula, but .5 is brighter*/
1059: int max_val = 0, row_max, col_max; /* max porportion value in image*/
1060:
1061: memset(new_img, 0, sizeof(PGMImage));
1062: (*new_img).height = (*org_img).height;
1063: (*new_img).width = (*org_img).width;
1064: (*new_img).maxVal = (*org_img).maxVal;
1065:
1066: /*starting at the top row*/
1067: for(row = (*new_img).height - 1 - 1; row > 0; row--)
1068: for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/
1069: {
1070: i = row;
1071: j = col;
1072: running_sum = 0;
1073:
1074: /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/
1075: for(k = i - 1; k <= i + 1; k++) /*row*/
1076: for(l = j - 1; l <= j + 1; l++) /*column*/
1077: running_sum += abs(rgb_avg((*org_img).data[k][l]) -
1078: rgb_avg((*org_img).data[i][j]));
1079:
1080: /*assign the new pixel value*/
1081: (*new_img).data[row][col].red = (int)(K * running_sum);
1082: (*new_img).data[row][col].green = (int)(K * running_sum);
1083: (*new_img).data[row][col].blue = (int)(K * running_sum);
1084: }
1085: }
1086:
1087: void detect_corners(PGMImage* org_img)
1088: {
1089: glPointSize(4); /*make points more visible, if desired*/
1090: glLineWidth(4);
1091:
1092: chain_codes = showChain(org_img);
1093: showBound(org_img, chain_codes);
1094:
1095: free_chaincode(chain_codes);
1096: }
1097:
1098: /* =================================================================
1099: * Callback functions.
1100: *
1101: * color = displayed graphics in window
1102: * menu = menu event handling
1103: * keyboard = deyboard event handling
1104: * ----------------------------------------------------------------- */
1105: void color(void)
1106: {
1107: /*glClear (GL_COLOR_BUFFER_BIT);*/
1108:
1109: /* printf("\nDrawing Original image...\n");*/
1110: showColor(img_cur);
1111:
1112: /*glFlush();*/
1113: #ifdef BUFFERED
1114: glutSwapBuffers();
1115: #endif
1116: }
1117:
1118: #define RESTART 0
1119: #define CAMERA_CORRECTION 1
1120: #define X2_C_CORR 2
1121: #define NEW_CORR 3
1122: #define COLOR_TO_GRAY 4
1123: #define MORAVEC 5
1124: #define CORNERS 6
1125:
1126: void menu(int selection)
1127: {
1128: if(selection == RESTART)
1129: {
1130: memcpy(img1, img0, sizeof(PGMImage));
1131: img_cur = img0;
1132: }
1133: if(selection == CAMERA_CORRECTION)
1134: {
1135: printf("Starting camera correction\n");
1136: camera_correction(img1, img0);
1137: img_cur = img1;
1138: }
1139: if(selection == X2_C_CORR)
1140: {
1141: printf("Starting camera correction\n");
1142: camera_correction(img1, img0);
1143: camera_correction(img2, img1);
1144: img_cur = img2;
1145: }
1146: if(selection == NEW_CORR)
1147: {
1148: new_corr(img1, img0);
1149: img_cur = img1;
1150: }
1151: if(selection == COLOR_TO_GRAY)
1152: {
1153: color_to_gray(img1, img0);
1154: img_cur = img1;
1155: }
1156: if(selection == MORAVEC)
1157: {
1158: moravec(img1, img0);
1159: img_cur = img1;
1160: }
1161: if(selection == CORNERS)
1162: {
1163: new_corr(img1, img0);
1164: showColor(img1);
1165: detect_corners(img1);
1166: img_cur = img1;
1167: }
1168:
1169: glutPostRedisplay();
1170: }
1171:
1172: void keyboard(unsigned char key, int x, int y)
1173: {
1174: switch (key)
1175: {
1176: case 27:
1177: exit(0);
1178: break;
1179: }
1180: }
1181:
1182: void mouse(int button, int state, int x, int y)
1183: {
1184: char temp[50];
1185:
1186: if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
1187: {
1188: sprintf(temp, "(x, y): (%d, %d) red: %d green: %d blue: %d\n",
1189: x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red,
1190: (*img_cur).data[VSIZE - y][x].green,
1191: (*img_cur).data[VSIZE - y][x].blue);
1192: setCRect(0, 0, 200, 12, black);
1193: glColor3f(1.0, 0.0, 0.0);
1194: drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp);
1195: glFlush();
1196: }
1197: }
1198:
1199: void buffer()
1200: {
1201: detect_corners(img_cur);
1202:
1203: glutPostRedisplay();
1204: }
1205:
1206: /* =================================================================
1207: * init - initializes graphics viewport
1208: *
1209: * You should not have to change this function for the first few
1210: * projects we have. It will become more important when we move to
1211: * 3D graphics.
1212: * ----------------------------------------------------------------- */
1213: void init (void)
1214: {
1215: /*
1216: * select clearing color - white
1217: */
1218: glClearColor (1.0, 1.0, 1.0, 0.0);
1219:
1220: /*
1221: * initialize viewport values
1222: */
1223: glMatrixMode(GL_PROJECTION);
1224: glLoadIdentity();
1225: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
1226:
1227: /*add menus*/
1228: glutCreateMenu(menu);
1229: glutAddMenuEntry("Restart", RESTART);
1230: glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION);
1231: glutAddMenuEntry("2x C. Corr.", X2_C_CORR);
1232: glutAddMenuEntry("new corr", NEW_CORR);
1233: glutAddMenuEntry("color to gray", COLOR_TO_GRAY);
1234: glutAddMenuEntry("moravec", MORAVEC);
1235: glutAddMenuEntry("corners", CORNERS);
1236: glutAttachMenu(GLUT_RIGHT_BUTTON);
1237:
1238: }
1239:
1240: int main(int argc, char** argv)
1241: {
1242: char PGMfileName[MAX_FILE_LENGTH];
1243:
1244: int WindowID;
1245:
1246: int i; /*looping variable*/
1247:
1248: /*parse the command line*/
1249: if(argc == 1)
1250: {
1251: printf("To few parameters.\n");
1252: printf("Usage: research <file.pgm>\n");
1253: exit(1);
1254: }
1255: else if(argc == 2)
1256: strcpy(PGMfileName, argv[1]);
1257: else
1258: {
1259: printf("To many parameters.\n");
1260: printf("Usage: research <file.pgm>\n");
1261: exit(1);
1262: }
1263: /*
1264: * Read in image file. - note: sets our global values, too.
1265: * ----------------------------------------------------------------- */
1266:
1267: img0 = (PGMImage*) malloc(sizeof(PGMImage));
1268: getPGMfile(PGMfileName, img0);
1269: HSIZE = (*img0).width;
1270: VSIZE = (*img0).height;
1271: MVAL = (*img0).maxVal;
1272:
1273: img_cur = img0; /*VERY IMPORTANT to set this*/
1274:
1275: /*allocate memory for second image*/
1276: img1 = (PGMImage*) malloc(sizeof(PGMImage));
1277: memcpy(img1, img0, sizeof(PGMImage));
1278: /*(*img1).width = HSIZE;
1279: (*img1).height = VSIZE;
1280: (*img1).maxVal = 255;*/
1281:
1282: img2 = (PGMImage*) malloc(sizeof(PGMImage));
1283: memcpy(img2, img0, sizeof(PGMImage));
1284:
1285: memset(corner1, 0, sizeof(coord) * MAX_CHAINS);
1286: memset(corner2, 0, sizeof(coord) * MAX_CHAINS);
1287: memset(corner3, 0, sizeof(coord) * MAX_CHAINS);
1288: memset(corner4, 0, sizeof(coord) * MAX_CHAINS);
1289:
1290: /*
1291: * Initialize the glut package.
1292: * ----------------------------------------------------------------- */
1293: glutInit(&argc, argv);
1294:
1295: glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
1296:
1297: /*
1298: * Define a new window (its size, position and title).
1299: * ----------------------------------------------------------------- */
1300: glutInitWindowSize (HSIZE, VSIZE); /*size*/
1301: glutInitWindowPosition (10, 10); /*position*/
1302: WindowID = glutCreateWindow (PGMfileName); /*title*/
1303: glutSetWindow(WindowID);
1304: glutDisplayFunc(color);
1305:
1306: /*
1307: * Call our init function to define viewing parameters.
1308: * ----------------------------------------------------------------- */
1309: init ();
1310:
1311: glutMouseFunc(mouse);
1312: #ifdef BUFFERED
1313: glutIdleFunc(buffer);
1314: printf("idle engaged\n");
1315: #endif
1316: glutKeyboardFunc(keyboard);
1317: glutMainLoop();
1318:
1319: /*
1320: * When we reach here, we've left the event loop and are ready to
1321: * exit.
1322: * ----------------------------------------------------------------- */
1323: return 0;
1324: }
1325:
1326:
1327:
1328:
1329:
1330:
1331:
1332:
1333:
1334:
1335:
1336:
1337: