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