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: /*#ifdef __STDC__ 18: typedef int bool; 19: #endif*/ 20: 21: #ifdef MAX_CHAINS 22: #error "MAX_CHAINS found" 23: #endif 24: 25: /*cartesian coordinate type*/ 26: typedef struct {int x; 27: int y;}coord; 28: 29: /*RGB color struct with floats*/ 30: /*typedef struct {float red; 31: float green; 32: float blue; 33: }RGB; 34: */ 35: /*RGB color struct with ints*/ 36: typedef struct {int red; 37: int green; 38: int blue; 39: }RGB_INT; 40: 41: /*number of chain codes stored*/ 42: /*#define MAX_CHAINS 0010*/ 43: const int MAX_CHAINS = 10; 44: 45: /*These constant values are the chain code directions*/ 46: #define NONE -1 47: #define EAST 0 48: #define NORTHEAST 1 49: #define NORTH 2 50: #define NORTHWEST 3 51: #define WEST 4 52: #define SOUTHWEST 5 53: #define SOUTH 6 54: #define SOUTHEAST 7 55: 56: typedef struct chainCode* chain_t; 57: typedef struct chainCode 58: { 59: chain_t prev; 60: int code; 61: coord location; /*absolute pixel location for starting point*/ 62: chain_t next; 63: }chainCode; /*This struct can be refered to by: struct chainCode or chainCode*/ 64: 65: struct PGMstructure 66: { 67: int maxVal; 68: int width; 69: int height; 70: RGB_INT data[MAX][MAX]; 71: }; 72: 73: typedef struct PGMstructure PGMImage; 74: 75: /*Evil globals, but not do-able otherwise.*/ 76: static PGMImage *img_cur; 77: static PGMImage *img0; /*original*/ 78: static PGMImage *img1; /*current*/ 79: static PGMImage *img2; /*current*/ 80: static int HSIZE; 81: static int VSIZE; 82: static int MVAL; 83: 84: 85: 86: 87: /**************Drawing funcitions************************************/ 88: /********************************************************************/ 89: 90: void setCPixel(int ix, int iy, RGB_INT color) 91: /*Same as setIPixel except that the last parameter is an RGB color*/ 92: { 93: float x = (ix*2.0)/HSIZE - 1.0; 94: float y = (iy*2.0)/VSIZE - 1.0; 95: 96: float red = (float)color.red/(float)MVAL; 97: float green = (float)color.green/(float)MVAL; 98: float blue = (float)color.blue/(float)MVAL; 99: 100: glColor3f(red, green, blue); 101: 102: glBegin(GL_POINTS); 103: glVertex2f (x, y); 104: glEnd(); 105: } 106: 107: void setCLines(int ix1, int iy1, int ix2, int iy2, RGB_INT color) 108: /*Similar as setIPixel except that this one draws a line between the first set 109: of points given and the second set in the RGB color specified*/ 110: { 111: float x1 = (ix1*2.0)/HSIZE - 1.0; 112: float y1 = (iy1*2.0)/VSIZE - 1.0; 113: float x2 = (ix2*2.0)/HSIZE - 1.0; 114: float y2 = (iy2*2.0)/VSIZE - 1.0; 115: 116: float red = (float)color.red/(float)MVAL; 117: float green = (float)color.green/(float)MVAL; 118: float blue = (float)color.blue/(float)MVAL; 119: 120: glColor3f(red, green, blue); 121: 122: glBegin(GL_LINES); 123: glVertex2f (x1, y1); 124: glVertex2f (x2, y2); 125: glEnd(); 126: } 127: 128: void setCRect(int ix1, int iy1, int ix2, int iy2, RGB_INT color) 129: /*Similar as setIPixel except that this one draws a line between the first set 130: of points given and the second set in the RGB color specified*/ 131: { 132: float x1 = (ix1*2.0)/HSIZE - 1.0; 133: float y1 = (iy1*2.0)/VSIZE - 1.0; 134: float x2 = (ix2*2.0)/HSIZE - 1.0; 135: float y2 = (iy2*2.0)/VSIZE - 1.0; 136: 137: float red = (float)color.red/(float)MVAL; 138: float green = (float)color.green/(float)MVAL; 139: float blue = (float)color.blue/(float)MVAL; 140: 141: glColor3f(red, green, blue); 142: 143: glBegin(GL_POLYGON); 144: glVertex2f (x1, y1); 145: glVertex2f (x1, y2); 146: glVertex2f (x2, y2); 147: glVertex2f (x2, y1); 148: glEnd(); 149: } 150: 151: void pxlcpy(PGMImage *dest, int dest_row, int dest_col, 152: PGMImage *src, int src_row, int src_col) 153: { 154: /*make sure values are within bounds*/ 155: if(dest_col > 0 && dest_col < (*dest).width 156: && dest_row > 0 && dest_row < (*dest).height 157: && src_col > 0 && src_col < (*src).width 158: && src_row > 0 && src_row < (*src).height) 159: { 160: (*dest).data[dest_row][dest_col].red = 161: (*src).data[src_row][src_col].red; 162: 163: (*dest).data[dest_row][dest_col].green = 164: (*src).data[src_row][src_col].green; 165: 166: (*dest).data[dest_row][dest_col].blue = 167: (*src).data[src_row][src_col].blue; 168: } 169: } 170: 171: int rgb_avg(RGB_INT cur_pxl) 172: { 173: /*convert each RGB to the average of the original*/ 174: return ((cur_pxl.red + cur_pxl.green + cur_pxl.blue) / 3); 175: } 176: 177: /*1st: pixel one of type RGB_INT 178: 2nd: pixel one of type RGB_INT 179: 3rd: differnce allowed to be considered "equal" or close enough*/ 180: int pxlcmp (RGB_INT pxl1, RGB_INT pxl2, int range) 181: { 182: return ((abs((rgb_avg(pxl1) - rgb_avg(pxl2)))) < range); 183: } 184: 185: /* ================================================================= 186: * drawString - outputs a string of characters to the graphics port 187: * 188: * x, y: defines the starting location to draw the text 189: * note: this point is the lower left anchor of 190: * the first character - a character's decending 191: * portion would be drawn below this point. 192: * theFont: points to the glut font to be used 193: * theString: holds the string to be output -- up to 255 ch 194: * ----------------------------------------------------------------- */ 195: void drawString(int ix, int iy, void *theFont, char theString[256]) 196: { 197: float x = (ix*2.0)/HSIZE - 1.0; 198: float y = (iy*2.0)/VSIZE - 1.0; 199: int i; 200: glRasterPos2f(x, y); 201: for (i = 0; theString[i] != '\0'; i++) /* draw the chars one at a time */ 202: glutBitmapCharacter(theFont, theString[i]); 203: } 204: 205: /******CHAIN CODE************************************************ 206: ****************************************************************/ 207: 208: /*returns NONE if the chain code loops around itself, otherwise false*/ 209: int checkCode(struct chainCode* beginning, int x_current, int y_current, 210: int x_check, int y_check, int dir) 211: { 212: struct chainCode* currentNode = beginning; 213: 214: while(currentNode && currentNode- >next) 215: { 216: if((currentNode- >location.x == x_current) && 217: (currentNode- >location.y == y_current) && 218: (currentNode- >code == dir) && 219: (currentNode- >next- >location.x == x_check) && 220: (currentNode- >next- >location.y == y_check)) 221: return NONE; 222: else 223: currentNode = currentNode- >next; 224: } 225: return FALSE; 226: 227: } 228: 229: RGB_INT chainColor = {0, 0, 255}; 230: 231: /*This function is the intermediate function call during the recursion of the 232: chain code calculation. 233: Preconditions: 234: 1st parameter: integer value containing the current direction code. 235: 2nd parameter: integer value containing the potentially new direction code. 236: 3rd parameter: integer value containing the current x coordinate. 237: 4th parameter: integer value containing the current y coordinate. 238: 5th parameter: pointer to the linked list of the chain code. 239: 6th parameter: pointer to the pgm image being used. 240: Postconditions: The pixel is drawn and if the checked pixel is a boarder pixel 241: true is returned, otherwise false is returned.*/ 242: int checkThings(int *dir, int next, int x_current, int y_current, int x_check, 243: int y_check, struct chainCode **theChain, PGMImage *img, 244: struct chainCode **beginning) 245: { 246: struct chainCode *temp; 247: 248: printf("cur: (%d, %d) check: (%d, %d) dir: %d ", 249: x_current, y_current, x_check, y_check, *dir); 250: printf("pxl_avg org: %d pxl_chk org: %d\n", 251: rgb_avg((*img).data[y_current][x_current]), 252: rgb_avg((*img).data[y_check][x_check])); 253: 254: /*check for being in bounds*/ 255: if((x_check < 0) || (y_check < 0) || (x_check >= (*img).width) || 256: (y_check >= (*img).height)) 257: return FALSE; 258: 259: /*test condition for the end.*/ 260: else if(checkCode(*beginning, x_current, y_current, x_check, y_check, 261: *dir) == NONE) 262: { 263: *dir = NONE; 264: return FALSE; 265: } 266: 267: /*tests if the next pixel is a boundry pixel. If so does stuff*/ 268: if(pxlcmp((*img).data[y_current][x_current], 269: (*img).data[y_check][x_check], 30)) 270: { 271: setCPixel(x_check, y_check, chainColor); 272: glFlush(); 273: *dir = next; 274: printf("here\n"); 275: temp = (chain_t)malloc(sizeof(struct chainCode)); 276: printf("here2\n"); 277: temp- >next = NULL; 278: temp- >code = *dir; 279: temp- >location.x = x_check; 280: temp- >location.y = y_check; 281: temp- >prev = *theChain; 282: if(*theChain) 283: (*theChain)- >next = temp; /*now this is a good thing to set.*/ 284: *theChain = temp; /*advance one*/ 285: 286: if(*beginning == NULL) 287: *beginning = *theChain;/*set this for the first node in the list once*/ 288: return TRUE; 289: } 290: return FALSE; 291: } 292: 293: /*determines the chain code for a starting pixel*/ 294: /*this chain code uses 8 connectivity*/ 295: /*Note: There are many different coordinate systems at work in this function.*/ 296: /*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 297: /* top left is (0, 0). If it looks strange, look harder!!!*/ 298: /*Preconditions: 299: 1st parameter: pointer to the pgm image being used. 300: 2nd parameter: integer value containing the current x coordinate. 301: 3rd parameter: integer value containing the current y coordinate. 302: 4th parameter: integer value containing the current direction code. 303: 5th parameter: pointer to the linked list of the chain code. 304: 6th parameter: pointer to the linked list of the chain code.*/ 305: /*This function assumes the (0, 0) point is in the lower left*/ 306: 307: int chaincode(PGMImage *img, int x, int y, int dir, 308: struct chainCode** theChain, struct chainCode** beginning) 309: { 310: int i; /*loop counting*/ 311: int initial, next, finished; 312: 313: /* if(dir % 2) /*if dir is odd*/ 314: /* initial = (dir + 6) % 8; 315: else /*if dir is even*/ 316: /* initial = (dir + 7) % 8;*/ 317: 318: initial = (dir + 5) % 8; /*better initail choice?*/ 319: 320: next = initial; /*set the next direction to search*/ 321: printf("next: %d x: %d y: %d\n", next, x, y); 322: for(i = 0; i < 8; i++) 323: { 324: if(next == EAST) 325: { 326: if(checkThings(&dir, EAST, x, y, x + 1, y, theChain, img, beginning)) 327: finished = chaincode(img, x + 1, y, dir, theChain, beginning); 328: } 329: else if(next == NORTHEAST) 330: { 331: 332: if(checkThings(&dir, NORTHEAST, x, y, x + 1, y + 1, theChain, img, 333: beginning)) 334: finished = chaincode(img, x + 1, y + 1, dir, theChain, beginning); 335: } 336: else if(next == NORTH) 337: { 338: if(checkThings(&dir, NORTH, x, y, x, y + 1, theChain, img, 339: beginning)) 340: finished = chaincode(img, x, y + 1, dir, theChain, beginning); 341: } 342: else if(next == NORTHWEST) 343: { 344: if(checkThings(&dir, NORTHWEST, x, y, x - 1, y + 1, theChain, img, 345: beginning)) 346: finished = chaincode(img, x - 1, y + 1, dir, theChain, beginning); 347: } 348: else if(next == WEST) 349: { 350: if(checkThings(&dir, WEST, x, y, x - 1, y, theChain, img, beginning)) 351: finished = chaincode(img, x - 1, y, dir, theChain, beginning); 352: } 353: else if(next == SOUTHWEST) 354: { 355: if(checkThings(&dir, SOUTHWEST, x, y, x - 1, y - 1, theChain, img, 356: beginning)) 357: finished = chaincode(img, x - 1, y - 1, dir, theChain, beginning); 358: } 359: else if(next == SOUTH) 360: { 361: if(checkThings(&dir, SOUTH, x, y, x, y - 1, theChain, img,beginning)) 362: finished = chaincode(img, x, y - 1, dir, theChain, beginning); 363: } 364: else if(next == SOUTHEAST) 365: { 366: if(checkThings(&dir, SOUTHEAST, x, y, x + 1, y - 1, theChain, img, 367: beginning)) 368: finished = chaincode(img, x + 1, y - 1, dir, theChain, beginning); 369: } 370: 371: /*if the next chaincode function in the recursion or the current state 372: is the final state of the the chain code; recursively returns DONE 373: back through all the levels to stop the chain code.*/ 374: if(dir == NONE || finished == NONE) 375: return NONE; 376: 377: /*set next for next iteration*/ 378: next = (next + 1) % 8; 379: } 380: 381: } 382: 383: /*returns true if the point is already in one of the chains, false otherwise*/ 384: int alreadyFound(int initThreashFlag, int i, int j, PGMImage* img, 385: struct chainCode** found, int count) 386: { 387: int k; 388: struct chainCode* temp; 389: /*this if statement determines if a pixel is not the background*/ 390: if(initThreashFlag < rgb_avg((*img).data[j][i])) /*collumn major*/ 391: { 392: /*Now search to determine if the pixel has been found already*/ 393: for(k = 0; k < = count; k++) 394: { 395: temp = (found[k]); 396: while(temp) 397: {/* if point has already been found*/ 398: if((temp- >location.x == i) && (temp- >location.y == j)) 399: { 400: j = 0; /*does this work?*/ 401: return TRUE; 402: break; 403: } 404: temp = temp- >next; 405: } 406: } 407: } 408: return FALSE; 409: } 410: 411: /*saves a chain code to file. Was usefull during debuging now is just 412: a cool thing to leave in*/ 413: /*1st: pointer to beginning of a chaincode 414: 2nd: the index of the chain code for destiqushing the 'chain' files*/ 415: void saveChainCode(chainCode* saveChain, int count) 416: { 417: struct chainCode* temp = saveChain; 418: char filename[12]; 419: FILE* outfile; 420: sprintf(filename, "chain%d", count); 421: outfile = fopen(filename, "w"); /*output file for chaincode*/ 422: printf("Writing chain code to file %s.\n", filename); 423: 424: while(temp) 425: { 426: 427: fprintf(outfile, "%d %d %d\n",temp- >location.x,temp- >location.y, 428: temp- >code); 429: temp = temp- >next; 430: } 431: fclose(outfile); 432: } 433: 434: chainCode** showChain(PGMImage *original) 435: { 436: int i, j; /*loop counting*/ 437: int count = 0; /*array index holder*/ 438: int initThreashFlag = 128, foundFlag = TRUE; 439: RGB_INT /*chainColor = {255, 0, 255},*/ tempColor = {255, 0, 0}; 440: struct chainCode** beginning, *chain = NULL, *temp, *next_tmep, *temp_loop; 441: beginning = (chainCode**) 442: malloc(MAX_CHAINS * sizeof(chainCode*)); 443: 444: /*Need a temporary threasholded image*/ 445: /*PGMImage *threashed = (PGMImage*) malloc(sizeof(PGMImage)); 446: */ 447: glPointSize(4); /*make points more visible*/ 448: 449: /*showThreashold(original, threashed);*/ 450: 451: /*Use starting pixel as defualt. This is partially based on the fact that 452: most likely a corner will be background and not an object.*/ 453: /*the image assumes that (0, 0) is in the bottom left, I assume that 454: (0, 0) is in the upper left. This is handled here.*/ 455: /*initThreashFlag = (*threashed).data[(*threashed).height - 1][0];*/ 456: 457: for(i = 0; i < 10; i++) beginning[i] = NULL;/*initailize pointer array.*/ 458: 459: /*search image until a pixel is found with threasholded value of the 460: object. i & j will then contain the starting coordinate.*/ 461: for(i = 0; i < (*original).width; i++) /*x direction*/ 462: { 463: for(j = (*original).height - 1; j >= 0; j--) /*y direction*/ 464: { 465: /*skip to the next iteration if pixel isn't "good" enough*/ 466: if(rgb_avg((*original).data[j][i]) < initThreashFlag) 467: { 468: continue; 469: } 470: /*skip to the next iteration, which will be at the top of the next 471: collumn*/ 472: else if(alreadyFound(initThreashFlag, i, j, original, beginning, 473: count)) 474: { 475: j = 0; /*reseting to make this the last iteration without reseting 476: search to the top of next collumn*/ 477: continue; 478: } 479: else 480: { 481: /*printf("chaincode: %d\n", count);*/ 482: /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/ 483: chain = NULL; /*reset this to seperate the chaincodes*/ 484: 485: chainColor.blue = (128 + 10 * count) * (count % 2); 486: chainColor.green =(128 + 10 * count) * (count % 3); 487: chainColor.red =(128 + 10 * count); 488: /*find the chaincode for the current starting pixel*/ 489: chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]); 490: 491: if(beginning[count] != NULL) /*avoid writing zero length chains*/ 492: { 493: saveChainCode(beginning[count], count); 494: count++; /*advance the beginning counter*/ 495: } 496: 497: /*force end of loops, leaving code when finished looping 498: to still execute*/ 499: if(count >= MAX_CHAINS) 500: i = (*original).width; 501: 502: j = 0; /*reset search to start at top on next pass. This the 503: setting for stopping condition for the current j loop.*/ 504: break; /*Quick fix?*/ 505: } 506: } 507: } 508: printf("Done finding chain code(s). %d were found.\n", count); 509: return beginning; 510: } 511: 512: 513: /**********************File I/O functions*******************************/ 514: /***********************************************************************/ 515: 516: /*Gets an ascii color pgm image file (type P3).*/ 517: void getPGMfile (char filename[], PGMImage *img) 518: { 519: FILE *in_file; 520: char ch; 521: int row, col; 522: 523: in_file = fopen(filename, "r"); 524: if (in_file == NULL) 525: { 526: fprintf(stderr, "Error: Unable to open file %s\n\n", filename); 527: exit(8); 528: } 529: 530: printf("\nReading image file: %s", filename); 531: 532: do /* skip header identifier */ 533: ch = getc(in_file); 534: while (ch != '\n'); 535: 536: do /* skip comments lines */ 537: { 538: while (ch != '\n') ch = getc(in_file); /* flush to end of line */ 539: ch = getc(in_file); 540: } while (ch == '#'); 541: 542: fseek(in_file, -1, SEEK_CUR); /* backup one character */ 543: 544: fscanf(in_file,"%d", &((*img).width)); 545: fscanf(in_file,"%d", &((*img).height)); 546: fscanf(in_file,"%d", &((*img).maxVal)); 547: 548: printf("\n width = %d",(*img).width); 549: printf("\n height = %d",(*img).height); 550: printf("\n maxVal = %d",(*img).maxVal); 551: printf("\n"); 552: 553: if (((*img).width > MAX) || ((*img).height > MAX)) 554: { 555: printf("\n\n***ERROR - image too big for current image structure***\n\n"); 556: exit(0); 557: } 558: 559: for (row=(*img).height-1; row >=0; row--) 560: for (col=0; col< (*img).width; col++) 561: { 562: fscanf(in_file,"%d", &((*img).data[row][col].red) ); 563: fscanf(in_file,"%d", &((*img).data[row][col].green)); 564: fscanf(in_file,"%d", &((*img).data[row][col].blue)); 565: } 566: fclose(in_file); 567: printf("\nDone reading file.\n"); 568: } 569: 570: 571: void save(PGMImage *img) 572: { 573: int i, j, nr, nc, k; 574: int red, green, blue; 575: FILE *iop; 576: 577: nr = img- >height; 578: nc = img- >width; 579: 580: iop = fopen("image1.pgm", "w"); 581: fprintf(iop, "P3\n"); 582: fprintf(iop, "%d %d\n", nc, nr); 583: fprintf(iop, "255\n"); 584: 585: k = 1; 586: for(i = nr - 1; i >= 0; i--) 587: { 588: for(j = 0; j < nc; j++) 589: { 590: red = img- >data[i][j].red; 591: green = img- >data[i][j].green; 592: blue = img- >data[i][j].blue; 593: if(red < 0) 594: { 595: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j); 596: printf(" Setting red to zero\n"); 597: red = 0; 598: } 599: if(green < 0) 600: { 601: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j); 602: printf(" Setting green to zero\n"); 603: green = 0; 604: } 605: if(blue < 0) 606: { 607: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j); 608: printf(" Setting green to zero\n"); 609: blue = 0; 610: } 611: if(red > 255) 612: { 613: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j); 614: printf(" Setting red to 255\n"); 615: red = 255; 616: } 617: if(green > 255) 618: { 619: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j); 620: printf(" Setting green to 255\n"); 621: green = 255; 622: } 623: if(blue > 255) 624: { 625: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j); 626: printf(" Setting blue to 255\n"); 627: blue = 255; 628: } 629: 630: if(k % 10) 631: { 632: fprintf(iop, "%d ", red); 633: fprintf(iop, "%d ", green); 634: fprintf(iop, "%d ", blue); 635: } 636: else /*for newline*/ 637: { 638: fprintf(iop, "%d\n", red); 639: fprintf(iop, "%d\n", green); 640: fprintf(iop, "%d\n", blue); 641: } 642: k++; 643: } 644: } 645: fprintf(iop, "\n"); 646: fclose(iop); 647: } 648: 649: 650: 651: 652: /****Calculation & drawing functions of the image translations********** 653: ***********************************************************************/ 654: 655: 656: void showColor (PGMImage *img) 657: { 658: int row, col; /*y, x*/ 659: /*for (row=(*img).height-1; row >=0; row--) 660: for (col=0; col< (*img).width; col++) 661: { 662: 663: setCPixel(col, row, (*img).data[row][col]); 664: }*/ 665: 666: int i, j; /*loop counting: i = x, j = y*/ 667: int mid_width = ((*img).width / 2); 668: int mid_height = ((*img).height / 2); 669: 670: for(i = 0; i < mid_width / 2; i++) 671: { 672: for(j = 0; j < mid_height; j++) 673: { 674: /*inorder they are: 675: bottom left, bottom middle right, top left, top m right, 676: bottom middle left, bottom right, top middle left, top right.*/ 677: 678: setCPixel(i, j, (*img).data[j][i]); 679: setCPixel(i + mid_width, j, (*img).data[j][i + mid_width]); 680: setCPixel(i, j + mid_height, (*img).data[j + mid_height][i]); 681: setCPixel(i + mid_width, j + mid_height, 682: (*img).data[j + mid_height][i + mid_width]); 683: 684: setCPixel(mid_width - i - 1, j, 685: (*img).data[j][mid_width - i - 1]); 686: setCPixel((*img).width - i - 1, j, 687: (*img).data[j][(*img).width - i - 1]); 688: setCPixel(mid_width - i - 1, (*img).height - j - 1, 689: (*img).data[(*img).height - j - 1][mid_width - i - 1]); 690: setCPixel((*img).width - i - 1, (*img).height - j - 1, 691: (*img).data[(*img).height - j - 1][(*img).width - i - 1]); 692: } 693: } 694: glFlush(); 695: } 696: 697: void camera_correction(PGMImage* new_img, PGMImage* org_img) 698: { 699: int row, col, img_row, img_col; /*loop counting*/ 700: 701: /*camera parameters*/ 702: float height = 30; /*height of camera in cm*/ 703: float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/ 704: float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/ 705: 706: /*temporary varaibles*/ 707: float angular_height_corr; 708: float angular_side_corr; 709: int x_coord, y_coord; 710: 711: memset(new_img, 0, sizeof(PGMImage)); 712: (*new_img).height = (*org_img).height; 713: (*new_img).width = (*org_img).width; 714: (*new_img).maxVal = (*org_img).maxVal; 715: 716: for (row=(*org_img).height-1; row >=0; row--) 717: for (col=0; col< (*org_img).width; col++) 718: { 719: /*img_row -= (*org_img).height / 2; 720: img_col = col - (*org_img).width / 2;*/ 721: 722: angular_height_corr = 723: (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1)); 724: angular_side_corr = 725: (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1)); 726: 727: angular_height_corr /= 2; 728: /*angular_side_corr /= 2;*/ 729: /*height *= 2;*/ 730: height = 150; 731: 732: x_coord = (int) 733: (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr)); 734: y_coord = (int) 735: (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr)); 736: 737: /*x_coord += (*org_img).width / 2;*/ 738: y_coord += (*org_img).height / 2; 739: 740: /*printf("org: (%d, %d) new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/ 741: 742: pxlcpy(new_img, y_coord, x_coord, org_img, row, col); 743: } 744: } 745: 746: void new_corr(PGMImage* new_img, PGMImage* org_img) 747: { 748: /*i and j are the left half, k and l are the right half*/ 749: float i, k; /*loop counting*/ 750: int j, l, row; /*loop counting*/ 751: int old_i, old_k; 752: 753: float ins_s = 2; /*insert constant starting value*/ 754: float ins_k = ins_s; /*insert constant*/ 755: 756: /*The halfway marks in the width.*/ 757: int mid_width_left = ((*new_img).width / 2) - 1; 758: int mid_width_right = ((*new_img).width / 2); 759: 760: /*just to be thourough clear the memory and reset maxes*/ 761: memset(new_img, 0, sizeof(PGMImage)); 762: (*new_img).height = (*org_img).height; 763: (*new_img).width = (*org_img).width; 764: (*new_img).maxVal = (*org_img).maxVal; 765: 766: /*Loop through each row from top to bottom...*/ 767: for(row = ((*new_img).height - 1); row >= 0; row--) 768: { 769: /*...reset moire interference removal counter...*/ 770: old_i = ((*new_img).width / 2) - 1; 771: old_k = ((*new_img).width / 2); 772: 773: /*...so each half is ajusted to remove perspective effect...*/ 774: for(i = j = mid_width_left, k = l = mid_width_right 775: ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width 776: ; i -= ins_k, j--, k += ins_k, l++) 777: { 778: for(;old_i >= (int)i; old_i--) /*...in the left half...*/ 779: pxlcpy(new_img, row, old_i, org_img, row, j); 780: for(;old_k < = (int)k; old_k++) /*...in the right half.*/ 781: pxlcpy(new_img, row, old_k, org_img, row, l); 782: } 783: /*Move the new image x_coord pixel counter to next new image pixel*/ 784: ins_k -= ((ins_s - 1.0) / (*new_img).height); 785: } 786: } 787: 788: void color_to_gray(PGMImage* new_img, PGMImage* org_img) 789: { 790: int row, col; /*loop counting*/ 791: RGB_INT cur_pxl; /*current pixel*/ 792: 793: (*new_img).height = (*org_img).height; 794: (*new_img).width = (*org_img).width; 795: (*new_img).maxVal = (*org_img).maxVal; 796: 797: /*Starting with the top row...*/ 798: for(row = (*new_img).height - 1; row >= 0; row--) 799: for(col = 0; col < (*new_img).width - 1; col++) 800: { 801: cur_pxl = (*org_img).data[row][col]; /*more readable*/ 802: 803: /*convert each RGB to the average of the original*/ 804: (*new_img).data[row][col].red = rgb_avg(cur_pxl); 805: (*new_img).data[row][col].green = rgb_avg(cur_pxl); 806: (*new_img).data[row][col].blue = rgb_avg(cur_pxl); 807: } 808: } 809: 810: void moravec(PGMImage* new_img, PGMImage* org_img) 811: { 812: int row, col; /*loop counting*/ 813: int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/ 814: int running_sum; 815: float K = .5; /*.125 according to org. formula, but .5 is brighter*/ 816: int max_val = 0, row_max, col_max; /* max porportion value in image*/ 817: 818: memset(new_img, 0, sizeof(PGMImage)); 819: (*new_img).height = (*org_img).height; 820: (*new_img).width = (*org_img).width; 821: (*new_img).maxVal = (*org_img).maxVal; 822: 823: /*starting at the top row*/ 824: for(row = (*new_img).height - 1 - 1; row > 0; row--) 825: for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/ 826: { 827: i = row; 828: j = col; 829: running_sum = 0; 830: 831: /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/ 832: for(k = i - 1; k < = i + 1; k++) /*row*/ 833: for(l = j - 1; l < = j + 1; l++) /*column*/ 834: running_sum += abs(rgb_avg((*org_img).data[k][l]) - 835: rgb_avg((*org_img).data[i][j])); 836: 837: /*assign the new pixel value*/ 838: (*new_img).data[row][col].red = (int)(K * running_sum); 839: (*new_img).data[row][col].green = (int)(K * running_sum); 840: (*new_img).data[row][col].blue = (int)(K * running_sum); 841: } 842: } 843: 844: void detect_corners(PGMImage* org_img) 845: { 846: struct chainCode **chain_codes; 847: 848: chain_codes = showChain(org_img); 849: } 850: 851: /* ================================================================= 852: * Callback functions. 853: * 854: * color = displayed graphics in window 855: * menu = menu event handling 856: * keyboard = deyboard event handling 857: * ----------------------------------------------------------------- */ 858: void color(void) 859: { 860: /*glClear (GL_COLOR_BUFFER_BIT);*/ 861: 862: /* printf("\nDrawing Original image...\n");*/ 863: showColor(img_cur); 864: 865: /*glFlush();*/ 866: } 867: 868: #define RESTART 0 869: #define CAMERA_CORRECTION 1 870: #define X2_C_CORR 2 871: #define NEW_CORR 3 872: #define COLOR_TO_GRAY 4 873: #define MORAVEC 5 874: #define CORNERS 6 875: 876: void menu(int selection) 877: { 878: if(selection == RESTART) 879: { 880: memcpy(img1, img0, sizeof(PGMImage)); 881: img_cur = img0; 882: } 883: if(selection == CAMERA_CORRECTION) 884: { 885: printf("Starting camera correction\n"); 886: camera_correction(img1, img0); 887: img_cur = img1; 888: } 889: if(selection == X2_C_CORR) 890: { 891: printf("Starting camera correction\n"); 892: camera_correction(img1, img0); 893: camera_correction(img2, img1); 894: img_cur = img2; 895: } 896: if(selection == NEW_CORR) 897: { 898: new_corr(img1, img0); 899: img_cur = img1; 900: } 901: if(selection == COLOR_TO_GRAY) 902: { 903: color_to_gray(img1, img0); 904: img_cur = img1; 905: } 906: if(selection == MORAVEC) 907: { 908: moravec(img1, img0); 909: img_cur = img1; 910: } 911: if(selection == CORNERS) 912: { 913: /*new_corr(img1, img0);*/ 914: /*moravec(img2, img1);*/ 915: showColor(img0); 916: detect_corners(img0); 917: img_cur = img0; 918: return; 919: } 920: /*glClear (GL_COLOR_BUFFER_BIT);*/ 921: showColor(img_cur); 922: glutPostRedisplay(); 923: } 924: 925: void keyboard(unsigned char key, int x, int y) 926: { 927: switch (key) 928: { 929: case 27: 930: exit(0); 931: break; 932: } 933: } 934: 935: void mouse(int button, int state, int x, int y) 936: { 937: char temp[50]; 938: RGB_INT erase = {0, 0, 0}; 939: 940: if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 941: { 942: sprintf(temp, "(x, y): (%d, %d) red: %d green: %d blue: %d\n", 943: x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red, 944: (*img_cur).data[VSIZE - y][x].green, 945: (*img_cur).data[VSIZE - y][x].blue); 946: setCRect(0, 0, 200, 12, erase); 947: glColor3f(1.0, 0.0, 0.0); 948: drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp); 949: glFlush(); 950: } 951: } 952: 953: /* ================================================================= 954: * init - initializes graphics viewport 955: * 956: * You should not have to change this function for the first few 957: * projects we have. It will become more important when we move to 958: * 3D graphics. 959: * ----------------------------------------------------------------- */ 960: void init (void) 961: { 962: 963: /* 964: * select clearing color - white 965: */ 966: glClearColor (1.0, 1.0, 1.0, 0.0); 967: 968: /* 969: * initialize viewport values 970: */ 971: glMatrixMode(GL_PROJECTION); 972: glLoadIdentity(); 973: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 974: 975: /*add menus*/ 976: glutCreateMenu(menu); 977: glutAddMenuEntry("Restart", RESTART); 978: glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION); 979: glutAddMenuEntry("2x C. Corr.", X2_C_CORR); 980: glutAddMenuEntry("new corr", NEW_CORR); 981: glutAddMenuEntry("color to gray", COLOR_TO_GRAY); 982: glutAddMenuEntry("moravec", MORAVEC); 983: glutAddMenuEntry("corners", CORNERS); 984: glutAttachMenu(GLUT_RIGHT_BUTTON); 985: } 986: 987: int main(int argc, char** argv) 988: { 989: char PGMfileName[MAX_FILE_LENGTH]; 990: 991: int WindowID; 992: 993: int i; /*looping variable*/ 994: 995: /*parse the command line*/ 996: if(argc == 1) 997: { 998: printf("To few parameters.\n"); 999: printf("Usage: research < file.pgm >\n"); 1000: exit(1); 1001: } 1002: else if(argc == 2) 1003: strcpy(PGMfileName, argv[1]); 1004: else 1005: { 1006: printf("To many parameters.\n"); 1007: printf("Usage: research < file.pgm >\n"); 1008: exit(1); 1009: } 1010: /* 1011: * Read in image file. - note: sets our global values, too. 1012: * ----------------------------------------------------------------- */ 1013: 1014: img0 = (PGMImage*) malloc(sizeof(PGMImage)); 1015: getPGMfile(PGMfileName, img0); 1016: HSIZE = (*img0).width; 1017: VSIZE = (*img0).height; 1018: MVAL = (*img0).maxVal; 1019: 1020: img_cur = img0; /*VERY IMPORTANT to set this*/ 1021: 1022: /*allocate memory for second image*/ 1023: img1 = (PGMImage*) malloc(sizeof(PGMImage)); 1024: memcpy(img1, img0, sizeof(PGMImage)); 1025: /*(*img1).width = HSIZE; 1026: (*img1).height = VSIZE; 1027: (*img1).maxVal = 255;*/ 1028: 1029: img2 = (PGMImage*) malloc(sizeof(PGMImage)); 1030: memcpy(img2, img0, sizeof(PGMImage)); 1031: 1032: /* 1033: * Initialize the glut package. 1034: * ----------------------------------------------------------------- */ 1035: glutInit(&argc, argv); 1036: glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 1037: /* 1038: * Define a new window (its size, position and title). 1039: * ----------------------------------------------------------------- */ 1040: glutInitWindowSize (HSIZE, VSIZE); /*size*/ 1041: glutInitWindowPosition (10, 10); /*position*/ 1042: WindowID = glutCreateWindow (PGMfileName); /*title*/ 1043: glutSetWindow(WindowID); 1044: glutDisplayFunc(color); 1045: 1046: /* 1047: * Call our init function to define viewing parameters. 1048: * ----------------------------------------------------------------- */ 1049: init (); 1050: 1051: glutMouseFunc(mouse); 1052: glutKeyboardFunc(keyboard); 1053: glutMainLoop(); 1054: 1055: /* 1056: * When we reach here, we've left the event loop and are ready to 1057: * exit. 1058: * ----------------------------------------------------------------- */ 1059: return 0; 1060: } 1061: 1062: 1063: 1064: 1065: 1066: 1067: 1068: 1069: 1070: 1071: 1072: 1073: