 Timestamp:
 May 25, 2009, 2:16:50 AM (11 years ago)
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

libpipi/trunk/examples/img2twit.cpp
r3520 r3521 16 16 */ 17 17 18 /* Debug mode */ 19 #define DEBUG 1 20 21 /* Encoding iterations: 1000 gives a fast answer, 10000 gives good quality */ 22 #define MAX_ITERATIONS 10000 23 18 24 /* The maximum message length */ 19 25 #define MAX_MSG_LEN 140 20 26 21 /* The number of characters at disposal */ 22 //#define NUM_CHARACTERS 0x7fffffff // The sky's the limit 23 //#define NUM_CHARACTERS 1111998 // Full valid Unicode set 24 //#define NUM_CHARACTERS 100507 // Full graphic Unicode 25 #define NUM_CHARACTERS 32768 // Chinese characters 26 //#define NUM_CHARACTERS 127 // ASCII 27 /* The Unicode characters at disposal  XXX: must be _ordered_ */ 28 static const uint32_t unichars[] = 29 { 30 /* Printable ASCII (except space) */ 31 0x0021, 0x007f, 32 33 /* Stupid symbols and Dingbats shit */ 34 //0x25a0, 0x2600, /* Geometric Shapes */ 35 //0x2600, 0x269e, 0x26a0, 0x26bd, 0x26c0, 0x26c4, /* Misc. Symbols */ 36 //0x2701, 0x2705, 0x2706, 0x270a, 0x270c, 0x2728, 0x2729, 0x274c, 37 // 0x274d, 0x274e, 0x274f, 0x2753, 0x2756, 0x2757, 0x2758, 0x275f, 38 // 0x2761, 0x2795, 0x2798, 0x27b0, 0x27b1, 0x27bf, /* Dingbats */ 39 40 /* Chineselooking stuff */ 41 //0x2e80, 0x2e9a, 0x2e9b, 0x2ef4, /* CJK Radicals Supplement */ 42 //0x2f00, 0x2fd6, /* Kangxi Radicals */ 43 //0x3400, 0x4db6, /* CJK Unified Ideographs Extension A */ 44 //0x4e00, 0x9fa6, /* CJK Unified Ideographs */ 45 46 /* Korean  most people don't know the difference anyway */ 47 0xac00, 0xd7a4, /* Hangul Syllables */ 48 49 /* More Chinese */ 50 //0xf900, 0xfa2e, 0xfa30, 0xfa6b, 0xfa70, 0xfada, /* CJK Compat. Idgphs. */ 51 52 /* TODO: there's also the U+20000 and U+2f800 planes, but they're 53 * not supported by the Twitter Javascript filter (yet?). */ 54 55 /* End of list marker  XXX: don't remove! */ 56 0x0000, 0x0000 57 }; 27 58 28 59 /* The maximum image size we want to support */ … … 54 85 static float HEADER_BITS; 55 86 static float DATA_BITS; 56 static float POINT_BITS; 57 87 static float CELL_BITS; 88 89 static int NUM_CHARACTERS; 58 90 static unsigned int TOTAL_CELLS; 59 91 … … 78 110 static Delaunay_triangulation dt; 79 111 112 /* 113 * Unicode stuff handling 114 */ 115 116 /* Return the number of chars in the unichars table */ 117 static int count_unichars(void) 118 { 119 int ret = 0; 120 121 for(int u = 0; unichars[u] != unichars[u + 1]; u += 2) 122 ret += unichars[u + 1]  unichars[u]; 123 124 return ret; 125 } 126 127 /* Get the ith Unicode character in our list */ 128 static uint32_t index2uni(uint32_t i) 129 { 130 for(int u = 0; unichars[u] != unichars[u + 1]; u += 2) 131 if(i < unichars[u + 1]  unichars[u]) 132 return unichars[u] + i; 133 else 134 i = unichars[u + 1]  unichars[u]; 135 136 return 0; /* Should not happen! */ 137 } 138 139 /* Convert a Unicode character to its position in the compact list */ 140 static uint32_t uni2index(uint32_t x) 141 { 142 uint32_t ret = 0; 143 144 for(int u = 0; unichars[u] != unichars[u + 1]; u += 2) 145 if(x < unichars[u + 1]) 146 return ret + x  unichars[u]; 147 else 148 ret += unichars[u + 1]  unichars[u]; 149 150 return ret; /* Should not happen! */ 151 } 152 153 static uint8_t const utf8_trailing[256] = 154 { 155 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 156 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 157 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 158 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 159 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 160 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 161 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 162 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 163 }; 164 165 static uint32_t const utf8_offsets[6] = 166 { 167 0x00000000UL, 0x00003080UL, 0x000E2080UL, 168 0x03C82080UL, 0xFA082080UL, 0x82082080UL 169 }; 170 171 static uint32_t fread_utf8(FILE *f) 172 { 173 int ch, i = 0, todo = 1; 174 uint32_t ret = 0; 175 176 for(;;) 177 { 178 ch = fgetc(f); 179 if(!ch) 180 return 0; 181 if(todo == 1) 182 todo = utf8_trailing[ch]; 183 ret += ((uint32_t)ch) << (6 * (todo  i)); 184 if(todo == i++) 185 return ret  utf8_offsets[todo]; 186 } 187 } 188 189 static void fwrite_utf8(FILE *f, uint32_t x) 190 { 191 static const uint8_t mark[7] = 192 { 193 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC 194 }; 195 196 char buf[8]; 197 char *parser = buf; 198 size_t bytes; 199 200 if(x < 0x80) 201 { 202 fprintf(f, "%c", x); 203 return; 204 } 205 206 bytes = (x < 0x800) ? 2 : (x < 0x10000) ? 3 : 4; 207 parser += bytes; 208 *parser = '\0'; 209 210 switch(bytes) 211 { 212 case 4: *parser = (x  0x80) & 0xbf; x >>= 6; 213 case 3: *parser = (x  0x80) & 0xbf; x >>= 6; 214 case 2: *parser = (x  0x80) & 0xbf; x >>= 6; 215 } 216 *parser = x  mark[bytes]; 217 218 fprintf(f, "%s", buf); 219 } 220 221 /* 222 * Our nifty nonpoweroftwo bitstack handling 223 */ 224 225 class bitstack 226 { 227 public: 228 bitstack() { init(0); } 229 230 char const *tostring() 231 { 232 int pos = sprintf(str, "0x%x", digits[msb]); 233 234 for(int i = msb  1; i >= 0; i) 235 pos += sprintf(str + pos, "%08x", digits[i]); 236 237 return str; 238 } 239 240 void push(uint32_t val, uint32_t range) 241 { 242 if(!range) 243 return; 244 245 mul(range); 246 add(val % range); 247 } 248 249 uint32_t pop(uint32_t range) 250 { 251 if(!range) 252 return 0; 253 254 return div(range); 255 } 256 257 bool isempty() 258 { 259 for(int i = msb; i >= 0; i) 260 if(digits[i]) 261 return false; 262 263 return true; 264 } 265 266 private: 267 bitstack(uint32_t i) { init(i); } 268 269 void init(uint32_t i) 270 { 271 memset(digits, 0, sizeof(digits)); 272 digits[0] = i; 273 msb = 0; 274 } 275 276 /* Could be done much faster, but we don't care! */ 277 void add(uint32_t x) { add(bitstack(x)); } 278 void sub(uint32_t x) { sub(bitstack(x)); } 279 280 void add(bitstack const &_b) 281 { 282 /* Copy the operand in case we get added to ourselves */ 283 bitstack b = _b; 284 uint64_t x = 0; 285 286 if(msb < b.msb) 287 msb = b.msb; 288 289 for(int i = 0; i <= msb; i++) 290 { 291 uint64_t tmp = (uint64_t)digits[i] + (uint64_t)b.digits[i] + x; 292 digits[i] = tmp; 293 if((uint64_t)digits[i] == tmp) 294 x = 0; 295 else 296 { 297 x = 1; 298 if(i == msb) 299 msb++; 300 } 301 } 302 } 303 304 void sub(bitstack const &_b) 305 { 306 /* Copy the operand in case we get substracted from ourselves */ 307 bitstack b = _b; 308 uint64_t x = 0; 309 310 /* We cannot substract a larger number! */ 311 if(msb < b.msb) 312 { 313 init(0); 314 return; 315 } 316 317 for(int i = 0; i <= msb; i++) 318 { 319 uint64_t tmp = (uint64_t)digits[i]  (uint64_t)b.digits[i]  x; 320 digits[i] = tmp; 321 if((uint64_t)digits[i] == tmp) 322 x = 0; 323 else 324 { 325 x = 1; 326 if(i == msb) 327 { 328 /* Error: carry into MSB! */ 329 init(0); 330 return; 331 } 332 } 333 } 334 335 while(msb > 0 && digits[msb] == 0) msb; 336 } 337 338 void mul(uint32_t x) 339 { 340 bitstack b = *this; 341 init(0); 342 343 while(x) 344 { 345 if(x & 1) 346 add(b); 347 x /= 2; 348 b.add(b); 349 } 350 } 351 352 uint32_t div(uint32_t x) 353 { 354 bitstack b = *this; 355 356 for(int i = msb; i >= 0; i) 357 { 358 uint64_t tmp = b.digits[i] + (((uint64_t)b.digits[i + 1]) << 32); 359 uint32_t res = tmp / x; 360 uint32_t rem = tmp % x; 361 digits[i]= res; 362 b.digits[i + 1] = 0; 363 b.digits[i] = rem; 364 } 365 366 while(msb > 0 && digits[msb] == 0) msb; 367 368 return b.digits[0]; 369 } 370 371 int msb; 372 uint32_t digits[MAX_MSG_LEN + 1]; /* This is a safe max value */ 373 char str[(MAX_MSG_LEN + 1) * 8 + 1]; 374 }; 375 376 /* 377 * Point handling 378 */ 379 80 380 static unsigned int det_rand(unsigned int mod) 81 381 { … … 157 457 } 158 458 459 #if 0 159 460 static void add_random_point() 160 461 { … … 162 463 npoints++; 163 464 } 465 #endif 164 466 165 467 #define NB_OPS 20 … … 439 741 { 440 742 int opstats[2 * NB_OPS]; 743 bitstack b; 441 744 pipi_image_t *src, *tmp, *dst; 442 745 double error = 1.0; 443 746 int width, height, ret = 0; 444 445 /* Compute bit allocation */ 446 fprintf(stderr, "Available characters: %i\n", NUM_CHARACTERS); 447 fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN); 747 bool decode = (argc >= 2 && !strcmp(argv[1], "o")); 748 749 if(!((argc == 2 && !decode)  (argc == 3 && decode))) 750 { 751 fprintf(stderr, "img2twit: wrong argument count\n"); 752 fprintf(stderr, "Usage: img2twit <image> Encode image and print result to stdout\n"); 753 fprintf(stderr, " img2twit o <image> Read data from stdin and decode image to file\n"); 754 return EXIT_FAILURE; 755 } 756 757 pipi_set_gamma(1.0); 758 759 /* Precompute bit allocation */ 760 NUM_CHARACTERS = count_unichars(); 448 761 TOTAL_BITS = MAX_MSG_LEN * logf(NUM_CHARACTERS) / logf(2); 449 fprintf(stderr, "Available bits: %f\n", TOTAL_BITS);450 fprintf(stderr, "Maximum image resolution: %ix%i\n", MAX_W, MAX_H);451 762 HEADER_BITS = logf(MAX_W * MAX_H) / logf(2); 452 fprintf(stderr, "Header bits: %f\n", HEADER_BITS);453 763 DATA_BITS = TOTAL_BITS  HEADER_BITS; 454 fprintf(stderr, "Bits available for data: %f\n", DATA_BITS);455 764 #if POINTS_PER_CELL == 1 456 POINT_BITS = logf(RANGE_SYXRGB) / logf(2);765 CELL_BITS = logf(RANGE_SYXRGB) / logf(2); 457 766 #else 458 float coord_bits = logf((RANGE_Y * RANGE_X) * (RANGE_Y * RANGE_X + 1) / 2); 459 float other_bits = logf(RANGE_R * RANGE_G * RANGE_B * RANGE_S); 460 POINT_BITS = (coord_bits + 2 * other_bits) / logf(2); 461 #endif 462 fprintf(stderr, "Cell bits: %f\n", POINT_BITS); 463 TOTAL_CELLS = (int)(DATA_BITS / POINT_BITS); 464 fprintf(stderr, "Available cells: %i\n", TOTAL_CELLS); 465 fprintf(stderr, "Wasted bits: %f\n", DATA_BITS  POINT_BITS * TOTAL_CELLS); 466 467 /* Load image */ 468 pipi_set_gamma(1.0); 469 src = pipi_load(argv[1]); 470 width = pipi_get_image_width(src); 471 height = pipi_get_image_height(src); 767 // TODO: implement the following shit 768 //float coord_bits = logf((RANGE_Y * RANGE_X) * (RANGE_Y * RANGE_X + 1) / 2); 769 //float other_bits = logf(RANGE_R * RANGE_G * RANGE_B * RANGE_S); 770 //CELL_BITS = (coord_bits + 2 * other_bits) / logf(2); 771 CELL_BITS = 2 * logf(RANGE_SYXRGB) / logf(2); 772 #endif 773 TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS); 774 775 if(decode) 776 { 777 /* Decoding mode: read UTF8 text from stdin, find each 778 * character's index in our character list, and push it to our 779 * wonderful custom bitstream. */ 780 uint32_t data[MAX_MSG_LEN]; 781 for(int i = 0; i < MAX_MSG_LEN; i++) 782 data[i] = uni2index(fread_utf8(stdin)); 783 for(int i = MAX_MSG_LEN; i; ) 784 b.push(data[i], NUM_CHARACTERS); 785 786 /* Read width and height from bitstream */ 787 src = NULL; 788 width = b.pop(MAX_W); 789 height = b.pop(MAX_H); 790 } 791 else 792 { 793 /* Argument given: open image for encoding */ 794 src = pipi_load(argv[1]); 795 796 if(!src) 797 { 798 fprintf(stderr, "Error loading %s\n", argv[1]); 799 return EXIT_FAILURE; 800 } 801 802 width = pipi_get_image_width(src); 803 height = pipi_get_image_height(src); 804 } 472 805 473 806 /* Compute best w/h ratio */ … … 489 822 while((dh + 1) * dw <= TOTAL_CELLS) dh++; 490 823 while(dw * (dh + 1) <= TOTAL_CELLS) dw++; 824 825 /* Print debug information */ 826 #if DEBUG 827 fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN); 828 fprintf(stderr, "Available characters: %i\n", NUM_CHARACTERS); 829 fprintf(stderr, "Available bits: %f\n", TOTAL_BITS); 830 fprintf(stderr, "Maximum image resolution: %ix%i\n", MAX_W, MAX_H); 831 fprintf(stderr, "Image resolution: %ix%i\n", width, height); 832 fprintf(stderr, "Header bits: %f\n", HEADER_BITS); 833 fprintf(stderr, "Bits available for data: %f\n", DATA_BITS); 834 fprintf(stderr, "Cell bits: %f\n", CELL_BITS); 835 fprintf(stderr, "Available cells: %i\n", TOTAL_CELLS); 836 fprintf(stderr, "Wasted bits: %f\n", DATA_BITS  CELL_BITS * TOTAL_CELLS); 837 491 838 fprintf(stderr, "Chosen image ratio: %i:%i (wasting %i point cells)\n", 492 839 dw, dh, TOTAL_CELLS  dw * dh); 493 840 fprintf(stderr, "Total wasted bits: %f\n", 494 DATA_BITS  POINT_BITS * dw * dh); 495 496 /* Resize and filter image to better state */ 497 tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y); 498 pipi_free(src); 499 src = pipi_median_ext(tmp, 1, 1); 500 pipi_free(tmp); 501 502 /* Analyse image */ 503 analyse(src); 504 505 /* Render what we just computed */ 506 tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y); 507 render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y); 508 error = pipi_measure_rmsd(src, tmp); 509 510 fprintf(stderr, "Distance: %2.10g\n", error); 511 512 memset(opstats, 0, sizeof(opstats)); 513 for(int iter = 0, stuck = 0, failures = 0, success = 0; 514 /*stuck < 5 && */iter < 10000; 515 iter++) 516 { 517 if(failures > 500) 518 { 519 stuck++; 520 failures = 0; 521 } 522 523 pipi_image_t *scrap = pipi_copy(tmp); 524 525 /* Choose a point at random */ 526 int pt = det_rand(npoints); 527 uint32_t oldval = points[pt]; 528 529 /* Compute the affected image zone */ 530 float fx, fy, fr, fg, fb, fs; 531 get_point(pt, &fx, &fy, &fr, &fg, &fb, &fs); 532 int zonex = (int)fx / RANGE_X  1; 533 int zoney = (int)fy / RANGE_Y  1; 534 int zonew = 3; 535 int zoneh = 3; 536 if(zonex < 0) { zonex = 0; zonew; } 537 if(zoney < 0) { zoney = 0; zoneh; } 538 if(zonex + zonew >= (int)dw) { zonew; } 539 if(zoney + zoneh >= (int)dh) { zoneh; } 540 541 /* Choose random operations and measure their effect */ 542 uint8_t op1 = rand_op(); 543 //uint8_t op2 = rand_op(); 544 545 uint32_t candidates[3]; 546 double besterr = error + 1.0; 547 int bestop = 1; 548 candidates[0] = apply_op(op1, oldval); 549 //candidates[1] = apply_op(op2, oldval); 550 //candidates[2] = apply_op(op1, apply_op(op2, oldval)); 551 552 for(int i = 0; i < 1; i++) 553 //for(int i = 0; i < 3; i++) 554 { 555 if(oldval == candidates[i]) 556 continue; 557 558 points[pt] = candidates[i]; 559 560 render(scrap, zonex * RANGE_X, zoney * RANGE_Y, 561 zonew * RANGE_X, zoneh * RANGE_Y); 562 563 double newerr = pipi_measure_rmsd(src, scrap); 564 if(newerr < besterr) 841 DATA_BITS  CELL_BITS * dw * dh); 842 #endif 843 844 if(src) 845 { 846 /* Resize and filter image to better state */ 847 tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y); 848 pipi_free(src); 849 src = pipi_median_ext(tmp, 1, 1); 850 pipi_free(tmp); 851 852 /* Analyse image */ 853 analyse(src); 854 855 /* Render what we just computed */ 856 tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y); 857 render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y); 858 error = pipi_measure_rmsd(src, tmp); 859 860 #if DEBUG 861 fprintf(stderr, "Distance: %2.10g\n", error); 862 #endif 863 864 memset(opstats, 0, sizeof(opstats)); 865 for(int iter = 0, stuck = 0, failures = 0, success = 0; 866 iter < MAX_ITERATIONS /* && stuck < 5 && */; 867 iter++) 868 { 869 if(failures > 500) 565 870 { 566 besterr = newerr;567 bestop = i;871 stuck++; 872 failures = 0; 568 873 } 569 } 570 571 opstats[op1 * 2]++; 572 //opstats[op2 * 2]++; 573 574 if(besterr < error) 575 { 576 points[pt] = candidates[bestop]; 577 /* Redraw image if the last check wasn't the best one */ 578 if(bestop != 2) 874 875 #if !DEBUG 876 if(!(iter % 16)) 877 fprintf(stderr, "\rEncoding... %i%%", 878 iter * 100 / MAX_ITERATIONS); 879 #endif 880 881 pipi_image_t *scrap = pipi_copy(tmp); 882 883 /* Choose a point at random */ 884 int pt = det_rand(npoints); 885 uint32_t oldval = points[pt]; 886 887 /* Compute the affected image zone */ 888 float fx, fy, fr, fg, fb, fs; 889 get_point(pt, &fx, &fy, &fr, &fg, &fb, &fs); 890 int zonex = (int)fx / RANGE_X  1; 891 int zoney = (int)fy / RANGE_Y  1; 892 int zonew = 3; 893 int zoneh = 3; 894 if(zonex < 0) { zonex = 0; zonew; } 895 if(zoney < 0) { zoney = 0; zoneh; } 896 if(zonex + zonew >= (int)dw) { zonew; } 897 if(zoney + zoneh >= (int)dh) { zoneh; } 898 899 /* Choose random operations and measure their effect */ 900 uint8_t op1 = rand_op(); 901 //uint8_t op2 = rand_op(); 902 903 uint32_t candidates[3]; 904 double besterr = error + 1.0; 905 int bestop = 1; 906 candidates[0] = apply_op(op1, oldval); 907 //candidates[1] = apply_op(op2, oldval); 908 //candidates[2] = apply_op(op1, apply_op(op2, oldval)); 909 910 for(int i = 0; i < 1; i++) 911 //for(int i = 0; i < 3; i++) 912 { 913 if(oldval == candidates[i]) 914 continue; 915 916 points[pt] = candidates[i]; 917 579 918 render(scrap, zonex * RANGE_X, zoney * RANGE_Y, 580 919 zonew * RANGE_X, zoneh * RANGE_Y); 581 920 582 pipi_free(tmp); 583 tmp = scrap; 584 //fprintf(stderr, "%08i %2.010g %2.010g after op%i(%i)\n", 585 // iter, besterr  error, error, op1, pt); 586 fprintf(stderr, "%08i .%08i %2.010g after op%i(%i)\n", iter, 587 (int)((error  besterr) * 100000000), error, op1, pt); 588 error = besterr; 589 opstats[op1 * 2 + 1]++; 590 //opstats[op2 * 2 + 1]++; 591 failures = 0; 592 success++; 593 594 /* Save image! */ 595 //char buf[128]; 596 //sprintf(buf, "twit%08i.bmp", success); 597 //if((success % 10) == 0) 598 // pipi_save(tmp, buf); 599 } 600 else 601 { 602 pipi_free(scrap); 603 points[pt] = oldval; 604 failures++; 605 } 606 } 607 608 for(int j = 0; j < 2; j++) 609 { 610 fprintf(stderr, "operation: "); 611 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 612 fprintf(stderr, "%4i ", i); 613 fprintf(stderr, "\nattempts: "); 614 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 615 fprintf(stderr, "%4i ", opstats[i * 2]); 616 fprintf(stderr, "\nsuccesses: "); 617 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 618 fprintf(stderr, "%4i ", opstats[i * 2 + 1]); 619 fprintf(stderr, "\n"); 620 } 621 622 fprintf(stderr, "Distance: %2.10g\n", error); 623 624 dst = pipi_resize(tmp, width, height); 625 pipi_free(tmp); 626 627 /* Save image and bail out */ 628 pipi_save(dst, "lol.bmp"); 629 pipi_free(dst); 921 double newerr = pipi_measure_rmsd(src, scrap); 922 if(newerr < besterr) 923 { 924 besterr = newerr; 925 bestop = i; 926 } 927 } 928 929 opstats[op1 * 2]++; 930 //opstats[op2 * 2]++; 931 932 if(besterr < error) 933 { 934 points[pt] = candidates[bestop]; 935 /* Redraw image if the last check wasn't the best one */ 936 if(bestop != 2) 937 render(scrap, zonex * RANGE_X, zoney * RANGE_Y, 938 zonew * RANGE_X, zoneh * RANGE_Y); 939 940 pipi_free(tmp); 941 tmp = scrap; 942 #if DEBUG 943 fprintf(stderr, "%08i .%08i %2.010g after op%i(%i)\n", iter, 944 (int)((error  besterr) * 100000000), error, op1, pt); 945 #endif 946 error = besterr; 947 opstats[op1 * 2 + 1]++; 948 //opstats[op2 * 2 + 1]++; 949 failures = 0; 950 success++; 951 952 /* Save image! */ 953 //char buf[128]; 954 //sprintf(buf, "twit%08i.bmp", success); 955 //if((success % 10) == 0) 956 // pipi_save(tmp, buf); 957 } 958 else 959 { 960 pipi_free(scrap); 961 points[pt] = oldval; 962 failures++; 963 } 964 } 965 966 fprintf(stderr, "\r \r"); 967 968 #if DEBUG 969 for(int j = 0; j < 2; j++) 970 { 971 fprintf(stderr, "operation: "); 972 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 973 fprintf(stderr, "%4i ", i); 974 fprintf(stderr, "\nattempts: "); 975 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 976 fprintf(stderr, "%4i ", opstats[i * 2]); 977 fprintf(stderr, "\nsuccesses: "); 978 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 979 fprintf(stderr, "%4i ", opstats[i * 2 + 1]); 980 fprintf(stderr, "\n"); 981 } 982 983 fprintf(stderr, "Distance: %2.10g\n", error); 984 #endif 985 986 #if 0 987 dst = pipi_resize(tmp, width, height); 988 pipi_free(tmp); 989 990 /* Save image and bail out */ 991 pipi_save(dst, "lol.bmp"); 992 pipi_free(dst); 993 #endif 994 995 /* Push our points to the bitstream */ 996 for(int i = 0; i < npoints; i++) 997 b.push(points[i], RANGE_SYXRGB); 998 b.push(height, MAX_H); 999 b.push(width, MAX_W); 1000 1001 /* Pop Unicode characters from the bitstream and print them */ 1002 for(int i = 0; i < MAX_MSG_LEN; i++) 1003 fwrite_utf8(stdout, index2uni(b.pop(NUM_CHARACTERS))); 1004 fprintf(stdout, "\n"); 1005 } 1006 else 1007 { 1008 /* Pop points from the bitstream */ 1009 for(int i = dw * dh; i; ) 1010 { 1011 #if POINTS_PER_CELL == 2 1012 points[i * 2 + 1] = b.pop(RANGE_SYXRGB); 1013 points[i * 2] = b.pop(RANGE_SYXRGB); 1014 #else 1015 points[i] = b.pop(RANGE_SYXRGB); 1016 #endif 1017 } 1018 npoints = dw * dh * POINTS_PER_CELL; 1019 1020 /* Render these points to a new image */ 1021 tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y); 1022 render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y); 1023 1024 /* TODO: render directly to the final image; scaling sucks */ 1025 dst = pipi_resize(tmp, width, height); 1026 pipi_free(tmp); 1027 1028 /* Save image and bail out */ 1029 pipi_save(dst, argv[2]); 1030 pipi_free(dst); 1031 } 630 1032 631 1033 return ret;
Note: See TracChangeset
for help on using the changeset viewer.