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: if(rgb_avg((*img).data[y_check][x_check]) > img_pxl_avg(img)) 271: { 272: setCPixel(x_check, y_check, chainColor); 273: glFlush(); 274: *dir = next; 275: temp = (chain_t)malloc(sizeof(struct chainCode)); 276: temp->next = NULL; 277: temp->code = *dir; 278: temp->location.x = x_check; 279: temp->location.y = y_check; 280: temp->prev = *theChain; 281: if(*theChain) 282: (*theChain)->next = temp; /*now this is a good thing to set.*/ 283: *theChain = temp; /*advance one*/ 284: 285: if(*beginning == NULL) 286: *beginning = *theChain;/*set this for the first node in the list once*/ 287: return TRUE; 288: } 289: return FALSE; 290: } 291: 292: /*determines the chain code for a starting pixel*/ 293: /*this chain code uses 8 connectivity*/ 294: /*Note: There are many different coordinate systems at work in this function.*/ 295: /*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 296: /* top left is (0, 0). If it looks strange, look harder!!!*/ 297: /*Preconditions: 298: 1st parameter: pointer to the pgm image being used. 299: 2nd parameter: integer value containing the current x coordinate. 300: 3rd parameter: integer value containing the current y coordinate. 301: 4th parameter: integer value containing the current direction code. 302: 5th parameter: pointer to the linked list of the chain code. 303: 6th parameter: pointer to the linked list of the chain code.*/ 304: /*This function assumes the (0, 0) point is in the lower left*/ 305: 306: int chaincode(PGMImage *img, int x, int y, int dir, 307: struct chainCode** theChain, struct chainCode** beginning) 308: { 309: int i; /*loop counting*/ 310: int initial, next, finished; 311: 312: /* if(dir % 2) /*if dir is odd*/ 313: /* initial = (dir + 6) % 8; 314: else /*if dir is even*/ 315: /* initial = (dir + 7) % 8;*/ 316: 317: initial = (dir + 5) % 8; /*better initail choice?*/ 318: 319: next = initial; /*set the next direction to search*/ 320: /*printf("next: %d x: %d y: %d\n", next, x, y); */ 321: for(i = 0; i < 8; i++) 322: { 323: if(next == EAST) 324: { 325: if(checkThings(&dir, EAST, x, y, x + 1, y, theChain, img, beginning)) 326: finished = chaincode(img, x + 1, y, dir, theChain, beginning); 327: } 328: else if(next == NORTHEAST) 329: { 330: 331: if(checkThings(&dir, NORTHEAST, x, y, x + 1, y + 1, theChain, img, 332: beginning)) 333: finished = chaincode(img, x + 1, y + 1, dir, theChain, beginning); 334: } 335: else if(next == NORTH) 336: { 337: if(checkThings(&dir, NORTH, x, y, x, y + 1, theChain, img, 338: beginning)) 339: finished = chaincode(img, x, y + 1, dir, theChain, beginning); 340: } 341: else if(next == NORTHWEST) 342: { 343: if(checkThings(&dir, NORTHWEST, x, y, x - 1, y + 1, theChain, img, 344: beginning)) 345: finished = chaincode(img, x - 1, y + 1, dir, theChain, beginning); 346: } 347: else if(next == WEST) 348: { 349: if(checkThings(&dir, WEST, x, y, x - 1, y, theChain, img, beginning)) 350: finished = chaincode(img, x - 1, y, dir, theChain, beginning); 351: } 352: else if(next == SOUTHWEST) 353: { 354: if(checkThings(&dir, SOUTHWEST, x, y, x - 1, y - 1, theChain, img, 355: beginning)) 356: finished = chaincode(img, x - 1, y - 1, dir, theChain, beginning); 357: } 358: else if(next == SOUTH) 359: { 360: if(checkThings(&dir, SOUTH, x, y, x, y - 1, theChain, img,beginning)) 361: finished = chaincode(img, x, y - 1, dir, theChain, beginning); 362: } 363: else if(next == SOUTHEAST) 364: { 365: if(checkThings(&dir, SOUTHEAST, x, y, x + 1, y - 1, theChain, img, 366: beginning)) 367: finished = chaincode(img, x + 1, y - 1, dir, theChain, beginning); 368: } 369: 370: /*if the next chaincode function in the recursion or the current state 371: is the final state of the the chain code; recursively returns DONE 372: back through all the levels to stop the chain code.*/ 373: if(dir == NONE || finished == NONE) 374: return NONE; 375: 376: /*set next for next iteration*/ 377: next = (next + 1) % 8; 378: } 379: 380: } 381: 382: /*returns true if the point is already in one of the chains, false otherwise*/ 383: int alreadyFound(int initThreashFlag, int i, int j, PGMImage* img, 384: struct chainCode** found, int count) 385: { 386: int k; 387: struct chainCode* temp; 388: /*this if statement determines if a pixel is not the background*/ 389: if(initThreashFlag < rgb_avg((*img).data[j][i])) /*collumn major*/ 390: { 391: /*Now search to determine if the pixel has been found already*/ 392: for(k = 0; k <= count; k++) 393: { 394: temp = (found[k]); 395: while(temp) 396: {/* if point has already been found*/ 397: if((temp->location.x == i) && (temp->location.y == j)) 398: { 399: j = 0; /*does this work?*/ 400: return TRUE; 401: break; 402: } 403: temp = temp->next; 404: } 405: } 406: } 407: return FALSE; 408: } 409: 410: /*saves a chain code to file. Was usefull during debuging now is just 411: a cool thing to leave in*/ 412: /*1st: pointer to beginning of a chaincode 413: 2nd: the index of the chain code for destiqushing the 'chain' files*/ 414: void saveChainCode(chainCode* saveChain, int count) 415: { 416: struct chainCode* temp = saveChain; 417: char filename[12]; 418: FILE* outfile; 419: sprintf(filename, "chain%d", count); 420: outfile = fopen(filename, "w"); /*output file for chaincode*/ 421: printf("Writing chain code to file %s.\n", filename); 422: 423: while(temp) 424: { 425: 426: fprintf(outfile, "%d %d %d\n",temp->location.x,temp->location.y, 427: temp->code); 428: temp = temp->next; 429: } 430: fclose(outfile); 431: } 432: 433: chainCode** showChain(PGMImage *original) 434: { 435: int i, j; /*loop counting*/ 436: int count = 0; /*array index holder*/ 437: int initThreashFlag = img_pxl_avg(original), foundFlag = TRUE; 438: RGB_INT /*chainColor = {255, 0, 255},*/ tempColor = {255, 0, 0}; 439: struct chainCode** beginning, *chain = NULL, *temp, *next_tmep, *temp_loop; 440: beginning = (chainCode**) 441: malloc(MAX_CHAINS * sizeof(chainCode*)); 442: 443: /*Need a temporary threasholded image*/ 444: /*PGMImage *threashed = (PGMImage*) malloc(sizeof(PGMImage)); 445: */ 446: glPointSize(4); /*make points more visible*/ 447: 448: /*showThreashold(original, threashed);*/ 449: 450: /*Use starting pixel as defualt. This is partially based on the fact that 451: most likely a corner will be background and not an object.*/ 452: /*the image assumes that (0, 0) is in the bottom left, I assume that 453: (0, 0) is in the upper left. This is handled here.*/ 454: /*initThreashFlag = (*threashed).data[(*threashed).height - 1][0];*/ 455: 456: for(i = 0; i < 10; i++) beginning[i] = NULL;/*initailize pointer array.*/ 457: 458: /*search image until a pixel is found with threasholded value of the 459: object. i & j will then contain the starting coordinate.*/ 460: for(i = 0; i < (*original).width; i++) /*x direction*/ 461: { 462: for(j = (*original).height - 1; j >= 0; j--) /*y direction*/ 463: { 464: /*skip to the next iteration if pixel isn't "good" enough*/ 465: if(rgb_avg((*original).data[j][i]) < initThreashFlag) 466: { 467: continue; 468: } 469: /*skip to the next iteration, which will be at the top of the next 470: collumn*/ 471: else if(alreadyFound(initThreashFlag, i, j, original, beginning, 472: count)) 473: { 474: j = 0; /*reseting to make this the last iteration without reseting 475: search to the top of next collumn*/ 476: continue; 477: } 478: else 479: { 480: /*printf("chaincode: %d\n", count);*/ 481: /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/ 482: chain = NULL; /*reset this to seperate the chaincodes*/ 483: 484: chainColor.blue = (128 + 10 * count) * (count % 2); 485: chainColor.green =(128 + 10 * count) * (count % 3); 486: chainColor.red =(128 + 10 * count); 487: /*find the chaincode for the current starting pixel*/ 488: chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]); 489: 490: if(beginning[count] != NULL) /*avoid writing zero length chains*/ 491: { 492: saveChainCode(beginning[count], count); 493: count++; /*advance the beginning counter*/ 494: } 495: 496: /*force end of loops, leaving code when finished looping 497: to still execute*/ 498: if(count >= MAX_CHAINS) 499: i = (*original).width; 500: 501: j = 0; /*reset search to start at top on next pass. This the 502: setting for stopping condition for the current j loop.*/ 503: break; /*Quick fix?*/ 504: } 505: } 506: } 507: printf("Done finding chain code(s). %d were found.\n", count); 508: return beginning; 509: } 510: 511: /**********************Support functions*******************************/ 512: /***********************************************************************/ 513: 514: /*Returns average (with RGB avg) pixel value for the image passed in.*/ 515: int img_pxl_avg(PGMImage* img) 516: { 517: int i, j; /*loop counting*/ 518: int sum = 0; 519: 520: for(i = 0; i < (*img).height; i++) 521: for(j = 0; j < (*img).height; j++) 522: sum += rgb_avg((*img).data[i][j]); 523: 524: return (sum / ((*img).height * (*img).height)); 525: } 526: 527: 528: /**********************File I/O functions*******************************/ 529: /***********************************************************************/ 530: 531: /*Gets an ascii color pgm image file (type P3).*/ 532: void getPGMfile (char filename[], PGMImage *img) 533: { 534: FILE *in_file; 535: char ch; 536: int row, col; 537: 538: in_file = fopen(filename, "r"); 539: if (in_file == NULL) 540: { 541: fprintf(stderr, "Error: Unable to open file %s\n\n", filename); 542: exit(8); 543: } 544: 545: printf("\nReading image file: %s", filename); 546: 547: do /* skip header identifier */ 548: ch = getc(in_file); 549: while (ch != '\n'); 550: 551: do /* skip comments lines */ 552: { 553: while (ch != '\n') ch = getc(in_file); /* flush to end of line */ 554: ch = getc(in_file); 555: } while (ch == '#'); 556: 557: fseek(in_file, -1, SEEK_CUR); /* backup one character */ 558: 559: fscanf(in_file,"%d", &((*img).width)); 560: fscanf(in_file,"%d", &((*img).height)); 561: fscanf(in_file,"%d", &((*img).maxVal)); 562: 563: printf("\n width = %d",(*img).width); 564: printf("\n height = %d",(*img).height); 565: printf("\n maxVal = %d",(*img).maxVal); 566: printf("\n"); 567: 568: if (((*img).width > MAX) || ((*img).height > MAX)) 569: { 570: printf("\n\n***ERROR - image too big for current image structure***\n\n"); 571: exit(0); 572: } 573: 574: for (row=(*img).height-1; row>=0; row--) 575: for (col=0; col<(*img).width; col++) 576: { 577: fscanf(in_file,"%d", &((*img).data[row][col].red) ); 578: fscanf(in_file,"%d", &((*img).data[row][col].green)); 579: fscanf(in_file,"%d", &((*img).data[row][col].blue)); 580: } 581: fclose(in_file); 582: printf("\nDone reading file.\n"); 583: } 584: 585: 586: void save(PGMImage *img) 587: { 588: int i, j, nr, nc, k; 589: int red, green, blue; 590: FILE *iop; 591: 592: nr = img->height; 593: nc = img->width; 594: 595: iop = fopen("image1.pgm", "w"); 596: fprintf(iop, "P3\n"); 597: fprintf(iop, "%d %d\n", nc, nr); 598: fprintf(iop, "255\n"); 599: 600: k = 1; 601: for(i = nr - 1; i >= 0; i--) 602: { 603: for(j = 0; j < nc; j++) 604: { 605: red = img->data[i][j].red; 606: green = img->data[i][j].green; 607: blue = img->data[i][j].blue; 608: if(red < 0) 609: { 610: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j); 611: printf(" Setting red to zero\n"); 612: red = 0; 613: } 614: if(green < 0) 615: { 616: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j); 617: printf(" Setting green to zero\n"); 618: green = 0; 619: } 620: if(blue < 0) 621: { 622: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j); 623: printf(" Setting green to zero\n"); 624: blue = 0; 625: } 626: if(red > 255) 627: { 628: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j); 629: printf(" Setting red to 255\n"); 630: red = 255; 631: } 632: if(green > 255) 633: { 634: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j); 635: printf(" Setting green to 255\n"); 636: green = 255; 637: } 638: if(blue > 255) 639: { 640: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j); 641: printf(" Setting blue to 255\n"); 642: blue = 255; 643: } 644: 645: if(k % 10) 646: { 647: fprintf(iop, "%d ", red); 648: fprintf(iop, "%d ", green); 649: fprintf(iop, "%d ", blue); 650: } 651: else /*for newline*/ 652: { 653: fprintf(iop, "%d\n", red); 654: fprintf(iop, "%d\n", green); 655: fprintf(iop, "%d\n", blue); 656: } 657: k++; 658: } 659: } 660: fprintf(iop, "\n"); 661: fclose(iop); 662: } 663: 664: 665: 666: 667: /****Calculation & drawing functions of the image translations********** 668: ***********************************************************************/ 669: 670: 671: void showColor (PGMImage *img) 672: { 673: int row, col; /*y, x*/ 674: /*for (row=(*img).height-1; row>=0; row--) 675: for (col=0; col<(*img).width; col++) 676: { 677: 678: setCPixel(col, row, (*img).data[row][col]); 679: }*/ 680: 681: int i, j; /*loop counting: i = x, j = y*/ 682: int mid_width = ((*img).width / 2); 683: int mid_height = ((*img).height / 2); 684: 685: for(i = 0; i < mid_width / 2; i++) 686: { 687: for(j = 0; j < mid_height; j++) 688: { 689: /*inorder they are: 690: bottom left, bottom middle right, top left, top m right, 691: bottom middle left, bottom right, top middle left, top right.*/ 692: 693: setCPixel(i, j, (*img).data[j][i]); 694: setCPixel(i + mid_width, j, (*img).data[j][i + mid_width]); 695: setCPixel(i, j + mid_height, (*img).data[j + mid_height][i]); 696: setCPixel(i + mid_width, j + mid_height, 697: (*img).data[j + mid_height][i + mid_width]); 698: 699: setCPixel(mid_width - i - 1, j, 700: (*img).data[j][mid_width - i - 1]); 701: setCPixel((*img).width - i - 1, j, 702: (*img).data[j][(*img).width - i - 1]); 703: setCPixel(mid_width - i - 1, (*img).height - j - 1, 704: (*img).data[(*img).height - j - 1][mid_width - i - 1]); 705: setCPixel((*img).width - i - 1, (*img).height - j - 1, 706: (*img).data[(*img).height - j - 1][(*img).width - i - 1]); 707: } 708: } 709: glFlush(); 710: } 711: 712: void camera_correction(PGMImage* new_img, PGMImage* org_img) 713: { 714: int row, col, img_row, img_col; /*loop counting*/ 715: 716: /*camera parameters*/ 717: float height = 30; /*height of camera in cm*/ 718: float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/ 719: float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/ 720: 721: /*temporary varaibles*/ 722: float angular_height_corr; 723: float angular_side_corr; 724: int x_coord, y_coord; 725: 726: memset(new_img, 0, sizeof(PGMImage)); 727: (*new_img).height = (*org_img).height; 728: (*new_img).width = (*org_img).width; 729: (*new_img).maxVal = (*org_img).maxVal; 730: 731: for (row=(*org_img).height-1; row>=0; row--) 732: for (col=0; col<(*org_img).width; col++) 733: { 734: /*img_row -= (*org_img).height / 2; 735: img_col = col - (*org_img).width / 2;*/ 736: 737: angular_height_corr = 738: (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1)); 739: angular_side_corr = 740: (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1)); 741: 742: angular_height_corr /= 2; 743: /*angular_side_corr /= 2;*/ 744: /*height *= 2;*/ 745: height = 150; 746: 747: x_coord = (int) 748: (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr)); 749: y_coord = (int) 750: (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr)); 751: 752: /*x_coord += (*org_img).width / 2;*/ 753: y_coord += (*org_img).height / 2; 754: 755: /*printf("org: (%d, %d) new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/ 756: 757: pxlcpy(new_img, y_coord, x_coord, org_img, row, col); 758: } 759: } 760: 761: void new_corr(PGMImage* new_img, PGMImage* org_img) 762: { 763: /*i and j are the left half, k and l are the right half*/ 764: float i, k; /*loop counting*/ 765: int j, l, row; /*loop counting*/ 766: int old_i, old_k; 767: 768: float ins_s = 2; /*insert constant starting value*/ 769: float ins_k = ins_s; /*insert constant*/ 770: 771: /*The halfway marks in the width.*/ 772: int mid_width_left = ((*new_img).width / 2) - 1; 773: int mid_width_right = ((*new_img).width / 2); 774: 775: /*just to be thourough clear the memory and reset maxes*/ 776: memset(new_img, 0, sizeof(PGMImage)); 777: (*new_img).height = (*org_img).height; 778: (*new_img).width = (*org_img).width; 779: (*new_img).maxVal = (*org_img).maxVal; 780: 781: /*Loop through each row from top to bottom...*/ 782: for(row = ((*new_img).height - 1); row >= 0; row--) 783: { 784: /*...reset moire interference removal counter...*/ 785: old_i = ((*new_img).width / 2) - 1; 786: old_k = ((*new_img).width / 2); 787: 788: /*...so each half is ajusted to remove perspective effect...*/ 789: for(i = j = mid_width_left, k = l = mid_width_right 790: ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width 791: ; i -= ins_k, j--, k += ins_k, l++) 792: { 793: for(;old_i >= (int)i; old_i--) /*...in the left half...*/ 794: pxlcpy(new_img, row, old_i, org_img, row, j); 795: for(;old_k <= (int)k; old_k++) /*...in the right half.*/ 796: pxlcpy(new_img, row, old_k, org_img, row, l); 797: } 798: /*Move the new image x_coord pixel counter to next new image pixel*/ 799: ins_k -= ((ins_s - 1.0) / (*new_img).height); 800: } 801: } 802: 803: void color_to_gray(PGMImage* new_img, PGMImage* org_img) 804: { 805: int row, col; /*loop counting*/ 806: RGB_INT cur_pxl; /*current pixel*/ 807: 808: (*new_img).height = (*org_img).height; 809: (*new_img).width = (*org_img).width; 810: (*new_img).maxVal = (*org_img).maxVal; 811: 812: /*Starting with the top row...*/ 813: for(row = (*new_img).height - 1; row >= 0; row--) 814: for(col = 0; col < (*new_img).width - 1; col++) 815: { 816: cur_pxl = (*org_img).data[row][col]; /*more readable*/ 817: 818: /*convert each RGB to the average of the original*/ 819: (*new_img).data[row][col].red = rgb_avg(cur_pxl); 820: (*new_img).data[row][col].green = rgb_avg(cur_pxl); 821: (*new_img).data[row][col].blue = rgb_avg(cur_pxl); 822: } 823: } 824: 825: void moravec(PGMImage* new_img, PGMImage* org_img) 826: { 827: int row, col; /*loop counting*/ 828: int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/ 829: int running_sum; 830: float K = .5; /*.125 according to org. formula, but .5 is brighter*/ 831: int max_val = 0, row_max, col_max; /* max porportion value in image*/ 832: 833: memset(new_img, 0, sizeof(PGMImage)); 834: (*new_img).height = (*org_img).height; 835: (*new_img).width = (*org_img).width; 836: (*new_img).maxVal = (*org_img).maxVal; 837: 838: /*starting at the top row*/ 839: for(row = (*new_img).height - 1 - 1; row > 0; row--) 840: for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/ 841: { 842: i = row; 843: j = col; 844: running_sum = 0; 845: 846: /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/ 847: for(k = i - 1; k <= i + 1; k++) /*row*/ 848: for(l = j - 1; l <= j + 1; l++) /*column*/ 849: running_sum += abs(rgb_avg((*org_img).data[k][l]) - 850: rgb_avg((*org_img).data[i][j])); 851: 852: /*assign the new pixel value*/ 853: (*new_img).data[row][col].red = (int)(K * running_sum); 854: (*new_img).data[row][col].green = (int)(K * running_sum); 855: (*new_img).data[row][col].blue = (int)(K * running_sum); 856: } 857: } 858: 859: void detect_corners(PGMImage* org_img) 860: { 861: struct chainCode **chain_codes; 862: 863: chain_codes = showChain(org_img); 864: } 865: 866: /* ================================================================= 867: * Callback functions. 868: * 869: * color = displayed graphics in window 870: * menu = menu event handling 871: * keyboard = deyboard event handling 872: * ----------------------------------------------------------------- */ 873: void color(void) 874: { 875: /*glClear (GL_COLOR_BUFFER_BIT);*/ 876: 877: /* printf("\nDrawing Original image...\n");*/ 878: showColor(img_cur); 879: 880: /*glFlush();*/ 881: } 882: 883: #define RESTART 0 884: #define CAMERA_CORRECTION 1 885: #define X2_C_CORR 2 886: #define NEW_CORR 3 887: #define COLOR_TO_GRAY 4 888: #define MORAVEC 5 889: #define CORNERS 6 890: 891: void menu(int selection) 892: { 893: if(selection == RESTART) 894: { 895: memcpy(img1, img0, sizeof(PGMImage)); 896: img_cur = img0; 897: } 898: if(selection == CAMERA_CORRECTION) 899: { 900: printf("Starting camera correction\n"); 901: camera_correction(img1, img0); 902: img_cur = img1; 903: } 904: if(selection == X2_C_CORR) 905: { 906: printf("Starting camera correction\n"); 907: camera_correction(img1, img0); 908: camera_correction(img2, img1); 909: img_cur = img2; 910: } 911: if(selection == NEW_CORR) 912: { 913: new_corr(img1, img0); 914: img_cur = img1; 915: } 916: if(selection == COLOR_TO_GRAY) 917: { 918: color_to_gray(img1, img0); 919: img_cur = img1; 920: } 921: if(selection == MORAVEC) 922: { 923: moravec(img1, img0); 924: img_cur = img1; 925: } 926: if(selection == CORNERS) 927: { 928: printf("img avg: %d\n", img_pxl_avg(img0)); 929: /*new_corr(img1, img0);*/ 930: /*moravec(img2, img1);*/ 931: showColor(img0); 932: detect_corners(img0); 933: img_cur = img0; 934: return; 935: } 936: /*glClear (GL_COLOR_BUFFER_BIT);*/ 937: showColor(img_cur); 938: glutPostRedisplay(); 939: } 940: 941: void keyboard(unsigned char key, int x, int y) 942: { 943: switch (key) 944: { 945: case 27: 946: exit(0); 947: break; 948: } 949: } 950: 951: void mouse(int button, int state, int x, int y) 952: { 953: char temp[50]; 954: RGB_INT erase = {0, 0, 0}; 955: 956: if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 957: { 958: sprintf(temp, "(x, y): (%d, %d) red: %d green: %d blue: %d\n", 959: x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red, 960: (*img_cur).data[VSIZE - y][x].green, 961: (*img_cur).data[VSIZE - y][x].blue); 962: setCRect(0, 0, 200, 12, erase); 963: glColor3f(1.0, 0.0, 0.0); 964: drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp); 965: glFlush(); 966: } 967: } 968: 969: /* ================================================================= 970: * init - initializes graphics viewport 971: * 972: * You should not have to change this function for the first few 973: * projects we have. It will become more important when we move to 974: * 3D graphics. 975: * ----------------------------------------------------------------- */ 976: void init (void) 977: { 978: 979: /* 980: * select clearing color - white 981: */ 982: glClearColor (1.0, 1.0, 1.0, 0.0); 983: 984: /* 985: * initialize viewport values 986: */ 987: glMatrixMode(GL_PROJECTION); 988: glLoadIdentity(); 989: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 990: 991: /*add menus*/ 992: glutCreateMenu(menu); 993: glutAddMenuEntry("Restart", RESTART); 994: glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION); 995: glutAddMenuEntry("2x C. Corr.", X2_C_CORR); 996: glutAddMenuEntry("new corr", NEW_CORR); 997: glutAddMenuEntry("color to gray", COLOR_TO_GRAY); 998: glutAddMenuEntry("moravec", MORAVEC); 999: glutAddMenuEntry("corners", CORNERS); 1000: glutAttachMenu(GLUT_RIGHT_BUTTON); 1001: } 1002: 1003: int main(int argc, char** argv) 1004: { 1005: char PGMfileName[MAX_FILE_LENGTH]; 1006: 1007: int WindowID; 1008: 1009: int i; /*looping variable*/ 1010: 1011: /*parse the command line*/ 1012: if(argc == 1) 1013: { 1014: printf("To few parameters.\n"); 1015: printf("Usage: research <file.pgm>\n"); 1016: exit(1); 1017: } 1018: else if(argc == 2) 1019: strcpy(PGMfileName, argv[1]); 1020: else 1021: { 1022: printf("To many parameters.\n"); 1023: printf("Usage: research <file.pgm>\n"); 1024: exit(1); 1025: } 1026: /* 1027: * Read in image file. - note: sets our global values, too. 1028: * ----------------------------------------------------------------- */ 1029: 1030: img0 = (PGMImage*) malloc(sizeof(PGMImage)); 1031: getPGMfile(PGMfileName, img0); 1032: HSIZE = (*img0).width; 1033: VSIZE = (*img0).height; 1034: MVAL = (*img0).maxVal; 1035: 1036: img_cur = img0; /*VERY IMPORTANT to set this*/ 1037: 1038: /*allocate memory for second image*/ 1039: img1 = (PGMImage*) malloc(sizeof(PGMImage)); 1040: memcpy(img1, img0, sizeof(PGMImage)); 1041: /*(*img1).width = HSIZE; 1042: (*img1).height = VSIZE; 1043: (*img1).maxVal = 255;*/ 1044: 1045: img2 = (PGMImage*) malloc(sizeof(PGMImage)); 1046: memcpy(img2, img0, sizeof(PGMImage)); 1047: 1048: /* 1049: * Initialize the glut package. 1050: * ----------------------------------------------------------------- */ 1051: glutInit(&argc, argv); 1052: glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 1053: /* 1054: * Define a new window (its size, position and title). 1055: * ----------------------------------------------------------------- */ 1056: glutInitWindowSize (HSIZE, VSIZE); /*size*/ 1057: glutInitWindowPosition (10, 10); /*position*/ 1058: WindowID = glutCreateWindow (PGMfileName); /*title*/ 1059: glutSetWindow(WindowID); 1060: glutDisplayFunc(color); 1061: 1062: /* 1063: * Call our init function to define viewing parameters. 1064: * ----------------------------------------------------------------- */ 1065: init (); 1066: 1067: glutMouseFunc(mouse); 1068: glutKeyboardFunc(keyboard); 1069: glutMainLoop(); 1070: 1071: /* 1072: * When we reach here, we've left the event loop and are ready to 1073: * exit. 1074: * ----------------------------------------------------------------- */ 1075: return 0; 1076: } 1077: 1078: 1079: 1080: 1081: 1082: 1083: 1084: 1085: 1086: 1087: 1088: 1089: