Changeset 3523


Ignore:
Timestamp:
05/25/09 02:17:02 (4 years ago)
Author:
sam
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.