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: