1: #include <stdlib.h> 2: #include <stdio.h> 3: #include <string.h> 4: #include <math.h> 5: #include <GL/glut.h> 6: 7: #define Round(v) ((int)(v+0.5)) 8: #define MAX 800 9: #define MAX_FILE_LENGTH 256 10: 11: #define LOW_VALUE 0 12: #define HIGH_VALUE 255 13: 14: #define TRUE 1 15: #define FALSE 0 16: 17: /*cartesian coordinate type*/ 18: typedef struct {int x; 19: int y;}coord; 20: 21: /*RGB color struct with floats*/ 22: /*typedef struct {float red; 23: float green; 24: float blue; 25: }RGB; 26: */ 27: /*RGB color struct with ints*/ 28: typedef struct {int red; 29: int green; 30: int blue; 31: }RGB_INT; 32: 33: /*number of chain codes stored, */ 34: #define MAX_NUMBER_OF_CHAINS 10 35: #define MAX_CHAINS MAX_NUMBER_OF_CHAINS 36: 37: /*These constant values are the chain code directions*/ 38: #define NONE -1 39: #define EAST 0 40: #define NORTHEAST 1 41: #define NORTH 2 42: #define NORTHWEST 3 43: #define WEST 4 44: #define SOUTHWEST 5 45: #define SOUTH 6 46: #define SOUTHEAST 7 47: 48: typedef struct chainCode* chain_t; 49: typedef struct chainCode 50: { 51: chain_t prev; 52: int code; 53: coord location; /*absolute pixel location for starting point*/ 54: chain_t next; 55: }chainCode; /*This struct can be refered to by: struct chainCode or chainCode*/ 56: 57: struct PGMstructure 58: { 59: int maxVal; 60: int width; 61: int height; 62: RGB_INT data[MAX][MAX]; 63: }; 64: 65: typedef struct PGMstructure PGMImage; 66: 67: /*Evil globals, but not do-able otherwise.*/ 68: static PGMImage *img_cur; 69: static PGMImage *img0; /*original*/ 70: static PGMImage *img1; /*current*/ 71: static PGMImage *img2; /*current*/ 72: static int HSIZE; 73: static int VSIZE; 74: static int MVAL; 75: 76: const RGB_INT white = {255, 255, 255}; 77: const RGB_INT yellow = {255, 255, 0}; 78: const RGB_INT purple = {255, 0, 255}; 79: const RGB_INT cyan = {0, 255, 255}; 80: const RGB_INT red = {255, 0, 0}; 81: const RGB_INT green = {0, 255, 0}; 82: const RGB_INT blue = {0, 0, 255}; 83: const RGB_INT black = {0, 0, 0}; 84: 85: int cur_threash_val; /*for speed optimization of chain code recursion*/ 86: int back_ground; 87: 88: /*pointer to an array of pointers which point to the first nodes in each of 89: the chain codes.*/ 90: chainCode **chain_codes; 91: 92: 93: /*hold the points farthest away from each other for each object*/ 94: coord corner1[MAX_CHAINS], corner2[MAX_CHAINS]; 95: coord corner3[MAX_CHAINS], corner4[MAX_CHAINS]; 96: 97: /*use double buffered output and keep running enable idle callback to call 98: detect_corners() over and over simulating realtime response. 99: Is set to TRUE or FALSE.*/ 100: int is_buffered; 101: 102: /*used to determine if abstract lines should be drawn to the screen. 103: Set to <0 if no abstract lines are to be drawn. Otherwise 104: is set to the number of objects found (AKA number of chaincodes).*/ 105: int draw_abstract_lines; 106: 107: /*used to draw the single object most likely to be considered the 108: tic-tac-toe board. Should be <0 if this should not be drawn. 109: Should be equal to the chain-code number (from 0 to MAX_CHAINS - 1) 110: if it is to be drawn.*/ 111: int draw_abstract_board; 112: 113: 114: /**************Drawing funcitions************************************/ 115: /********************************************************************/ 116: 117: void setCPixel(int ix, int iy, RGB_INT color) 118: /*Same as setIPixel except that the last parameter is an RGB color*/ 119: { 120: float x = (ix*2.0)/HSIZE - 1.0; 121: float y = (iy*2.0)/VSIZE - 1.0; 122: 123: float red = (float)color.red/(float)MVAL; 124: float green = (float)color.green/(float)MVAL; 125: float blue = (float)color.blue/(float)MVAL; 126: 127: glColor3f(red, green, blue); 128: 129: glBegin(GL_POINTS); 130: glVertex2f (x, y); 131: glEnd(); 132: } 133: 134: void setCLines(int ix1, int iy1, int ix2, int iy2, RGB_INT color) 135: /*Similar as setIPixel except that this one draws a line between the first set 136: of points given and the second set in the RGB color specified*/ 137: { 138: float x1 = (ix1*2.0)/HSIZE - 1.0; 139: float y1 = (iy1*2.0)/VSIZE - 1.0; 140: float x2 = (ix2*2.0)/HSIZE - 1.0; 141: float y2 = (iy2*2.0)/VSIZE - 1.0; 142: 143: float red = (float)color.red/(float)MVAL; 144: float green = (float)color.green/(float)MVAL; 145: float blue = (float)color.blue/(float)MVAL; 146: 147: glColor3f(red, green, blue); 148: 149: glBegin(GL_LINES); 150: glVertex2f (x1, y1); 151: glVertex2f (x2, y2); 152: glEnd(); 153: } 154: 155: void setCRect(int ix1, int iy1, int ix2, int iy2, RGB_INT color) 156: /*Similar as setIPixel except that this one draws a line between the first set 157: of points given and the second set in the RGB color specified*/ 158: { 159: float x1 = (ix1*2.0)/HSIZE - 1.0; 160: float y1 = (iy1*2.0)/VSIZE - 1.0; 161: float x2 = (ix2*2.0)/HSIZE - 1.0; 162: float y2 = (iy2*2.0)/VSIZE - 1.0; 163: 164: float red = (float)color.red/(float)MVAL; 165: float green = (float)color.green/(float)MVAL; 166: float blue = (float)color.blue/(float)MVAL; 167: 168: glColor3f(red, green, blue); 169: 170: glBegin(GL_POLYGON); 171: glVertex2f (x1, y1); 172: glVertex2f (x1, y2); 173: glVertex2f (x2, y2); 174: glVertex2f (x2, y1); 175: glEnd(); 176: } 177: 178: void pxlcpy(PGMImage *dest, int dest_row, int dest_col, 179: PGMImage *src, int src_row, int src_col) 180: { 181: /*make sure values are within bounds*/ 182: if(dest_col > 0 && dest_col < (*dest).width 183: && dest_row > 0 && dest_row < (*dest).height 184: && src_col > 0 && src_col < (*src).width 185: && src_row > 0 && src_row < (*src).height) 186: { 187: (*dest).data[dest_row][dest_col].red = 188: (*src).data[src_row][src_col].red; 189: 190: (*dest).data[dest_row][dest_col].green = 191: (*src).data[src_row][src_col].green; 192: 193: (*dest).data[dest_row][dest_col].blue = 194: (*src).data[src_row][src_col].blue; 195: } 196: } 197: 198: 199: /**********************Support functions*******************************/ 200: /***********************************************************************/ 201: 202: int rgb_avg(RGB_INT cur_pxl) 203: { 204: /*convert each RGB to the average of the original*/ 205: return ((cur_pxl.red + cur_pxl.green + cur_pxl.blue) / 3); 206: } 207: 208: /*Returns average (with RGB avg) pixel value for the image passed in.*/ 209: int img_pxl_avg(PGMImage* img) 210: { 211: int i, j; /*loop counting*/ 212: int sum = 0; 213: 214: for(i = 0; i < (*img).height; i++)/*collumn*/ 215: for(j = 0; j < (*img).width; j++)/*row*/ 216: sum += rgb_avg((*img).data[i][j]); 217: 218: return (sum / ((*img).height * (*img).height)); 219: } 220: 221: /*1st: pixel one of type RGB_INT 222: 2nd: pixel one of type RGB_INT 223: 3rd: differnce allowed to be considered "equal" or close enough*/ 224: int pxlcmp (RGB_INT pxl1, RGB_INT pxl2, int range) 225: { 226: return ((abs((rgb_avg(pxl1) - rgb_avg(pxl2)))) < range); 227: } 228: 229: /* ================================================================= 230: * drawString - outputs a string of characters to the graphics port 231: * 232: * x, y: defines the starting location to draw the text 233: * note: this point is the lower left anchor of 234: * the first character - a character's decending 235: * portion would be drawn below this point. 236: * theFont: points to the glut font to be used 237: * theString: holds the string to be output -- up to 255 ch 238: * ----------------------------------------------------------------- */ 239: void drawString(int ix, int iy, void *theFont, char theString[256]) 240: { 241: float x = (ix*2.0)/HSIZE - 1.0; 242: float y = (iy*2.0)/VSIZE - 1.0; 243: int i; 244: glRasterPos2f(x, y); 245: for (i = 0; theString[i] != '\0'; i++) /* draw the chars one at a time */ 246: glutBitmapCharacter(theFont, theString[i]); 247: } 248: 249: /*return >0 if number of pixels is greater than img. pxl. avg., return <0 if 250: number of pixesl is less than img. pxl. avg. and return zero of equal*/ 251: int background(int treash_value, PGMImage* img) 252: { 253: int i, j; /*loop counting*/ 254: int pxl_less = 0, pxl_more = 0; 255: 256: for(i = 0; i < (*img).height; i++)/*collumn*/ 257: for(j = 0; j < (*img).width; j++)/*row*/ 258: { 259: if(rgb_avg((*img).data[i][j]) < treash_value) 260: pxl_less++; 261: 262: if(rgb_avg((*img).data[i][j]) > treash_value) 263: pxl_more++; 264: } 265: 266: if(pxl_less > pxl_more) 267: return -1; 268: else if(pxl_less < pxl_more) 269: return 1; 270: else 271: return 0; 272: } 273: 274: /******CHAIN CODE************************************************ 275: ****************************************************************/ 276: 277: int createNode(chainCode** first, chainCode** last, int new_x, int new_y, 278: int new_dir) 279: { 280: chainCode* temp; 281: 282: if(!(temp = (chain_t)malloc(sizeof(struct chainCode)))) 283: { 284: printf("error creating node\n"); 285: return FALSE; 286: } 287: 288: temp->next = NULL; 289: temp->code = new_dir; 290: temp->location.x = new_x; 291: temp->location.y = new_y; 292: temp->prev = *last; 293: if(*last) 294: (*last)->next = temp; /*now this is a good thing to set.*/ 295: *last = temp; /*advance one*/ 296: 297: if(*first == NULL) 298: *first = *last;/*set this for the first node in the list once*/ 299: 300: return TRUE; 301: } 302: 303: /*returns TRUE if the chain code loops around itself, otherwise false*/ 304: int checkCode(chainCode* first, int x_current, int y_current, 305: int x_check, int y_check, int dir) 306: { 307: struct chainCode* currentNode = first; 308: 309: while(currentNode && currentNode->next) 310: { 311: /*check two consedutive points*/ 312: if((currentNode->location.x == x_current) && 313: (currentNode->location.y == y_current) && 314: (currentNode->code == dir) && 315: (currentNode->next->location.x == x_check) && 316: (currentNode->next->location.y == y_check) && 317: (currentNode->next->next)) /*don't count the new node already*/ 318: { 319: return TRUE; /*The chain code end looped around*/ 320: } 321: else 322: currentNode = currentNode->next; 323: } 324: return FALSE; 325: } 326: 327: /* 328: Preconditions: 329: 1st parameter: integer value containing the current x coordinate. 330: 2nd parameter: integer value containing the current y coordinate. 331: 3rd parameter: pointer to the pgm image being used. 332: Postconditions: return true if pixel is deemed boarder of object, false 333: otherwise.*/ 334: int checkThings(int x_check, int y_check, PGMImage *img) 335: { 336: 337: /*check for being in bounds*/ 338: if((x_check < 0) || (y_check < 0) || (x_check >= (*img).width) || 339: (y_check >= (*img).height)) 340: return FALSE; 341: 342: /*tests if the next pixel is greater than the threashing value. This 343: value (cur_threash_val) should be set to the return value of 344: img_pxl_avg(). Also, checks if the pixel is considered in the background 345: or forground agains the value in back_ground. If so, return true to 346: indicate create new node.*/ 347: if((rgb_avg((*img).data[y_check][x_check]) > cur_threash_val) 348: && (back_ground < 0)) 349: return TRUE; 350: 351: /*same thing as above, just for things less than, rathur than greater than*/ 352: if((rgb_avg((*img).data[y_check][x_check]) < cur_threash_val) 353: && (back_ground > 0)) 354: return TRUE; 355: 356: return FALSE; 357: } 358: 359: coord neighborhood_point(int x_coord, int y_coord, int dir) 360: { 361: coord temp = {x_coord, y_coord}; 362: 363: if(dir == EAST) 364: temp.x++; 365: else if(dir == NORTHEAST) 366: { 367: temp.x++; 368: temp.y++; 369: } 370: else if(dir == NORTH) 371: temp.y++; 372: else if(dir == NORTHWEST) 373: { 374: temp.x--; 375: temp.y++; 376: } 377: else if(dir == WEST) 378: temp.x--; 379: else if(dir == SOUTHWEST) 380: { 381: temp.x--; 382: temp.y--; 383: } 384: else if(dir == SOUTH) 385: temp.y--; 386: else if(dir == SOUTHEAST) 387: { 388: temp.x++; 389: temp.y--; 390: } 391: 392: return temp; 393: } 394: 395: /*determines the chain code for a starting pixel*/ 396: /*this chain code uses 8 connectivity*/ 397: /*Note: There are many different coordinate systems at work in this function.*/ 398: /*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 399: /* top left is (0, 0). If it looks strange, look harder!!!*/ 400: /*Preconditions: 401: 1st parameter: pointer to the pgm image being used. 402: 2nd parameter: integer value containing the current x coordinate. 403: 3rd parameter: integer value containing the current y coordinate. 404: 4th parameter: integer value containing the current direction code. 405: 5th parameter: pointer to the last node of the chain code. 406: 6th parameter: pointer to the first node of the chain code.*/ 407: /*This function assumes the (0, 0) point is in the lower left*/ 408: 409: int chaincode(PGMImage *img, int x, int y, int dir, 410: struct chainCode** last, struct chainCode** first) 411: { 412: int i; /*loop counting*/ 413: int next /*next direction to check*/, finished /*finished flag*/; 414: coord next_point_to_check; /*next_point_to_check What else?*/ 415: 416: next = (dir + 5) % 8; /*better initail choice?*/ 417: 418: /*printf("next: %d x: %d y: %d\n", next, x, y);*/ 419: for(i = 0; i < 8; i++) 420: { 421: /*determine the next point to check*/ 422: next_point_to_check = neighborhood_point(x, y, next); 423: 424: if(checkThings(next_point_to_check.x, next_point_to_check.y, img)) 425: { 426: /*setCPixel(next_point_to_check.x, next_point_to_check.y, blue);*/ 427: 428: /*create the new node to go last in the chain*/ 429: createNode(first, last, next_point_to_check.x, 430: next_point_to_check.y, next); 431: 432: /*if the next chaincode function in the recursion or the current state 433: is the final state of the the chain code; recursively returns DONE 434: back through all the levels to stop the chain code.*/ 435: if(checkCode(*first, x, y, next_point_to_check.x, 436: next_point_to_check.y, dir)) 437: { 438: return NONE; 439: } 440: 441: if(NONE == chaincode(img, next_point_to_check.x, 442: next_point_to_check.y, next, last, first)) 443: return NONE; 444: } 445: 446: /*set next for next iteration*/ 447: next = (next + 1) % 8; 448: } 449: return FALSE; 450: } 451: 452: /*returns true if the point is already in one of the chains, false otherwise*/ 453: int alreadyFound(int initThreashFlag, int i, int j, chainCode** found) 454: { 455: int k; /*loop counting*/ 456: chainCode* temp; /*temporary node pointer*/ 457: 458: /*while there are codes to check...*/ 459: for(k = 0; (temp = (found[k])) && k < MAX_NUMBER_OF_CHAINS; k++) 460: { 461: while(temp) /*...check them.*/ 462: { 463: /*if point has already been found*/ 464: if((temp->location.x == i) && (temp->location.y == j)) 465: { 466: return TRUE; 467: break; 468: } 469: temp = temp->next; 470: } 471: } 472: 473: return FALSE; 474: } 475: 476: /*saves a chain code to file. Was usefull during debuging now is just 477: a cool thing to leave in*/ 478: /*1st: pointer to beginning of a chaincode 479: 2nd: the index of the chain code for destiqushing the 'chain' files*/ 480: void saveChainCode(chainCode* saveChain, int count) 481: { 482: struct chainCode* temp = saveChain; 483: char filename[12]; 484: FILE* outfile; 485: sprintf(filename, "chain%d", count); 486: outfile = fopen(filename, "w"); /*output file for chaincode*/ 487: /*printf("Writing chain code to file %s.\n", filename);*/ 488: 489: while(temp) 490: { 491: 492: fprintf(outfile, "%d %d %d\n",temp->location.x,temp->location.y, 493: temp->code); 494: temp = temp->next; 495: } 496: fclose(outfile); 497: } 498: 499: chainCode** showChain(PGMImage *original) 500: { 501: int i, j; /*loop counting*/ 502: int count = 0; /*array index holder*/ 503: int initThreashFlag = img_pxl_avg(original); 504: /*beginning points to an array of pointers. Each pointer in the array is 505: a pointer to the first node of MAX_NUMBER_OF_CHAINS number of chain 506: codes*/ 507: struct chainCode** beginning, *chain = NULL; 508: 509: /*allocate an array of pointers to chainCodes, then initalize their 510: values to NULL*/ 511: beginning = (chainCode**) 512: malloc(MAX_NUMBER_OF_CHAINS * sizeof(chainCode*)); 513: memset(beginning, 0, MAX_NUMBER_OF_CHAINS * sizeof(chainCode*)); 514: 515: cur_threash_val = initThreashFlag; /*set global variables*/ 516: back_ground = background(initThreashFlag, original); 517: 518: /*search image until a pixel is found with threasholded value of the 519: object. i & j will then contain the starting coordinate.*/ 520: for(i = 0; i < (*original).width; i++) /*x direction*/ 521: { 522: for(j = (*original).height - 1; j >= 0; j--) /*y direction*/ 523: { 524: /*skip to the next iteration if pixel isn't "good" enough*/ 525: if(!checkThings(i, j, original)) 526: continue; 527: 528: /*skip to the next iteration, which will be at the top of the next 529: collumn. This is true when the pixel has already been found in 530: one of the chain codes.*/ 531: else if(alreadyFound(initThreashFlag, i, j, beginning)) 532: break; 533: 534: else 535: { 536: /*printf("chaincode: %d\n", count);*/ 537: /*printf("The starting coordinate is (x, y): (%d, %d)\n", i, j);*/ 538: chain = NULL; /*reset this to seperate the chaincodes*/ 539: 540: /*find the chaincode for the current starting pixel*/ 541: chaincode(original, i, j, SOUTHEAST, &chain, &beginning[count]); 542: if(beginning[count] != NULL) /*avoid writing zero length chains*/ 543: { 544: saveChainCode(beginning[count], count); 545: count++; /*advance the beginning counter*/ 546: } 547: 548: /*force end of loops, leaving code when finished looping 549: to still execute*/ 550: if(count >= MAX_NUMBER_OF_CHAINS) 551: i = (*original).width; 552: 553: break; /*check the next collumn*/ 554: } 555: } 556: } 557: printf("\nDone finding chain code(s). %d were found.\n", count); 558: return beginning; 559: } 560: 561: /*frees the memory that the chain code(s) are using*/ 562: void free_chaincode(chainCode** pointer) 563: { 564: int i; /*loop counting*/ 565: chainCode* temp, *to_free; 566: 567: for(i = 0; pointer[i] && i < MAX_CHAINS; i++)/*for each chaincode*/ 568: { 569: temp = pointer[i]; 570: while(temp) /*for each node*/ 571: { 572: to_free = temp; 573: temp = temp->next; 574: free(to_free); 575: } 576: } 577: 578: free(pointer); /*free the array of pointers to chaincodes*/ 579: } 580: 581: /*****BOUNDRY BOX********************************************************** 582: **********************************************************************/ 583: 584: /*takes two coordinates as x and y pairs and returns the distence betweem them 585: as a decimal*/ 586: float findDist(int x1, int y1, int x2, int y2) 587: { 588: return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2))); 589: } 590: 591: /*1st param: The array of coords that the first point of the major axis is 592: returned in. 593: 2nd: The array of coords that the second point of the major axis is 594: returned in. 595: 3rd: The array of chain codes that are searched through to find the major 596: axes.*/ 597: /* Note: the ending condition is when a NULL chainCodes value is reached. 598: Thusly, it works like a string requiring it to have the last legal value 599: followed by a null value.*/ 600: void findFirstTwoCorners(coord corner1[], coord corner2[], 601: chainCode** chainCodes) 602: { 603: int i; /*loop counting*/ 604: chainCode *temp, *search; 605: double max_dist, test_dist; 606: 607: /*printf("\nFinding first 2 corners.\n");*/ 608: 609: /*as long as there are codes to check, keep checking. Note: the ending 610: condition is when a NULL chainCodes value is reached. Thusly, it works 611: like a string requiring it to have the last legal value followed by a 612: null value.*/ 613: for(i = 0; (temp = chainCodes[i]) && (i < MAX_CHAINS); i++) 614: { 615: max_dist = 0.0; /*reset this for each iteration*/ 616: 617: /*printf("checking list: %d\n", i);*/ 618: 619: while(temp) /*while there are still nodes to check in the chain*/ 620: { 621: search = temp; /*set the faster moving search pointer to temp, 622: this increases the effiecency a lot compared to 623: setting it equal to the first node..*/ 624: while(search) 625: { 626: /*setCPixel(temp->location.x, temp->location.y, green);*/ 627: 628: /*determine if found a new maximum distance between two locations*/ 629: if((test_dist = findDist(search->location.x, search->location.y, 630: temp->location.x, temp->location.y)) > max_dist) 631: { 632: max_dist = test_dist; 633: corner1[i].x = temp->location.x; 634: corner1[i].y = temp->location.y; 635: corner2[i].x = search->location.x; 636: corner2[i].y = search->location.y; 637: } 638: search = search->next; 639: } 640: temp = temp->next; 641: } 642: /*printf("point1: %d %d\n", max1[i].x, max1[i].y); 643: printf("point2: %d %d\n", max2[i].x, max2[i].y);*/ 644: } 645: } 646: 647: /*1st param: Array of coords for the first corner of each chain code. 648: 2nd param: Array of coords for the second corner of each chain code. 649: The first two parameters should equal the first two parameters "returned" 650: from the findFirstTwoCorners() function. 651: 3rd: Array of coords "returned" with the third corners. 652: 4th: Array of coords "returned" with the fourth corners. 653: 5th: Pointer pointing to the array of chaincode pointers, obtained from 654: showChain().*/ 655: void findSecondTwoCorners(coord corner1[], coord corner2[], coord corner3[], 656: coord corner4[], chainCode** chain_code_array) 657: { 658: int i; /*loop counting*/ 659: chainCode* temp; 660: float temp_dist1, temp_dist2; /*distance between point and each corner*/ 661: coord canidate_coord1, temp_coord; 662: float canidate_dist1, max_dist; 663: int corner_count; 664: 665: /*printf("\nFinding last 2 corners.\n\n");*/ 666: 667: /*for each chain code find the corners*/ 668: for(i = 0; chain_code_array[i] && i < MAX_CHAINS; i++) 669: { 670: temp = chain_code_array[i]; 671: 672: /*reset these for the next chain code*/ 673: max_dist = 0.0; 674: corner_count = 1; 675: 676: while(temp) /*while there are nodes in the chain code to check*/ 677: { 678: /*setCPixel(temp->location.x, temp->location.y, color1);*/ 679: 680: /*determine the first canidate coord for corner 3/4*/ 681: if(((temp->location.x == corner1[i].x) 682: && (temp->location.y == corner1[i].y)) 683: || ((temp->location.x == corner2[i].x) 684: && (temp->location.y == corner2[i].y))) 685: { 686: /*if this corner found is the first of the two allready known 687: corners, then set the first canidate coord data and reset data 688: to find the next canidate corner point*/ 689: if(corner_count == 1) 690: { 691: canidate_coord1.x = temp_coord.x; 692: canidate_coord1.y = temp_coord.y; 693: canidate_dist1 = max_dist; 694: 695: corner_count = 2; /*set for next corner*/ 696: max_dist = 0.0; 697: } 698: else if(corner_count == 2) 699: { 700: /*the second canidate is always a corner*/ 701: corner4[i].x = temp_coord.x; 702: corner4[i].y = temp_coord.y; 703: 704: max_dist = 0.0; /*set for next corner canidate*/ 705: } 706: } 707: 708: /*calculate the distance between the current point being checked and 709: each corner point*/ 710: temp_dist1 = findDist(corner1[i].x, corner1[i].y, temp->location.x, 711: temp->location.y); 712: temp_dist2 = findDist(corner2[i].x, corner2[i].y, temp->location.x, 713: temp->location.y); 714: 715: /*if the current point is the furthest away sofar, store this point 716: untill it is overridden or becomes a canidate point*/ 717: if((temp_dist1 + temp_dist2) > max_dist) 718: { 719: temp_coord.x = temp->location.x; 720: temp_coord.y = temp->location.y; 721: 722: max_dist = (temp_dist1 + temp_dist2); 723: } 724: 725: temp = temp->next; /*advance*/ 726: } 727: 728: /*from the three canidate coords find the two real corners.*/ 729: /*the second canidate will always be a corner, must test 1 vs 3, where 730: three is in the variables temp_coord and max_dist.*/ 731: if(canidate_dist1 > max_dist) /*first canidate*/ 732: { 733: corner3[i].x = canidate_coord1.x; 734: corner3[i].y = canidate_coord1.y; 735: } 736: else /*third canidate*/ 737: { 738: corner3[i].x = temp_coord.x; 739: corner3[i].y = temp_coord.y; 740: } 741: /*printf("corner3: (%d, %d) corner4: (%d, %d)\n", corner3[i].x, 742: corner3[i].y, corner4[i].x, corner4[i].y);*/ 743: } 744: } 745: 746: /*takes a pointer to an image, and a pointer pointing to an array of 747: chain codes pointers, here each chainCode pointer needs to be accessed 748: by calculating the memory address.*/ 749: void showBound(PGMImage *original, chainCode** chainCodes) 750: { 751: int i; 752: 753: /*find the first two corners. they will be across a diagnal.*/ 754: findFirstTwoCorners(corner1, corner2, chainCodes); 755: /*find the second two corners. they will be across a diagnal too.*/ 756: findSecondTwoCorners(corner1, corner2, corner3, corner4, chainCodes); 757: /* 758: for(i = 0; chainCodes[i] && i < MAX_CHAINS; i++) 759: { 760: setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow); 761: setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow); 762: setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow); 763: setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow); 764: setCPixel(corner1[i].x, corner1[i].y, purple); 765: setCPixel(corner2[i].x, corner2[i].y, purple); 766: setCPixel(corner3[i].x, corner3[i].y, purple); 767: setCPixel(corner4[i].x, corner4[i].y, purple); 768: }*/ 769: } 770: 771: /**********************File I/O functions*******************************/ 772: /***********************************************************************/ 773: 774: /*Gets an ascii color pgm image file (type P3).*/ 775: void getPGMfile (char filename[], PGMImage *img) 776: { 777: FILE *in_file; 778: char ch; 779: int row, col, type; 780: 781: in_file = fopen(filename, "r"); 782: if (in_file == NULL) 783: { 784: fprintf(stderr, "Error: Unable to open file %s\n\n", filename); 785: exit(8); 786: } 787: 788: printf("\nReading image file: %s\n", filename); 789: 790: /*determine pgm image type (only type three can be used)*/ 791: ch = getc(in_file); 792: if(ch != 'P') 793: { 794: printf("ERROR(1): Not valid pgm/ppm file type\n"); 795: exit(1); 796: } 797: ch = getc(in_file); 798: /*convert the one digit integer character to integer(48 == '0')*/ 799: type = ch - 48; 800: if((type != 3) && (type != 6)) 801: { 802: printf("ERROR(2): Not valid pgm/ppm file type\n"); 803: exit(1); 804: } 805: 806: while(getc(in_file) != '\n'); /* skip to end of line*/ 807: 808: while (getc(in_file) == '#'); /* skip comments lines */ 809: { 810: while (getc(in_file) != '\n'); /* skip to end of line */ 811: } 812: 813: fseek(in_file, -1, SEEK_CUR); /* backup one character */ 814: 815: fscanf(in_file,"%d", &((*img).width)); 816: fscanf(in_file,"%d", &((*img).height)); 817: fscanf(in_file,"%d", &((*img).maxVal)); 818: 819: printf("\n width = %d",(*img).width); 820: printf("\n height = %d",(*img).height); 821: printf("\n maxVal = %d",(*img).maxVal); 822: printf("\n"); 823: 824: if (((*img).width > MAX) || ((*img).height > MAX)) 825: { 826: printf("\n\n***ERROR - image too big for current image structure***\n\n"); 827: exit(1); 828: } 829: 830: if(type == 3) /*uncompressed ascii file*/ 831: { 832: for (row=(*img).height-1; row>=0; row--) 833: for (col=0; col<(*img).width; col++) 834: { 835: fscanf(in_file,"%d", &((*img).data[row][col].red)); 836: fscanf(in_file,"%d", &((*img).data[row][col].green)); 837: fscanf(in_file,"%d", &((*img).data[row][col].blue)); 838: } 839: } 840: else if(type == 6) /*compressed file*/ 841: { 842: while(getc(in_file) != '\n'); /*skip to end of line*/ 843: 844: for (row=(*img).height-1; row>=0; row--) 845: for (col=0; col<(*img).width; col++) 846: { 847: (*img).data[row][col].red = getc(in_file); 848: (*img).data[row][col].green = getc(in_file); 849: (*img).data[row][col].blue = getc(in_file); 850: } 851: } 852: 853: fclose(in_file); 854: printf("\nDone reading file.\n"); 855: } 856: 857: 858: void save(PGMImage *img) 859: { 860: int i, j, nr, nc, k; 861: int red, green, blue; 862: FILE *iop; 863: 864: nr = img->height; 865: nc = img->width; 866: 867: iop = fopen("image1.pgm", "w"); 868: fprintf(iop, "P3\n"); 869: fprintf(iop, "%d %d\n", nc, nr); 870: fprintf(iop, "255\n"); 871: 872: k = 1; 873: for(i = nr - 1; i >= 0; i--) 874: { 875: for(j = 0; j < nc; j++) 876: { 877: red = img->data[i][j].red; 878: green = img->data[i][j].green; 879: blue = img->data[i][j].blue; 880: if(red < 0) 881: { 882: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j); 883: printf(" Setting red to zero\n"); 884: red = 0; 885: } 886: if(green < 0) 887: { 888: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j); 889: printf(" Setting green to zero\n"); 890: green = 0; 891: } 892: if(blue < 0) 893: { 894: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j); 895: printf(" Setting green to zero\n"); 896: blue = 0; 897: } 898: if(red > 255) 899: { 900: printf("IMG_WRITE: Found value %d at row %d col %d\n", red, i, j); 901: printf(" Setting red to 255\n"); 902: red = 255; 903: } 904: if(green > 255) 905: { 906: printf("IMG_WRITE: Found value %d at row %d col %d\n", green,i, j); 907: printf(" Setting green to 255\n"); 908: green = 255; 909: } 910: if(blue > 255) 911: { 912: printf("IMG_WRITE: Found value %d at row %d col %d\n", blue, i, j); 913: printf(" Setting blue to 255\n"); 914: blue = 255; 915: } 916: 917: if(k % 10) 918: { 919: fprintf(iop, "%d ", red); 920: fprintf(iop, "%d ", green); 921: fprintf(iop, "%d ", blue); 922: } 923: else /*for newline*/ 924: { 925: fprintf(iop, "%d\n", red); 926: fprintf(iop, "%d\n", green); 927: fprintf(iop, "%d\n", blue); 928: } 929: k++; 930: } 931: } 932: fprintf(iop, "\n"); 933: fclose(iop); 934: } 935: 936: 937: /****Calculation & drawing functions of the image translations********** 938: ***********************************************************************/ 939: 940: void showColor (PGMImage *img) 941: { 942: int i, j; /*loop counting: i = y, j = x*/ 943: 944: GLubyte checkImage[(*img).height][(*img).width][3]; 945: 946: for(i = 0; i < (*img).height; i++) 947: { 948: for(j = 0; j < (*img).width; j++) 949: { 950: checkImage[i][j][0] = (GLubyte) (*img).data[i][j].red; 951: checkImage[i][j][1] = (GLubyte) (*img).data[i][j].green; 952: checkImage[i][j][2] = (GLubyte) (*img).data[i][j].blue; 953: } 954: } 955: 956: glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 957: glRasterPos2f(-1, -1); 958: glDrawPixels((*img).width, (*img).height, GL_RGB, 959: GL_UNSIGNED_BYTE, checkImage); 960: 961: /*first check for non-null pointer, next check for dereferenced pointers 962: in the array of head pointers and lastly make sure things stay in 963: bound of the max incase all MAX_CHAINS number of chains are used.*/ 964: /*draw_abstract_lines is the global that holds the number of "objects" 965: to draw abstract information for*/ 966: for(i = 0; i < draw_abstract_lines && i < MAX_CHAINS; i++) 967: { 968: setCLines(corner1[i].x, corner1[i].y, corner3[i].x, corner3[i].y,yellow); 969: setCLines(corner4[i].x, corner4[i].y, corner2[i].x, corner2[i].y,yellow); 970: setCLines(corner3[i].x, corner3[i].y, corner2[i].x, corner2[i].y,yellow); 971: setCLines(corner4[i].x, corner4[i].y, corner1[i].x, corner1[i].y,yellow); 972: setCPixel(corner1[i].x, corner1[i].y, purple); 973: setCPixel(corner2[i].x, corner2[i].y, purple); 974: setCPixel(corner3[i].x, corner3[i].y, purple); 975: setCPixel(corner4[i].x, corner4[i].y, purple); 976: } 977: 978: if(draw_abstract_board >= 0) 979: { 980: setCLines(corner1[draw_abstract_board].x, 981: corner1[draw_abstract_board].y, 982: corner3[draw_abstract_board].x, 983: corner3[draw_abstract_board].y,blue); 984: setCLines(corner4[draw_abstract_board].x, 985: corner4[draw_abstract_board].y, 986: corner2[draw_abstract_board].x, 987: corner2[draw_abstract_board].y,blue); 988: setCLines(corner3[draw_abstract_board].x, 989: corner3[draw_abstract_board].y, 990: corner2[draw_abstract_board].x, 991: corner2[draw_abstract_board].y,blue); 992: setCLines(corner4[draw_abstract_board].x, 993: corner4[draw_abstract_board].y, 994: corner1[draw_abstract_board].x, 995: corner1[draw_abstract_board].y,blue); 996: setCPixel(corner1[draw_abstract_board].x, 997: corner1[draw_abstract_board].y, red); 998: setCPixel(corner2[draw_abstract_board].x, 999: corner2[draw_abstract_board].y, red); 1000: setCPixel(corner3[draw_abstract_board].x, 1001: corner3[draw_abstract_board].y, red); 1002: setCPixel(corner4[draw_abstract_board].x, 1003: corner4[draw_abstract_board].y, red); 1004: } 1005: glFlush(); 1006: } 1007: 1008: void camera_correction(PGMImage* new_img, PGMImage* org_img) 1009: { 1010: int row, col, img_row, img_col; /*loop counting*/ 1011: 1012: /*camera parameters*/ 1013: float height = 30; /*height of camera in cm*/ 1014: float gamma = 0, theta = .698; /*camera angles = 40 degrees in rad*/ 1015: float aperture = 1.1968, alpha = .598; /*aperature = 2 * alpha*/ 1016: 1017: /*temporary varaibles*/ 1018: float angular_height_corr; 1019: float angular_side_corr; 1020: int x_coord, y_coord; 1021: 1022: memset(new_img, 0, sizeof(PGMImage)); 1023: (*new_img).height = (*org_img).height; 1024: (*new_img).width = (*org_img).width; 1025: (*new_img).maxVal = (*org_img).maxVal; 1026: 1027: for (row=(*org_img).height-1; row>=0; row--) 1028: for (col=0; col<(*org_img).width; col++) 1029: { 1030: /*img_row -= (*org_img).height / 2; 1031: img_col = col - (*org_img).width / 2;*/ 1032: 1033: angular_height_corr = 1034: (theta - alpha) + col * (aperture / ((float)((*org_img).width) - 1)); 1035: angular_side_corr = 1036: (gamma - alpha) + row * (aperture / ((float)((*org_img).height) - 1)); 1037: 1038: angular_height_corr /= 2; 1039: /*angular_side_corr /= 2;*/ 1040: /*height *= 2;*/ 1041: height = 150; 1042: 1043: x_coord = (int) 1044: (height * (1 / tan(angular_height_corr)) * cos(angular_side_corr)); 1045: y_coord = (int) 1046: (height * (1 / tan(angular_height_corr)) * sin(angular_side_corr)); 1047: 1048: /*x_coord += (*org_img).width / 2;*/ 1049: y_coord += (*org_img).height / 2; 1050: 1051: /*printf("org: (%d, %d) new: (%d, %d)\n\n", row, col, y_coord, x_coord);*/ 1052: 1053: pxlcpy(new_img, y_coord, x_coord, org_img, row, col); 1054: } 1055: } 1056: 1057: void new_corr(PGMImage* new_img, PGMImage* org_img) 1058: { 1059: /*i and j are the left half, k and l are the right half*/ 1060: float i, k; /*loop counting*/ 1061: int j, l, row; /*loop counting*/ 1062: int old_i, old_k; 1063: 1064: float ins_s = 2; /*insert constant starting value*/ 1065: float ins_k = ins_s; /*insert constant*/ 1066: 1067: /*The halfway marks in the width.*/ 1068: int mid_width_left = ((*new_img).width / 2) - 1; 1069: int mid_width_right = ((*new_img).width / 2); 1070: 1071: /*just to be thourough clear the memory and reset maxes*/ 1072: memset(new_img, 0, sizeof(PGMImage)); 1073: (*new_img).height = (*org_img).height; 1074: (*new_img).width = (*org_img).width; 1075: (*new_img).maxVal = (*org_img).maxVal; 1076: 1077: /*Loop through each row from top to bottom...*/ 1078: for(row = ((*new_img).height - 1); row >= 0; row--) 1079: { 1080: /*...reset moire interference removal counter...*/ 1081: old_i = ((*new_img).width / 2) - 1; 1082: old_k = ((*new_img).width / 2); 1083: 1084: /*...so each half is ajusted to remove perspective effect...*/ 1085: for(i = j = mid_width_left, k = l = mid_width_right 1086: ; i >= 0, j >= 0, k < (*new_img).width, l < (*new_img).width 1087: ; i -= ins_k, j--, k += ins_k, l++) 1088: { 1089: for(;old_i >= (int)i; old_i--) /*...in the left half...*/ 1090: pxlcpy(new_img, row, old_i, org_img, row, j); 1091: for(;old_k <= (int)k; old_k++) /*...in the right half.*/ 1092: pxlcpy(new_img, row, old_k, org_img, row, l); 1093: } 1094: /*Move the new image x_coord pixel counter to next new image pixel*/ 1095: ins_k -= ((ins_s - 1.0) / (*new_img).height); 1096: } 1097: } 1098: 1099: void color_to_gray(PGMImage* new_img, PGMImage* org_img) 1100: { 1101: int row, col; /*loop counting*/ 1102: RGB_INT cur_pxl; /*current pixel*/ 1103: 1104: (*new_img).height = (*org_img).height; 1105: (*new_img).width = (*org_img).width; 1106: (*new_img).maxVal = (*org_img).maxVal; 1107: 1108: /*Starting with the top row...*/ 1109: for(row = (*new_img).height - 1; row >= 0; row--) 1110: for(col = 0; col < (*new_img).width - 1; col++) 1111: { 1112: cur_pxl = (*org_img).data[row][col]; /*more readable*/ 1113: 1114: /*convert each RGB to the average of the original*/ 1115: (*new_img).data[row][col].red = rgb_avg(cur_pxl); 1116: (*new_img).data[row][col].green = rgb_avg(cur_pxl); 1117: (*new_img).data[row][col].blue = rgb_avg(cur_pxl); 1118: } 1119: } 1120: 1121: void moravec(PGMImage* new_img, PGMImage* org_img) 1122: { 1123: int row, col; /*loop counting*/ 1124: int i, j, k, l; /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/ 1125: int running_sum; 1126: float K = .5; /*.125 according to org. formula, but .5 is brighter*/ 1127: int max_val = 0, row_max, col_max; /* max porportion value in image*/ 1128: 1129: memset(new_img, 0, sizeof(PGMImage)); 1130: (*new_img).height = (*org_img).height; 1131: (*new_img).width = (*org_img).width; 1132: (*new_img).maxVal = (*org_img).maxVal; 1133: 1134: /*starting at the top row*/ 1135: for(row = (*new_img).height - 1 - 1; row > 0; row--) 1136: for(col = 1; col < (*new_img).width - 1; col++) /*left col start*/ 1137: { 1138: i = row; 1139: j = col; 1140: running_sum = 0; 1141: 1142: /*Sanka, Hlavac & Boyle; p. 97 f. 4.73*/ 1143: for(k = i - 1; k <= i + 1; k++) /*row*/ 1144: for(l = j - 1; l <= j + 1; l++) /*column*/ 1145: running_sum += abs(rgb_avg((*org_img).data[k][l]) - 1146: rgb_avg((*org_img).data[i][j])); 1147: 1148: /*assign the new pixel value*/ 1149: (*new_img).data[row][col].red = (int)(K * running_sum); 1150: (*new_img).data[row][col].green = (int)(K * running_sum); 1151: (*new_img).data[row][col].blue = (int)(K * running_sum); 1152: } 1153: } 1154: 1155: /*returns the number of objects found*/ 1156: int detect_corners(PGMImage* org_img) 1157: { 1158: int i; /*temporarily holds number of chaincodes*/ 1159: 1160: glPointSize(4); /*make points more visible, if desired*/ 1161: glLineWidth(4); 1162: 1163: chain_codes = showChain(org_img); 1164: showBound(org_img, chain_codes); 1165: 1166: /*when this stops, i holds the number of chaincodes*/ 1167: for(i = 0; (i < MAX_CHAINS) && chain_codes[i]; i++); 1168: 1169: free_chaincode(chain_codes); 1170: 1171: return i; 1172: } 1173: 1174: /*determines which object is the game board and determine moves made in 1175: the game.*/ 1176: /*takes the number of object corners (equal to # of chaincodes) as param.*/ 1177: int detect_game(int num_of_corners) 1178: { 1179: float length2to4[MAX_CHAINS], length1to3[MAX_CHAINS]; /*side pairs*/ 1180: float length1to4[MAX_CHAINS], length2to3[MAX_CHAINS]; /*side pairs*/ 1181: 1182: float error24to13[MAX_CHAINS], error14to23[MAX_CHAINS]; 1183: 1184: int i; /*loop counting*/ 1185: float denom_check; /*make sure denominators are not zero*/ 1186: 1187: /*the most likely object (0 to num_of_corners) that is to be considered 1188: as the board. The float is the error associated with this object.*/ 1189: int most_likely = -1; 1190: float ml_error = FLT_MAX; /*just to make sure*/ 1191: 1192: for(i = 0; i < num_of_corners; i++) 1193: { 1194: /*since points 1 & 2 are at a diagnal, and 3 & 4 are at a diagnol, 1195: then the slopes between 2 and 4 and 1 and three should be close 1196: in value.*/ 1197: length2to4[i] = findDist(corner2[i].x, corner2[i].y, corner4[i].x, 1198: corner4[i].y); 1199: length1to3[i] = findDist(corner1[i].x, corner1[i].y, corner3[i].x, 1200: corner3[i].y); 1201: 1202: /*the other side pair*/ 1203: length1to4[i] = findDist(corner1[i].x, corner1[i].y, corner4[i].x, 1204: corner4[i].y); 1205: 1206: length2to3[i] = findDist(corner2[i].x, corner2[i].y, corner3[i].x, 1207: corner3[i].y); 1208: 1209: 1210: denom_check = fabs((length2to4[i] + length1to3[i]) / 2); 1211: if(denom_check == 0) 1212: { 1213: /*the only way to possibly pull this off is if one point is 1214: is considered more than one corner. This is most likely 1215: to happen where the chain was only two or three nodes long.*/ 1216: /*Just set the error to the maximum value obtained from float.h, 1217: since such a small chain is not what we are looking for.*/ 1218: 1219: error24to13[i] = FLT_MAX; 1220: } 1221: else 1222: error24to13[i] = fabs(length2to4[i] - length1to3[i]) / denom_check; 1223: /*fabs((length2to4[i] + length1to3[i]) / 2);*/ 1224: 1225: denom_check = fabs((length1to4[i] + length2to3[i]) / 2); 1226: if(denom_check == 0) 1227: { 1228: /*the only way to possibly pull this off is if one point is 1229: is considered more than one corner. This is most likely 1230: to happen where the chain was only two or three nodes long.*/ 1231: /*Just set the error to the maximum value obtained from float.h, 1232: since such a small chain is not what we are looking for.*/ 1233: 1234: error14to23[i] = FLT_MAX; 1235: } 1236: else 1237: error14to23[i] = fabs(length1to4[i] - length2to3[i]) / denom_check; 1238: /*fabs((length1to4[i] + length2to3[i]) / 2);*/ 1239: 1240: /*determine if the current object is considered the most likely to 1241: be the ttt board so far.*/ 1242: if(ml_error > ((error24to13[i] + error14to23[i]) / 2)) 1243: { 1244: most_likely = i; 1245: ml_error = ((error24to13[i] + error14to23[i]) / 2); 1246: } 1247: } 1248: 1249: printf("Object %d is most likely the board with %f\%% error.\n", 1250: most_likely, ml_error * 100); 1251: 1252: return most_likely; 1253: } 1254: 1255: 1256: /* ================================================================= 1257: * Callback functions. 1258: * 1259: * color = displayed graphics in window 1260: * menu = menu event handling 1261: * keyboard = deyboard event handling 1262: * ----------------------------------------------------------------- */ 1263: void color(void) 1264: { 1265: /*glClear (GL_COLOR_BUFFER_BIT);*/ 1266: 1267: /* printf("\nDrawing Original image...\n");*/ 1268: showColor(img_cur); 1269: 1270: /*glFlush();*/ 1271: } 1272: 1273: void buffer() 1274: { 1275: draw_abstract_lines = detect_corners(img_cur); 1276: 1277: glutPostRedisplay(); 1278: } 1279: 1280: #define RESTART 0 1281: #define CAMERA_CORRECTION 1 1282: #define X2_C_CORR 2 1283: #define NEW_CORR 3 1284: #define COLOR_TO_GRAY 4 1285: #define MORAVEC 5 1286: #define CORNERS 6 1287: #define BUFFERS 7 1288: #define GAME 8 1289: 1290: void menu(int selection) 1291: { 1292: if(selection == RESTART) 1293: { 1294: memcpy(img1, img0, sizeof(PGMImage)); 1295: img_cur = img0; 1296: draw_abstract_lines = -1; 1297: draw_abstract_board = -1; 1298: } 1299: if(selection == CAMERA_CORRECTION) 1300: { 1301: printf("Starting camera correction\n"); 1302: camera_correction(img1, img0); 1303: img_cur = img1; 1304: draw_abstract_lines = -1; 1305: draw_abstract_board = -1; 1306: } 1307: if(selection == X2_C_CORR) 1308: { 1309: printf("Starting camera correction\n"); 1310: camera_correction(img1, img0); 1311: camera_correction(img2, img1); 1312: img_cur = img2; 1313: draw_abstract_lines = -1; 1314: draw_abstract_board = -1; 1315: } 1316: if(selection == NEW_CORR) 1317: { 1318: new_corr(img1, img0); 1319: img_cur = img1; 1320: draw_abstract_lines = -1; 1321: draw_abstract_board = -1; 1322: } 1323: if(selection == COLOR_TO_GRAY) 1324: { 1325: color_to_gray(img1, img0); 1326: img_cur = img1; 1327: draw_abstract_lines = -1; 1328: draw_abstract_board = -1; 1329: } 1330: if(selection == MORAVEC) 1331: { 1332: moravec(img1, img0); 1333: img_cur = img1; 1334: draw_abstract_lines = -1; 1335: draw_abstract_board = -1; 1336: } 1337: if(selection == CORNERS) 1338: { 1339: draw_abstract_lines = detect_corners(img_cur); 1340: } 1341: if(selection == BUFFERS) 1342: { 1343: 1344: if(is_buffered == FALSE) 1345: { 1346: glutIdleFunc(buffer); 1347: is_buffered = TRUE; 1348: } 1349: else 1350: { 1351: glutIdleFunc(NULL); 1352: is_buffered = FALSE; 1353: } 1354: } 1355: if(selection == GAME) 1356: { 1357: draw_abstract_board = detect_game(detect_corners(img_cur)); 1358: } 1359: 1360: glutPostRedisplay(); 1361: } 1362: 1363: void keyboard(unsigned char key, int x, int y) 1364: { 1365: switch (key) 1366: { 1367: case 27: 1368: exit(0); 1369: break; 1370: } 1371: } 1372: 1373: void mouse(int button, int state, int x, int y) 1374: { 1375: char temp[50]; 1376: 1377: if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 1378: { 1379: sprintf(temp, "(x, y): (%d, %d) red: %d green: %d blue: %d\n", 1380: x, VSIZE - y, (*img_cur).data[VSIZE - y][x].red, 1381: (*img_cur).data[VSIZE - y][x].green, 1382: (*img_cur).data[VSIZE - y][x].blue); 1383: setCRect(0, 0, 200, 12, black); 1384: glColor3f(1.0, 0.0, 0.0); 1385: drawString(0, 0, GLUT_BITMAP_TIMES_ROMAN_10, temp); 1386: glFlush(); 1387: } 1388: } 1389: 1390: 1391: /* ================================================================= 1392: * init() & parse_command_line() 1393: * initalize none-OpenGL related things. 1394: * ----------------------------------------------------------------- */ 1395: 1396: /*set global flag variables from things specified at commandline.*/ 1397: /*return the filename specified, if none specified exit().*/ 1398: char* parse_command_line(int argc, char** argv) 1399: { 1400: /*parse the command line*/ 1401: if(argc == 1) 1402: { 1403: printf("To few parameters.\n"); 1404: printf("Usage: research <file.pgm>\n"); 1405: exit(1); 1406: } 1407: else if(argc == 2) 1408: { 1409: return argv[1]; 1410: } 1411: else 1412: { 1413: printf("To many parameters.\n"); 1414: printf("Usage: research <file.pgm>\n"); 1415: exit(1); 1416: } 1417: } 1418: 1419: char* init (int argc, char** argv) 1420: { 1421: char* PGMfileName;/*pointer to the string containing the filename*/ 1422: 1423: /*parse the command line*/ 1424: PGMfileName = parse_command_line(argc, argv); 1425: 1426: /* 1427: * Read in image file. - note: sets our global values, too. 1428: * ----------------------------------------------------------------- */ 1429: 1430: img0 = (PGMImage*) malloc(sizeof(PGMImage)); 1431: getPGMfile(PGMfileName, img0); 1432: HSIZE = (*img0).width; 1433: VSIZE = (*img0).height; 1434: MVAL = (*img0).maxVal; 1435: 1436: img_cur = img0; /*VERY IMPORTANT to set this*/ 1437: 1438: /*allocate memory for second image*/ 1439: img1 = (PGMImage*) malloc(sizeof(PGMImage)); 1440: memcpy(img1, img0, sizeof(PGMImage)); 1441: /*(*img1).width = HSIZE; 1442: (*img1).height = VSIZE; 1443: (*img1).maxVal = 255;*/ 1444: 1445: img2 = (PGMImage*) malloc(sizeof(PGMImage)); 1446: memcpy(img2, img0, sizeof(PGMImage)); 1447: 1448: memset(corner1, 0, sizeof(coord) * MAX_CHAINS); 1449: memset(corner2, 0, sizeof(coord) * MAX_CHAINS); 1450: memset(corner3, 0, sizeof(coord) * MAX_CHAINS); 1451: memset(corner4, 0, sizeof(coord) * MAX_CHAINS); 1452: 1453: return PGMfileName; 1454: } 1455: 1456: 1457: int main(int argc, char** argv) 1458: { 1459: char* PGMfileName; 1460: int WindowID; /*unique window id, there is only one used*/ 1461: int i; /*looping variable*/ 1462: 1463: /* 1464: * Call our init function to define non-OpenGL related things. 1465: * Have init return a pointer to the filename, used to display the 1466: * filename in the titlebar of the window. 1467: * ----------------------------------------------------------------- */ 1468: PGMfileName = init (argc, argv); 1469: 1470: /* 1471: * Initialize the glut package. 1472: * ----------------------------------------------------------------- */ 1473: glutInit(&argc, argv); 1474: glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 1475: 1476: /* 1477: * Define a new window (its size, position and title). 1478: * ----------------------------------------------------------------- */ 1479: glutInitWindowSize (HSIZE, VSIZE); /*size*/ 1480: glutInitWindowPosition (10, 10); /*position*/ 1481: WindowID = glutCreateWindow (PGMfileName); /*title*/ 1482: glutSetWindow(WindowID); 1483: glutDisplayFunc(color); 1484: 1485: /* 1486: * select clearing color - white 1487: */ 1488: glClearColor (1.0, 1.0, 1.0, 0.0); 1489: 1490: /* 1491: * initialize viewport values 1492: */ 1493: glMatrixMode(GL_PROJECTION); 1494: glLoadIdentity(); 1495: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 1496: 1497: /*add menus*/ 1498: glutCreateMenu(menu); 1499: glutAddMenuEntry("Restart", RESTART); 1500: /* glutAddMenuEntry("Camera Correction", CAMERA_CORRECTION); 1501: glutAddMenuEntry("2x C. Corr.", X2_C_CORR);*/ 1502: glutAddMenuEntry("new corr", NEW_CORR); 1503: glutAddMenuEntry("color to gray", COLOR_TO_GRAY); 1504: glutAddMenuEntry("moravec", MORAVEC); 1505: glutAddMenuEntry("corners", CORNERS); 1506: glutAddMenuEntry("toggle buffering", BUFFERS); 1507: glutAddMenuEntry("detect game", GAME); 1508: glutAttachMenu(GLUT_RIGHT_BUTTON); 1509: 1510: glutMouseFunc(mouse); 1511: glutKeyboardFunc(keyboard); 1512: glutMainLoop(); 1513: 1514: /* 1515: * When we reach here, we've left the event loop and are ready to 1516: * exit. 1517: * ----------------------------------------------------------------- */ 1518: return 0; 1519: } 1520: 1521: 1522: 1523: 1524: 1525: 1526: 1527: 1528: 1529: 1530: 1531: 1532: