diff --git a/examples/img2twit.cpp b/examples/img2twit.cpp index e97328a..ba24b03 100644 --- a/examples/img2twit.cpp +++ b/examples/img2twit.cpp @@ -71,10 +71,6 @@ static const uint32_t *unichars; #define RANGE_H 2000 #define RANGE_V 10 -/* How does the algorithm work: one point per cell, or two? XXX: changing - * this value breaks compatibility with other images. */ -#define POINTS_PER_CELL 2 - /* Start with a random image (1), or with a good estimate (0)? */ #define RANDOM_START 0 @@ -91,6 +87,9 @@ static int MAX_MSG_LEN = 140; /* Iterations per point -- larger means slower but nicer */ static int ITERATIONS_PER_POINT = 50; +/* Points per cell -- 1 allows to put more cells, but 2 gives better results */ +static int POINTS_PER_CELL = 2; + /* The range value for point parameters: X Y, red/green/blue, "strength" * Tested values (on Mona Lisa) are: * 16 16 5 5 5 2 -> 0.06511725914 @@ -153,12 +152,16 @@ void compute_ranges(int width, int height) TOTAL_BITS = MAX_MSG_LEN * logf(NUM_CHARACTERS) / logf(2); HEADER_BITS = logf(RANGE_W * RANGE_H * RANGE_V) / logf(2); DATA_BITS = TOTAL_BITS - HEADER_BITS; -#if POINTS_PER_CELL == 2 - CELL_BITS = (2 * logf(RANGE_SBGR) + logf(RANGE_XY2)) / logf(2); - //CELL_BITS = 2 * logf(RANGE_SBGRXY) / logf(2); -#else - CELL_BITS = logf(RANGE_SBGRXY) / logf(2); -#endif + if(version == 0) + { + POINTS_PER_CELL = 1; + CELL_BITS = logf(RANGE_SBGRXY) / logf(2); + } + else if(version == 1) + { + POINTS_PER_CELL = 2; + CELL_BITS = (2 * logf(RANGE_SBGR) + logf(RANGE_XY2)) / logf(2); + } TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS); MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS; @@ -839,35 +842,24 @@ static void analyse(pipi_image_t *src) wmin = 0.0, wmax = 1.0; #if RANDOM_START == 1 -# if POINTS_PER_CELL == 2 - add_random_point(); -# endif - add_random_point(); + for(int i = 0; i < POINTS_PER_CELL; i++) + add_random_point(); #else /* 0.80 and 0.20 were chosen empirically, it gives a 10% better * initial distance. Definitely worth it. */ -# if POINTS_PER_CELL == 1 - if(total < min + (max - min) / 2) - { -# endif - add_point(xmin, ymin, - data[4 * (xmin + ymin * p->w) + 0] * 0.80 + mr * 0.20, - data[4 * (xmin + ymin * p->w) + 1] * 0.80 + mg * 0.20, - data[4 * (xmin + ymin * p->w) + 2] * 0.80 + mb * 0.20, - wmin); -# if POINTS_PER_CELL == 1 - } - else - { -# endif - add_point(xmax, ymax, - data[4 * (xmax + ymax * p->w) + 0] * 0.80 + mr * 0.20, - data[4 * (xmax + ymax * p->w) + 1] * 0.80 + mg * 0.20, - data[4 * (xmax + ymax * p->w) + 2] * 0.80 + mb * 0.20, - wmax); -# if POINTS_PER_CELL == 1 - } -# endif + if(POINTS_PER_CELL == 2 || total < min + (max - min) / 2) + add_point(xmin, ymin, + data[4 * (xmin + ymin * p->w) + 0] * 0.80 + mr * 0.20, + data[4 * (xmin + ymin * p->w) + 1] * 0.80 + mg * 0.20, + data[4 * (xmin + ymin * p->w) + 2] * 0.80 + mb * 0.20, + wmin); + + if(POINTS_PER_CELL == 2 || total >= min + (max - min) / 2) + add_point(xmax, ymax, + data[4 * (xmax + ymax * p->w) + 0] * 0.80 + mr * 0.20, + data[4 * (xmax + ymax * p->w) + 1] * 0.80 + mg * 0.20, + data[4 * (xmax + ymax * p->w) + 2] * 0.80 + mb * 0.20, + wmax); #endif } } @@ -1052,6 +1044,13 @@ int main(int argc, char *argv[]) /* The first thing we pop from the stream is the version information */ version = b.pop(RANGE_V); + if(version > 1) + { + fprintf(stderr, "Error: unsupported algorithm version %i\n", + version); + return EXIT_FAILURE; + } + /* Read width and height from bitstream */ width = b.pop(RANGE_W) + 1; height = b.pop(RANGE_H) + 1; @@ -1080,12 +1079,6 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - if(version > 1) - { - fprintf(stderr, "Error: unsupported algorithm version %i\n", version); - return EXIT_FAILURE; - } - compute_ranges(width, height); /* Try to cram some more information into our points as long as it @@ -1147,7 +1140,7 @@ int main(int argc, char *argv[]) if(srcname) { /* Resize and filter image to better state */ - tmp = pipi_gaussian_blur(src, 0.5 * dw * RANGE_X / width); + tmp = pipi_gaussian_blur(src, 0.25 * dw * RANGE_X / width); pipi_free(src); src = pipi_resize(tmp, dw * RANGE_X, dh * RANGE_Y); pipi_free(tmp); @@ -1202,16 +1195,17 @@ int main(int argc, char *argv[]) apply_op(op1, &points[pt]); -#if POINTS_PER_CELL == 2 /* Check that two points don't fall at the same place */ - while(points[pt].x == points[pt ^ 1].x - && points[pt].y == points[pt ^ 1].y) + if(POINTS_PER_CELL == 2) { - points[pt] = oldpt; - op1 = rand_op(); - apply_op(op1, &points[pt]); + while(points[pt].x == points[pt ^ 1].x + && points[pt].y == points[pt ^ 1].y) + { + points[pt] = oldpt; + op1 = rand_op(); + apply_op(op1, &points[pt]); + } } -#endif render(scrap, zonex * RANGE_X, zoney * RANGE_Y, zonew * RANGE_X, zoneh * RANGE_Y, false); @@ -1280,7 +1274,7 @@ int main(int argc, char *argv[]) else fprintf(stderr, "\r \r"); -#if 1 +#if 0 dst = pipi_resize(tmp, width, height); pipi_free(tmp); @@ -1292,33 +1286,36 @@ int main(int argc, char *argv[]) /* Push our points to the bitstream */ for(int i = 0; i < npoints; i += POINTS_PER_CELL) { -#if POINTS_PER_CELL == 2 - int x1, y1, x2, y2; - x1 = points[i].x; - y1 = points[i].y; - x2 = points[i + 1].x; - y2 = points[i + 1].y; - - bool swap; - uint32_t pack = pack_coords(x1, y1, x2, y2, &swap); - - b.push(points[i + (swap ? 1 : 0)].s, RANGE_S); - b.push(points[i + (swap ? 1 : 0)].b, RANGE_B); - b.push(points[i + (swap ? 1 : 0)].g, RANGE_G); - b.push(points[i + (swap ? 1 : 0)].r, RANGE_R); - b.push(points[i + (swap ? 0 : 1)].s, RANGE_S); - b.push(points[i + (swap ? 0 : 1)].b, RANGE_B); - b.push(points[i + (swap ? 0 : 1)].g, RANGE_G); - b.push(points[i + (swap ? 0 : 1)].r, RANGE_R); - b.push(pack, RANGE_XY2); -#else - b.push(points[i].s, RANGE_S); - b.push(points[i].b, RANGE_B); - b.push(points[i].g, RANGE_G); - b.push(points[i].r, RANGE_R); - b.push(points[i].x, RANGE_X); - b.push(points[i].y, RANGE_Y); -#endif + if(POINTS_PER_CELL == 2) + { + int x1, y1, x2, y2; + x1 = points[i].x; + y1 = points[i].y; + x2 = points[i + 1].x; + y2 = points[i + 1].y; + + bool swap; + uint32_t pack = pack_coords(x1, y1, x2, y2, &swap); + + b.push(points[i + (swap ? 1 : 0)].s, RANGE_S); + b.push(points[i + (swap ? 1 : 0)].b, RANGE_B); + b.push(points[i + (swap ? 1 : 0)].g, RANGE_G); + b.push(points[i + (swap ? 1 : 0)].r, RANGE_R); + b.push(points[i + (swap ? 0 : 1)].s, RANGE_S); + b.push(points[i + (swap ? 0 : 1)].b, RANGE_B); + b.push(points[i + (swap ? 0 : 1)].g, RANGE_G); + b.push(points[i + (swap ? 0 : 1)].r, RANGE_R); + b.push(pack, RANGE_XY2); + } + else + { + b.push(points[i].s, RANGE_S); + b.push(points[i].b, RANGE_B); + b.push(points[i].g, RANGE_G); + b.push(points[i].r, RANGE_R); + b.push(points[i].x, RANGE_X); + b.push(points[i].y, RANGE_Y); + } } b.push(height - 1, RANGE_H); b.push(width - 1, RANGE_W); @@ -1334,31 +1331,34 @@ int main(int argc, char *argv[]) /* Pop points from the bitstream */ for(int i = dw * dh; i--; ) { -#if POINTS_PER_CELL == 2 - uint32_t pack = b.pop(RANGE_XY2); - int x1, y1, x2, y2; - unpack_coords(pack, &x1, &y1, &x2, &y2); - - points[i * 2 + 1].y = y2; - points[i * 2 + 1].x = x2; - points[i * 2 + 1].r = b.pop(RANGE_R); - points[i * 2 + 1].g = b.pop(RANGE_G); - points[i * 2 + 1].b = b.pop(RANGE_B); - points[i * 2 + 1].s = b.pop(RANGE_S); - points[i * 2].y = y1; - points[i * 2].x = x1; - points[i * 2].r = b.pop(RANGE_R); - points[i * 2].g = b.pop(RANGE_G); - points[i * 2].b = b.pop(RANGE_B); - points[i * 2].s = b.pop(RANGE_S); -#else - points[i].y = b.pop(RANGE_Y); - points[i].x = b.pop(RANGE_X); - points[i].r = b.pop(RANGE_R); - points[i].g = b.pop(RANGE_G); - points[i].b = b.pop(RANGE_B); - points[i].s = b.pop(RANGE_S); -#endif + if(POINTS_PER_CELL == 2) + { + uint32_t pack = b.pop(RANGE_XY2); + int x1, y1, x2, y2; + unpack_coords(pack, &x1, &y1, &x2, &y2); + + points[i * 2 + 1].y = y2; + points[i * 2 + 1].x = x2; + points[i * 2 + 1].r = b.pop(RANGE_R); + points[i * 2 + 1].g = b.pop(RANGE_G); + points[i * 2 + 1].b = b.pop(RANGE_B); + points[i * 2 + 1].s = b.pop(RANGE_S); + points[i * 2].y = y1; + points[i * 2].x = x1; + points[i * 2].r = b.pop(RANGE_R); + points[i * 2].g = b.pop(RANGE_G); + points[i * 2].b = b.pop(RANGE_B); + points[i * 2].s = b.pop(RANGE_S); + } + else + { + points[i].y = b.pop(RANGE_Y); + points[i].x = b.pop(RANGE_X); + points[i].r = b.pop(RANGE_R); + points[i].g = b.pop(RANGE_G); + points[i].b = b.pop(RANGE_B); + points[i].s = b.pop(RANGE_S); + } } npoints = dw * dh * POINTS_PER_CELL;