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: