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