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