Sfoglia il codice sorgente

Make img2twit message length configurable at runtime, improve the initial

guess by smoothing hard colour gradients, and fixed the bitstack copy
constructor to avoid corruption on exit.

git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@3523 92316355-f0b4-4df1-b90c-862c8a59935f
master
sam 15 anni fa
parent
commit
901c4cd590
1 ha cambiato i file con 73 aggiunte e 32 eliminazioni
  1. +73
    -32
      examples/img2twit.cpp

+ 73
- 32
examples/img2twit.cpp Vedi File

@@ -1,3 +1,15 @@
/*
* img2twit Image to short text message encoder/decoder
* Copyright (c) 2009 Sam Hocevar <sam@hocevar.net>
* All Rights Reserved
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

#include "config.h"

#include <stdio.h>
@@ -56,6 +68,19 @@ static const uint32_t unichars[] =
/* How does the algorithm work: one point per cell, or two */
#define POINTS_PER_CELL 2

/*
* These values can be overwritten at runtime
*/

/* Debug mode */
static bool DEBUG_MODE = false;

/* The maximum message length */
static int MAX_MSG_LEN = 140;

/* Iterations per point -- larger means slower but nicer */
static int ITERATIONS_PER_POINT = 50;

/* 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
@@ -70,17 +95,6 @@ static unsigned int RANGE_G = 6;
static unsigned int RANGE_B = 6;
static unsigned int RANGE_S = 1;

/*
* These values can be overwritten at runtime
*/

static bool DEBUG = false;

/* The maximum message length */
static int MAX_MSG_LEN = 1140;

static int ITERATIONS_PER_POINT = 50;

/*
* These values are computed at runtime
*/
@@ -273,6 +287,13 @@ public:
private:
bitstack(uint32_t i) { alloc(); init(i); }

bitstack(bitstack &b)
{
alloc();
msb = b.msb;
memcpy(digits, b.digits, (MAX_MSG_LEN + 1) * sizeof(uint32_t));
}

bitstack(bitstack const &b)
{
alloc();
@@ -686,7 +707,7 @@ static void analyse(pipi_image_t *src)
for(unsigned int dy = 0; dy < dh; dy++)
for(unsigned int dx = 0; dx < dw; dx++)
{
float min = 1.1f, max = -0.1f;
float min = 1.1f, max = -0.1f, mr = 0.0f, mg = 0.0f, mb = 0.0f;
float total = 0.0;
int xmin = 0, xmax = 0, ymin = 0, ymax = 0;
int npixels = 0;
@@ -699,6 +720,11 @@ static void analyse(pipi_image_t *src)
lum += data[4 * (ix + iy * p->w) + 0];
lum += data[4 * (ix + iy * p->w) + 1];
lum += data[4 * (ix + iy * p->w) + 2];
lum /= 3;

mr += data[4 * (ix + iy * p->w) + 0];
mg += data[4 * (ix + iy * p->w) + 1];
mb += data[4 * (ix + iy * p->w) + 2];

if(lum < min)
{
@@ -719,6 +745,9 @@ static void analyse(pipi_image_t *src)
}

total /= npixels;
mr /= npixels;
mg /= npixels;
mb /= npixels;

float wmin, wmax;

@@ -730,17 +759,19 @@ static void analyse(pipi_image_t *src)
wmin = 0.0, wmax = 1.0;

#if 0
add_random_point();
add_random_point();
add_random_point();
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],
data[4 * (xmin + ymin * p->w) + 1],
data[4 * (xmin + ymin * p->w) + 2],
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
}
@@ -748,9 +779,9 @@ add_random_point();
{
#endif
add_point(xmax, ymax,
data[4 * (xmax + ymax * p->w) + 0],
data[4 * (xmax + ymax * p->w) + 1],
data[4 * (xmax + ymax * p->w) + 2],
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
}
@@ -764,7 +795,6 @@ add_random_point();
int main(int argc, char *argv[])
{
int opstats[2 * NB_OPS];
bitstack b;
char const *srcname = NULL, *dstname = NULL;
pipi_image_t *src, *tmp, *dst;
double error = 1.0;
@@ -777,12 +807,13 @@ int main(int argc, char *argv[])
static struct myoption long_options[] =
{
{ "output", 1, NULL, 'o' },
{ "length", 1, NULL, 'l' },
{ "quality", 1, NULL, 'q' },
{ "debug", 0, NULL, 'd' },
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
int c = mygetopt(argc, argv, "o:q:dh", long_options, &option_index);
int c = mygetopt(argc, argv, "o:l:q:dh", long_options, &option_index);

if(c == -1)
break;
@@ -792,15 +823,23 @@ int main(int argc, char *argv[])
case 'o':
dstname = myoptarg;
break;
case 'l':
MAX_MSG_LEN = atoi(myoptarg);
if(MAX_MSG_LEN < 16)
{
fprintf(stderr, "Warning: rounding minimum message length to 16\n");
MAX_MSG_LEN = 16;
}
break;
case 'q':
ITERATIONS_PER_POINT = 10 * atoi(myoptarg);
if(ITERATIONS_PER_POINT < 0)
ITERATIONS_PER_POINT = 0;
else if(ITERATIONS_PER_POINT > 10)
ITERATIONS_PER_POINT = 10;
else if(ITERATIONS_PER_POINT > 100)
ITERATIONS_PER_POINT = 100;
break;
case 'd':
DEBUG = true;
DEBUG_MODE = true;
break;
case 'h':
printf("Usage: img2twit [OPTIONS] SOURCE\n");
@@ -809,6 +848,7 @@ int main(int argc, char *argv[])
printf("\n");
printf("Mandatory arguments to long options are mandatory for short options too.\n");
printf(" -o, --output <filename> output resulting image to filename\n");
printf(" -l, --length <size> message length in characters (default 140)\n");
printf(" -q, --quality <rate> set image quality (0 - 10) (default 5)\n");
printf(" -d, --debug print debug information\n");
printf(" -h, --help display this help and exit\n");
@@ -858,6 +898,9 @@ int main(int argc, char *argv[])
TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS);
MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS;

bitstack b; /* We cannot declare this before, because MAX_MSG_LEN
* wouldn't be defined. */

if(dstname)
{
/* Decoding mode: read UTF-8 text from stdin, find each
@@ -909,7 +952,7 @@ int main(int argc, char *argv[])
while(dw * (dh + 1) <= TOTAL_CELLS) dw++;

/* Print debug information */
if(DEBUG)
if(DEBUG_MODE)
{
fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN);
fprintf(stderr, "Available characters: %i\n", NUM_CHARACTERS);
@@ -935,7 +978,6 @@ int main(int argc, char *argv[])
pipi_free(src);
src = pipi_median_ext(tmp, 1, 1);
pipi_free(tmp);
pipi_save(src, "lol.bmp");

/* Analyse image */
analyse(src);
@@ -943,10 +985,9 @@ pipi_save(src, "lol.bmp");
/* Render what we just computed */
tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y);
render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y);
pipi_save(tmp, "lol2.bmp");
error = pipi_measure_rmsd(src, tmp);

if(DEBUG)
if(DEBUG_MODE)
fprintf(stderr, "Initial distance: %2.10g\n", error);

memset(opstats, 0, sizeof(opstats));
@@ -960,7 +1001,7 @@ pipi_save(tmp, "lol2.bmp");
failures = 0;
}

if(!DEBUG && !(iter % 16))
if(!DEBUG_MODE && !(iter % 16))
fprintf(stderr, "\rEncoding... %i%%",
iter * 100 / MAX_ITERATIONS);

@@ -1026,7 +1067,7 @@ pipi_save(tmp, "lol2.bmp");
pipi_free(tmp);
tmp = scrap;

if(DEBUG)
if(DEBUG_MODE)
fprintf(stderr, "%08i -.%08i %2.010g after op%i(%i)\n",
iter, (int)((error - besterr) * 100000000), error,
op1, pt);
@@ -1051,7 +1092,7 @@ pipi_save(tmp, "lol2.bmp");
}
}

if(DEBUG)
if(DEBUG_MODE)
{
for(int j = 0; j < 2; j++)
{


Caricamento…
Annulla
Salva