Ignore:
Timestamp:
May 25, 2009, 2:17:02 AM (12 years ago)
Author:
Sam Hocevar
Message:

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.

File:
1 edited

Legend:

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

    r3522 r3523  
     1/*
     2 *  img2twit      Image to short text message encoder/decoder
     3 *  Copyright (c) 2009 Sam Hocevar <sam@hocevar.net>
     4 *                All Rights Reserved
     5 *
     6 *  This program is free software. It comes without any warranty, to
     7 *  the extent permitted by applicable law. You can redistribute it
     8 *  and/or modify it under the terms of the Do What The Fuck You Want
     9 *  To Public License, Version 2, as published by Sam Hocevar. See
     10 *  http://sam.zoy.org/wtfpl/COPYING for more details.
     11 */
     12
    113#include "config.h"
    214
     
    5668/* How does the algorithm work: one point per cell, or two */
    5769#define POINTS_PER_CELL 2
     70
     71/*
     72 * These values can be overwritten at runtime
     73 */
     74
     75/* Debug mode */
     76static bool DEBUG_MODE = false;
     77
     78/* The maximum message length */
     79static int MAX_MSG_LEN = 140;
     80
     81/* Iterations per point -- larger means slower but nicer */
     82static int ITERATIONS_PER_POINT = 50;
    5883
    5984/* The range value for point parameters: X Y, red/green/blue, "strength"
     
    7297
    7398/*
    74  * These values can be overwritten at runtime
    75  */
    76 
    77 static bool DEBUG = false;
    78 
    79 /* The maximum message length */
    80 static int MAX_MSG_LEN = 1140;
    81 
    82 static int ITERATIONS_PER_POINT = 50;
    83 
    84 /*
    8599 * These values are computed at runtime
    86100 */
     
    273287private:
    274288    bitstack(uint32_t i) { alloc(); init(i); }
     289
     290    bitstack(bitstack &b)
     291    {
     292        alloc();
     293        msb = b.msb;
     294        memcpy(digits, b.digits, (MAX_MSG_LEN + 1) * sizeof(uint32_t));
     295    }
    275296
    276297    bitstack(bitstack const &b)
     
    687708        for(unsigned int dx = 0; dx < dw; dx++)
    688709        {
    689             float min = 1.1f, max = -0.1f;
     710            float min = 1.1f, max = -0.1f, mr = 0.0f, mg = 0.0f, mb = 0.0f;
    690711            float total = 0.0;
    691712            int xmin = 0, xmax = 0, ymin = 0, ymax = 0;
     
    700721                    lum += data[4 * (ix + iy * p->w) + 1];
    701722                    lum += data[4 * (ix + iy * p->w) + 2];
     723                    lum /= 3;
     724
     725                    mr += data[4 * (ix + iy * p->w) + 0];
     726                    mg += data[4 * (ix + iy * p->w) + 1];
     727                    mb += data[4 * (ix + iy * p->w) + 2];
    702728
    703729                    if(lum < min)
     
    720746
    721747            total /= npixels;
     748            mr /= npixels;
     749            mg /= npixels;
     750            mb /= npixels;
    722751
    723752            float wmin, wmax;
     
    731760
    732761#if 0
    733 add_random_point();
    734 add_random_point();
     762            add_random_point();
     763            add_random_point();
    735764#else
     765            /* 0.80 and 0.20 were chosen empirically, it gives a 10% better
     766             * initial distance. Definitely worth it. */
    736767#if POINTS_PER_CELL == 1
    737768            if(total < min + (max - min) / 2)
     
    739770#endif
    740771            add_point(xmin, ymin,
    741                       data[4 * (xmin + ymin * p->w) + 0],
    742                       data[4 * (xmin + ymin * p->w) + 1],
    743                       data[4 * (xmin + ymin * p->w) + 2],
     772                      data[4 * (xmin + ymin * p->w) + 0] * 0.80 + mr * 0.20,
     773                      data[4 * (xmin + ymin * p->w) + 1] * 0.80 + mg * 0.20,
     774                      data[4 * (xmin + ymin * p->w) + 2] * 0.80 + mb * 0.20,
    744775                      wmin);
    745776#if POINTS_PER_CELL == 1
     
    749780#endif
    750781            add_point(xmax, ymax,
    751                       data[4 * (xmax + ymax * p->w) + 0],
    752                       data[4 * (xmax + ymax * p->w) + 1],
    753                       data[4 * (xmax + ymax * p->w) + 2],
     782                      data[4 * (xmax + ymax * p->w) + 0] * 0.80 + mr * 0.20,
     783                      data[4 * (xmax + ymax * p->w) + 1] * 0.80 + mg * 0.20,
     784                      data[4 * (xmax + ymax * p->w) + 2] * 0.80 + mb * 0.20,
    754785                      wmax);
    755786#if POINTS_PER_CELL == 1
     
    765796{
    766797    int opstats[2 * NB_OPS];
    767     bitstack b;
    768798    char const *srcname = NULL, *dstname = NULL;
    769799    pipi_image_t *src, *tmp, *dst;
     
    778808        {
    779809            { "output",      1, NULL, 'o' },
     810            { "length",      1, NULL, 'l' },
    780811            { "quality",     1, NULL, 'q' },
    781812            { "debug",       0, NULL, 'd' },
     
    783814            { NULL,          0, NULL, 0   },
    784815        };
    785         int c = mygetopt(argc, argv, "o:q:dh", long_options, &option_index);
     816        int c = mygetopt(argc, argv, "o:l:q:dh", long_options, &option_index);
    786817
    787818        if(c == -1)
     
    792823        case 'o':
    793824            dstname = myoptarg;
     825            break;
     826        case 'l':
     827            MAX_MSG_LEN = atoi(myoptarg);
     828            if(MAX_MSG_LEN < 16)
     829            {
     830                fprintf(stderr, "Warning: rounding minimum message length to 16\n");
     831                MAX_MSG_LEN = 16;
     832            }
    794833            break;
    795834        case 'q':
     
    797836            if(ITERATIONS_PER_POINT < 0)
    798837                ITERATIONS_PER_POINT = 0;
    799             else if(ITERATIONS_PER_POINT > 10)
    800                 ITERATIONS_PER_POINT = 10;
     838            else if(ITERATIONS_PER_POINT > 100)
     839                ITERATIONS_PER_POINT = 100;
    801840            break;
    802841        case 'd':
    803             DEBUG = true;
     842            DEBUG_MODE = true;
    804843            break;
    805844        case 'h':
     
    810849            printf("Mandatory arguments to long options are mandatory for short options too.\n");
    811850            printf("  -o, --output <filename>   output resulting image to filename\n");
     851            printf("  -l, --length <size>       message length in characters (default 140)\n");
    812852            printf("  -q, --quality <rate>      set image quality (0 - 10) (default 5)\n");
    813853            printf("  -d, --debug               print debug information\n");
     
    859899    MAX_ITERATIONS = ITERATIONS_PER_POINT * POINTS_PER_CELL * TOTAL_CELLS;
    860900
     901    bitstack b; /* We cannot declare this before, because MAX_MSG_LEN
     902                 * wouldn't be defined. */
     903
    861904    if(dstname)
    862905    {
     
    910953
    911954    /* Print debug information */
    912     if(DEBUG)
     955    if(DEBUG_MODE)
    913956    {
    914957        fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN);
     
    936979        src = pipi_median_ext(tmp, 1, 1);
    937980        pipi_free(tmp);
    938 pipi_save(src, "lol.bmp");
    939981
    940982        /* Analyse image */
     
    944986        tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y);
    945987        render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y);
    946 pipi_save(tmp, "lol2.bmp");
    947988        error = pipi_measure_rmsd(src, tmp);
    948989
    949         if(DEBUG)
     990        if(DEBUG_MODE)
    950991            fprintf(stderr, "Initial distance: %2.10g\n", error);
    951992
     
    9611002            }
    9621003
    963             if(!DEBUG && !(iter % 16))
     1004            if(!DEBUG_MODE && !(iter % 16))
    9641005                fprintf(stderr, "\rEncoding... %i%%",
    9651006                        iter * 100 / MAX_ITERATIONS);
     
    10271068                tmp = scrap;
    10281069
    1029                 if(DEBUG)
     1070                if(DEBUG_MODE)
    10301071                    fprintf(stderr, "%08i -.%08i %2.010g after op%i(%i)\n",
    10311072                            iter, (int)((error - besterr) * 100000000), error,
     
    10521093        }
    10531094
    1054         if(DEBUG)
     1095        if(DEBUG_MODE)
    10551096        {
    10561097            for(int j = 0; j < 2; j++)
Note: See TracChangeset for help on using the changeset viewer.