Ignore:
Timestamp:
May 25, 2009, 2:16:56 AM (11 years ago)
Author:
Sam Hocevar
Message:

Make img2twit more configurable: iterations per second and debug mode can
now be chosen at runtime. Message length will soon be.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libpipi/trunk/examples/img2twit.cpp

    r3521 r3522  
    1212#include <pipi.h>
    1313
     14#include "../genethumb/mygetopt.h"
     15
    1416/*
    1517 * User-definable settings.
    1618 */
    1719
    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 
    24 /* The maximum message length */
    25 #define MAX_MSG_LEN 140
    26 
    2720/* The Unicode characters at disposal - XXX: must be _ordered_ */
    2821static const uint32_t unichars[] =
    2922{
    3023    /* Printable ASCII (except space) */
    31     0x0021, 0x007f,
     24    //0x0021, 0x007f,
    3225
    3326    /* Stupid symbols and Dingbats shit */
     
    4235    //0x2f00, 0x2fd6, /* Kangxi Radicals */
    4336    //0x3400, 0x4db6, /* CJK Unified Ideographs Extension A */
    44     //0x4e00, 0x9fa6, /* CJK Unified Ideographs */
     37    0x4e00, 0x9fa6, /* CJK Unified Ideographs */
    4538
    4639    /* Korean - most people don't know the difference anyway */
    47     0xac00, 0xd7a4, /* Hangul Syllables */
     40    //0xac00, 0xd7a4, /* Hangul Syllables */
    4841
    4942    /* More Chinese */
     
    7972
    8073/*
     74 * These values can be overwritten at runtime
     75 */
     76
     77static bool DEBUG = false;
     78
     79/* The maximum message length */
     80static int MAX_MSG_LEN = 1140;
     81
     82static int ITERATIONS_PER_POINT = 50;
     83
     84/*
    8185 * These values are computed at runtime
    8286 */
     
    8892
    8993static int NUM_CHARACTERS;
     94static int MAX_ITERATIONS;
    9095static unsigned int TOTAL_CELLS;
    9196
     
    104109
    105110/* Global point encoding */
    106 static uint32_t points[1024];
     111static uint32_t points[4096]; /* FIXME: allocate this dynamically */
    107112static int npoints = 0;
    108113
     
    226231{
    227232public:
    228     bitstack() { init(0); }
     233    bitstack() { alloc(); init(0); }
     234
     235    ~bitstack() { delete[] digits; delete[] str; }
    229236
    230237    char const *tostring()
     
    265272
    266273private:
    267     bitstack(uint32_t i) { init(i); }
     274    bitstack(uint32_t i) { alloc(); init(i); }
     275
     276    bitstack(bitstack const &b)
     277    {
     278        alloc();
     279        msb = b.msb;
     280        memcpy(digits, b.digits, (MAX_MSG_LEN + 1) * sizeof(uint32_t));
     281    }
     282
     283    void alloc()
     284    {
     285        digits = new uint32_t[MAX_MSG_LEN + 1];
     286        str = new char[(MAX_MSG_LEN + 1) * 8 + 1];
     287    }
    268288
    269289    void init(uint32_t i)
    270290    {
    271         memset(digits, 0, sizeof(digits));
     291        msb = 0;
     292        memset(digits, 0, (MAX_MSG_LEN + 1) * sizeof(uint32_t));
    272293        digits[0] = i;
    273         msb = 0;
    274294    }
    275295
     
    281301    {
    282302        /* Copy the operand in case we get added to ourselves */
    283         bitstack b = _b;
     303        bitstack b(_b);
    284304        uint64_t x = 0;
    285305
     
    305325    {
    306326        /* Copy the operand in case we get substracted from ourselves */
    307         bitstack b = _b;
     327        bitstack b(_b);
    308328        uint64_t x = 0;
    309329
     
    338358    void mul(uint32_t x)
    339359    {
    340         bitstack b = *this;
     360        bitstack b(*this);
    341361        init(0);
    342362
     
    352372    uint32_t div(uint32_t x)
    353373    {
    354         bitstack b = *this;
     374        bitstack b(*this);
    355375
    356376        for(int i = msb; i >= 0; i--)
     
    370390
    371391    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];
     392    uint32_t *digits;
     393    char *str;
    374394};
    375395
     
    436456    float fx = int2midrange(pt % RANGE_X, RANGE_X); pt /= RANGE_X;
    437457
    438     *x = (fx + dx) * RANGE_X;
    439     *y = (fy + dy) * RANGE_Y;
     458    *x = (fx + dx) * RANGE_X /*+ 0.5 * (index & 1)*/;
     459    *y = (fy + dy) * RANGE_Y /*+ 0.5 * (index & 1)*/;
    440460
    441461    *b = int2midrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
     
    586606static void render(pipi_image_t *dst, int rx, int ry, int rw, int rh)
    587607{
    588     uint8_t lookup[TOTAL_CELLS * RANGE_X * RANGE_Y];
     608    int lookup[dw * RANGE_X * 2 * dh * RANGE_Y * 2];
    589609    pipi_pixels_t *p = pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
    590610    float *data = (float *)p->pixels;
    591     int i, x, y;
     611    int x, y;
    592612
    593613    memset(lookup, 0, sizeof(lookup));
    594614    dt.clear();
    595     for(i = 0; i < npoints; i++)
     615    for(int i = 0; i < npoints; i++)
    596616    {
    597617        float fx, fy, fr, fg, fb, fs;
    598618        get_point(i, &fx, &fy, &fr, &fg, &fb, &fs);
    599         lookup[(int)fx + dw * RANGE_X * (int)fy] = i; /* Keep link to point */
    600619        dt.insert(K::Point_2(fx, fy));
     620        /* Keep link to point */
     621        lookup[(int)(fx * 2) + dw * RANGE_X * 2 * (int)(fy * 2)] = i;
    601622    }
    602623
     
    619640                                                   std::back_inserter(coords));
    620641
    621             float r = 0.0f, g = 0.0f, b = 0.0f, norm = 0.0f;
     642            float r = 0.0f, g = 0.0f, b = 0.0f, norm = 0.000000000000001f;
    622643
    623644            Point_coordinate_vector::iterator it;
     
    632653                    continue;
    633654
    634                 int index = lookup[(int)fx + dw * RANGE_X * (int)fy];
     655                int index = lookup[(int)(fx * 2)
     656                                    + dw * RANGE_X * 2 * (int)(fy * 2)];
    635657
    636658                get_point(index, &fx, &fy, &fr, &fg, &fb, &fs);
     
    738760}
    739761
     762#define MOREINFO "Try `%s --help' for more information.\n"
     763
    740764int main(int argc, char *argv[])
    741765{
    742766    int opstats[2 * NB_OPS];
    743767    bitstack b;
     768    char const *srcname = NULL, *dstname = NULL;
    744769    pipi_image_t *src, *tmp, *dst;
    745770    double error = 1.0;
    746771    int width, height, ret = 0;
    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");
     772
     773    /* Parse command-line options */
     774    for(;;)
     775    {
     776        int option_index = 0;
     777        static struct myoption long_options[] =
     778        {
     779            { "output",      1, NULL, 'o' },
     780            { "quality",     1, NULL, 'q' },
     781            { "debug",       0, NULL, 'd' },
     782            { "help",        0, NULL, 'h' },
     783            { NULL,          0, NULL, 0   },
     784        };
     785        int c = mygetopt(argc, argv, "o:q:dh", long_options, &option_index);
     786
     787        if(c == -1)
     788            break;
     789
     790        switch(c)
     791        {
     792        case 'o':
     793            dstname = myoptarg;
     794            break;
     795        case 'q':
     796            ITERATIONS_PER_POINT = 10 * atoi(myoptarg);
     797            if(ITERATIONS_PER_POINT < 0)
     798                ITERATIONS_PER_POINT = 0;
     799            else if(ITERATIONS_PER_POINT > 10)
     800                ITERATIONS_PER_POINT = 10;
     801            break;
     802        case 'd':
     803            DEBUG = true;
     804            break;
     805        case 'h':
     806            printf("Usage: img2twit [OPTIONS] SOURCE\n");
     807            printf("       img2twit [OPTIONS] -o DESTINATION\n");
     808            printf("Encode SOURCE image to stdout or decode stdin to DESTINATION.\n");
     809            printf("\n");
     810            printf("Mandatory arguments to long options are mandatory for short options too.\n");
     811            printf("  -o, --output <filename>   output resulting image to filename\n");
     812            printf("  -q, --quality <rate>      set image quality (0 - 10) (default 5)\n");
     813            printf("  -d, --debug               print debug information\n");
     814            printf("  -h, --help                display this help and exit\n");
     815            printf("\n");
     816            printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n");
     817            return EXIT_SUCCESS;
     818        default:
     819            fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c);
     820            printf(MOREINFO, argv[0]);
     821            return EXIT_FAILURE;
     822        }
     823    }
     824
     825    if(myoptind == argc && !dstname)
     826    {
     827        fprintf(stderr, "%s: too few arguments\n", argv[0]);
     828        printf(MOREINFO, argv[0]);
    754829        return EXIT_FAILURE;
    755830    }
     831
     832    if((myoptind == argc - 1 && dstname) || myoptind < argc - 1)
     833    {
     834        fprintf(stderr, "%s: too many arguments\n", argv[0]);
     835        printf(MOREINFO, argv[0]);
     836        return EXIT_FAILURE;
     837    }
     838
     839    if(myoptind == argc - 1)
     840        srcname = argv[myoptind];
    756841
    757842    pipi_set_gamma(1.0);
     
    772857#endif
    773858    TOTAL_CELLS = (int)(DATA_BITS / CELL_BITS);
    774 
    775     if(decode)
     859    MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS;
     860
     861    if(dstname)
    776862    {
    777863        /* Decoding mode: read UTF-8 text from stdin, find each
     
    792878    {
    793879        /* Argument given: open image for encoding */
    794         src = pipi_load(argv[1]);
     880        src = pipi_load(srcname);
    795881
    796882        if(!src)
    797883        {
    798             fprintf(stderr, "Error loading %s\n", argv[1]);
     884            fprintf(stderr, "Error loading %s\n", srcname);
    799885            return EXIT_FAILURE;
    800886        }
     
    824910
    825911    /* 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 
    838     fprintf(stderr, "Chosen image ratio: %i:%i (wasting %i point cells)\n",
    839             dw, dh, TOTAL_CELLS - dw * dh);
    840     fprintf(stderr, "Total wasted bits: %f\n",
    841             DATA_BITS - CELL_BITS * dw * dh);
    842 #endif
    843 
    844     if(src)
     912    if(DEBUG)
     913    {
     914        fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN);
     915        fprintf(stderr, "Available characters: %i\n", NUM_CHARACTERS);
     916        fprintf(stderr, "Available bits: %f\n", TOTAL_BITS);
     917        fprintf(stderr, "Maximum image resolution: %ix%i\n", MAX_W, MAX_H);
     918        fprintf(stderr, "Image resolution: %ix%i\n", width, height);
     919        fprintf(stderr, "Header bits: %f\n", HEADER_BITS);
     920        fprintf(stderr, "Bits available for data: %f\n", DATA_BITS);
     921        fprintf(stderr, "Cell bits: %f\n", CELL_BITS);
     922        fprintf(stderr, "Available cells: %i\n", TOTAL_CELLS);
     923        fprintf(stderr, "Wasted bits: %f\n",
     924                DATA_BITS - CELL_BITS * TOTAL_CELLS);
     925        fprintf(stderr, "Chosen image ratio: %i:%i (wasting %i point cells)\n",
     926                dw, dh, TOTAL_CELLS - dw * dh);
     927        fprintf(stderr, "Total wasted bits: %f\n",
     928                DATA_BITS - CELL_BITS * dw * dh);
     929    }
     930
     931    if(srcname)
    845932    {
    846933        /* Resize and filter image to better state */
     
    849936        src = pipi_median_ext(tmp, 1, 1);
    850937        pipi_free(tmp);
     938pipi_save(src, "lol.bmp");
    851939
    852940        /* Analyse image */
     
    856944        tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y);
    857945        render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y);
     946pipi_save(tmp, "lol2.bmp");
    858947        error = pipi_measure_rmsd(src, tmp);
    859948
    860 #if DEBUG
    861         fprintf(stderr, "Distance: %2.10g\n", error);
    862 #endif
     949        if(DEBUG)
     950            fprintf(stderr, "Initial distance: %2.10g\n", error);
    863951
    864952        memset(opstats, 0, sizeof(opstats));
     
    873961            }
    874962
    875 #if !DEBUG
    876             if(!(iter % 16))
     963            if(!DEBUG && !(iter % 16))
    877964                fprintf(stderr, "\rEncoding... %i%%",
    878965                        iter * 100 / MAX_ITERATIONS);
    879 #endif
    880966
    881967            pipi_image_t *scrap = pipi_copy(tmp);
     
    9401026                pipi_free(tmp);
    9411027                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
     1028
     1029                if(DEBUG)
     1030                    fprintf(stderr, "%08i -.%08i %2.010g after op%i(%i)\n",
     1031                            iter, (int)((error - besterr) * 100000000), error,
     1032                            op1, pt);
     1033
    9461034                error = besterr;
    9471035                opstats[op1 * 2 + 1]++;
     
    9641052        }
    9651053
    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
     1054        if(DEBUG)
     1055        {
     1056            for(int j = 0; j < 2; j++)
     1057            {
     1058                fprintf(stderr,   "operation: ");
     1059                for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
     1060                    fprintf(stderr, "%4i ", i);
     1061                fprintf(stderr, "\nattempts:  ");
     1062                for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
     1063                    fprintf(stderr, "%4i ", opstats[i * 2]);
     1064                fprintf(stderr, "\nsuccesses: ");
     1065                for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++)
     1066                    fprintf(stderr, "%4i ", opstats[i * 2 + 1]);
     1067                fprintf(stderr, "\n");
     1068            }
     1069
     1070            fprintf(stderr, "Distance: %2.10g\n", error);
     1071        }
     1072        else
     1073            fprintf(stderr, "\r                    \r");
    9851074
    9861075#if 0
     
    10271116
    10281117        /* Save image and bail out */
    1029         pipi_save(dst, argv[2]);
     1118        pipi_save(dst, dstname);
    10301119        pipi_free(dst);
    10311120    }
Note: See TracChangeset for help on using the changeset viewer.