Просмотр исходного кода

Optimise img2twit's cell packing even more, gaining around 60 bits.

git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@3536 92316355-f0b4-4df1-b90c-862c8a59935f
master
sam 15 лет назад
Родитель
Сommit
470a28b96b
1 измененных файлов: 77 добавлений и 56 удалений
  1. +77
    -56
      examples/img2twit.cpp

+ 77
- 56
examples/img2twit.cpp Просмотреть файл

@@ -74,6 +74,9 @@ static const uint32_t *unichars;
* 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

/*
* These values can be overwritten at runtime
*/
@@ -115,8 +118,7 @@ static int MAX_ITERATIONS;
static unsigned int TOTAL_CELLS;

#define RANGE_XY (RANGE_Y*RANGE_X)
#define RANGE_XYXY (RANGE_XY*RANGE_XY)
//#define RANGE_XYXY (RANGE_Y*RANGE_X*(RANGE_Y*RANGE_X+1)/2)
#define RANGE_XY2 (RANGE_Y*RANGE_X*(RANGE_Y*RANGE_X+1)/2)
#define RANGE_RXY (RANGE_Y*RANGE_X*RANGE_R)
#define RANGE_GRXY (RANGE_Y*RANGE_X*RANGE_R*RANGE_G)
#define RANGE_BGRXY (RANGE_Y*RANGE_X*RANGE_R*RANGE_G*RANGE_B)
@@ -146,14 +148,11 @@ void compute_ranges(int width, int height)
TOTAL_BITS = MAX_MSG_LEN * logf(NUM_CHARACTERS) / logf(2);
HEADER_BITS = logf(RANGE_W * RANGE_H) / logf(2);
DATA_BITS = TOTAL_BITS - HEADER_BITS;
#if POINTS_PER_CELL == 1
CELL_BITS = logf(RANGE_SBGRXY) / logf(2);
#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
// TODO: implement the following shit
//float coord_bits = logf((RANGE_Y * RANGE_X) * (RANGE_Y * RANGE_X + 1) / 2);
//float other_bits = logf(RANGE_R * RANGE_G * RANGE_B * RANGE_S);
//CELL_BITS = (coord_bits + 2 * other_bits) / logf(2);
CELL_BITS = 2 * logf(RANGE_SBGRXY) / logf(2);
CELL_BITS = logf(RANGE_SBGRXY) / logf(2);
#endif
TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS);
MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS;
@@ -508,17 +507,17 @@ static inline void set_point(int index, float x, float y, float r,
float fx = (x - dx * RANGE_X) / RANGE_X;
float fy = (y - dy * RANGE_Y) / RANGE_Y;

int is = range2int(s, RANGE_S);

int ix = range2int(fx, RANGE_X);
int iy = range2int(fy, RANGE_Y);
int ix = range2int(fx, RANGE_X);

int ir = range2int(r, RANGE_R);
int ig = range2int(g, RANGE_G);
int ib = range2int(b, RANGE_B);

points[index] = iy + RANGE_Y * (ix + RANGE_X * (ib + RANGE_B *
(ig + (RANGE_R * ir + (RANGE_S * is)))));
int is = range2int(s, RANGE_S);

points[index] = iy + RANGE_Y * (ix + RANGE_X * (ir + RANGE_R *
(ig + (RANGE_G * ib + (RANGE_B * is)))));
}

static inline void get_point(int index, float *x, float *y, float *r,
@@ -532,20 +531,20 @@ static inline void get_point(int index, float *x, float *y, float *r,
float fy = int2midrange(pt % RANGE_Y, RANGE_Y); pt /= RANGE_Y;
float fx = int2midrange(pt % RANGE_X, RANGE_X); pt /= RANGE_X;

*x = (fx + dx) * RANGE_X /*+ 0.5 * (index & 1)*/;
*y = (fy + dy) * RANGE_Y /*+ 0.5 * (index & 1)*/;
*x = (fx + dx) * RANGE_X /*+ 0.5 * (index & 1)*/;

if(final)
{
*b = int2fullrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
*r = int2fullrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
*g = int2fullrange(pt % RANGE_G, RANGE_G); pt /= RANGE_G;
*r = int2fullrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B;
*b = int2fullrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B;
}
else
{
*b = int2midrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
*r = int2midrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
*g = int2midrange(pt % RANGE_G, RANGE_G); pt /= RANGE_G;
*r = int2midrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B;
*b = int2midrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B;
}

*s = int2fullrange(pt % RANGE_S, RANGE_S); pt /= RANGE_S;
@@ -557,20 +556,37 @@ static void add_point(float x, float y, float r, float g, float b, float s)
npoints++;
}

static uint32_t pack_coords(int x1, int y1, int x2, int y2)
static uint32_t pack_coords(int x1, int y1, int x2, int y2, bool *swap)
{
return ((y2 * RANGE_X + x2) * RANGE_Y + y1) * RANGE_X + x1;
int k1 = y1 * RANGE_X + x1;
int k2 = y2 * RANGE_X + x2;

/* XXX: this should not happen */
if(k1 == k2)
k1 += (x1 > 0 ? -1 : 1);

*swap = k1 > k2;

if(*swap)
{
int tmp = k1; k1 = k2; k2 = tmp;
}

return k2 * (k2 + 1) / 2 + k1;
}

static void unpack_coords(uint32_t pack, int *x1, int *y1, int *x2, int *y2)
{
*x1 = pack % RANGE_X; pack /= RANGE_X;
*y1 = pack % RANGE_Y; pack /= RANGE_Y;
*x2 = pack % RANGE_X; pack /= RANGE_X;
*y2 = pack % RANGE_Y;
int k2 = ((int)sqrt(1.0 + 8 * pack) - 1) / 2;
int k1 = pack - k2 * (k2 + 1) / 2;

*x1 = k1 % RANGE_X;
*y1 = k1 / RANGE_X;
*x2 = k2 % RANGE_X;
*y2 = k2 / RANGE_X;
}

#if 0
#if RANDOM_START == 1
static void add_random_point()
{
points[npoints] = det_rand(RANGE_SBGRXY);
@@ -845,34 +861,36 @@ static void analyse(pipi_image_t *src)
else
wmin = 0.0, wmax = 1.0;

#if 0
#if RANDOM_START == 1
# if POINTS_PER_CELL == 2
add_random_point();
# endif
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 POINTS_PER_CELL == 1
if(total < min + (max - min) / 2)
{
#endif
# 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
# if POINTS_PER_CELL == 1
}
else
{
#endif
# 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
# if POINTS_PER_CELL == 1
}
#endif
# endif
#endif
}
}
@@ -938,8 +956,8 @@ int main(int argc, char *argv[])
ITERATIONS_PER_POINT = 10 * atof(myoptarg);
if(ITERATIONS_PER_POINT < 0)
ITERATIONS_PER_POINT = 0;
else if(ITERATIONS_PER_POINT > 100)
ITERATIONS_PER_POINT = 100;
else if(ITERATIONS_PER_POINT > 200)
ITERATIONS_PER_POINT = 200;
break;
case 'd':
DEBUG_MODE = true;
@@ -953,7 +971,7 @@ int main(int argc, char *argv[])
printf(" -o, --output <filename> output resulting image to filename\n");
printf(" -l, --length <size> message length in characters (default 140)\n");
printf(" -c, --charset <block> character set to use (ascii, [cjk], symbols)\n");
printf(" -q, --quality <rate> set image quality (0 - 10) (default 5)\n");
printf(" -q, --quality <rate> set image quality (0 - 20) (default 5)\n");
printf(" -d, --debug print debug information\n");
printf(" -h, --help display this help and exit\n");
printf("\n");
@@ -1095,7 +1113,7 @@ int main(int argc, char *argv[])
{ revert; compute_ranges(width, height); } \
} while(0)

for(int i = 0; i < 5; i++)
for(int i = 0; i < 2; i++)
{
TRY(RANGE_G++, RANGE_G--);
TRY(RANGE_R++, RANGE_R--);
@@ -1141,9 +1159,9 @@ int main(int argc, char *argv[])
if(srcname)
{
/* Resize and filter image to better state */
tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y);
tmp = pipi_gaussian_blur(src, 0.5 * dw * RANGE_X / width);
pipi_free(src);
src = pipi_median_ext(tmp, 1, 1);
src = pipi_resize(tmp, dw * RANGE_X, dh * RANGE_Y);
pipi_free(tmp);

/* Analyse image */
@@ -1181,14 +1199,14 @@ int main(int argc, char *argv[])
/* Compute the affected image zone */
float fx, fy, fr, fg, fb, fs;
get_point(pt, &fx, &fy, &fr, &fg, &fb, &fs);
int zonex = (int)fx / RANGE_X - 1;
int zoney = (int)fy / RANGE_Y - 1;
int zonew = 3;
int zoneh = 3;
if(zonex < 0) { zonex = 0; zonew--; }
if(zoney < 0) { zoney = 0; zoneh--; }
if(zonex + zonew >= (int)dw) { zonew--; }
if(zoney + zoneh >= (int)dh) { zoneh--; }
int zonex = (int)fx / RANGE_X - 2;
int zoney = (int)fy / RANGE_Y - 2;
int zonew = 4;
int zoneh = 4;
if(zonex < 0) { zonew += zonex; zonex = 0; }
if(zoney < 0) { zoneh += zoney; zoney = 0;; }
if(zonex + zonew > (int)dw) { zonew = dw - zonex; }
if(zoney + zoneh > (int)dh) { zoneh = dh - zoney; }

/* Choose random operations and measure their effect */
uint8_t op1 = rand_op();
@@ -1246,10 +1264,10 @@ int main(int argc, char *argv[])
success++;

/* Save image! */
//char buf[128];
//sprintf(buf, "twit%08i.bmp", success);
//if((success % 10) == 0)
// pipi_save(tmp, buf);
char buf[128];
sprintf(buf, "twit%08i.bmp", success);
if((success % 10) == 0)
pipi_save(tmp, buf);
}
else
{
@@ -1298,11 +1316,13 @@ int main(int argc, char *argv[])
y1 = points[i] % RANGE_Y;
x2 = (points[i + 1] / RANGE_Y) % RANGE_X;
y2 = points[i + 1] % RANGE_Y;
uint32_t pack = pack_coords(x1, y1, x2, y2);

b.push(points[i] / RANGE_XY, RANGE_SBGR);
b.push(points[i + 1] / RANGE_XY, RANGE_SBGR);
b.push(pack, RANGE_XYXY);
bool swap;
uint32_t pack = pack_coords(x1, y1, x2, y2, &swap);

b.push(points[i + (swap ? 1 : 0)] / RANGE_XY, RANGE_SBGR);
b.push(points[i + (swap ? 0 : 1)] / RANGE_XY, RANGE_SBGR);
b.push(pack, RANGE_XY2);
#else
b.push(points[i], RANGE_SBGRXY);
#endif
@@ -1321,10 +1341,11 @@ int main(int argc, char *argv[])
for(int i = dw * dh; i--; )
{
#if POINTS_PER_CELL == 2
uint32_t pack = b.pop(RANGE_XYXY);
uint32_t pack = b.pop(RANGE_XY2);
uint32_t p2 = b.pop(RANGE_SBGR);
uint32_t p1 = b.pop(RANGE_SBGR);
int x1, y1, x2, y2;

unpack_coords(pack, &x1, &y1, &x2, &y2);
points[i * 2] = p1 * RANGE_XY + x1 * RANGE_Y + y1;
points[i * 2 + 1] = p2 * RANGE_XY + x2 * RANGE_Y + y2;


Загрузка…
Отмена
Сохранить