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