Changeset 3537


Ignore:
Timestamp:
May 30, 2009 6:01:09 PM (5 years ago)
Author:
sam
Message:

img2twit: prevent two points from having the same coordinates, since this
is forbidden by the image format; simplify operation computations by not
packing coordinates at runtime; add a version information in the file
format for future extension.

File:
1 edited

Legend:

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

    r3536 r3537  
    6767static const uint32_t *unichars;
    6868
    69 /* The maximum image size we want to support */
    70 #define RANGE_W 4000
    71 #define RANGE_H 4000
     69/* The maximum image size we want to support, and the version range */
     70#define RANGE_W 2000
     71#define RANGE_H 2000
     72#define RANGE_V 10
    7273
    7374/* How does the algorithm work: one point per cell, or two? XXX: changing
     
    118119static unsigned int TOTAL_CELLS;
    119120
    120 #define RANGE_XY (RANGE_Y*RANGE_X)
    121121#define RANGE_XY2 (RANGE_Y*RANGE_X*(RANGE_Y*RANGE_X+1)/2)
    122 #define RANGE_RXY (RANGE_Y*RANGE_X*RANGE_R)
    123 #define RANGE_GRXY (RANGE_Y*RANGE_X*RANGE_R*RANGE_G)
    124 #define RANGE_BGRXY (RANGE_Y*RANGE_X*RANGE_R*RANGE_G*RANGE_B)
     122#define RANGE_SBGR (RANGE_R*RANGE_G*RANGE_B*RANGE_S)
    125123#define RANGE_SBGRXY (RANGE_Y*RANGE_X*RANGE_R*RANGE_G*RANGE_B*RANGE_S)
    126 #define RANGE_SBGR (RANGE_R*RANGE_G*RANGE_B*RANGE_S)
    127124
    128125struct K : CGAL::Exact_predicates_inexact_constructions_kernel {};
     
    133130static unsigned int dw, dh;
    134131
     132/* Algorithm version */
     133static unsigned int version;
     134
    135135/* Global point encoding */
    136 static uint32_t points[4096]; /* FIXME: allocate this dynamically */
     136typedef struct point
     137{
     138    uint8_t x, y, r, g, b, s;
     139}
     140point_t;
     141static point_t points[4096]; /* FIXME: allocate this dynamically */
    137142static int npoints = 0;
    138143
     
    147152{
    148153    TOTAL_BITS = MAX_MSG_LEN * logf(NUM_CHARACTERS) / logf(2);
    149     HEADER_BITS = logf(RANGE_W * RANGE_H) / logf(2);
     154    HEADER_BITS = logf(RANGE_W * RANGE_H * RANGE_V) / logf(2);
    150155    DATA_BITS = TOTAL_BITS - HEADER_BITS;
    151156#if POINTS_PER_CELL == 2
     
    508513    float fy = (y - dy * RANGE_Y) / RANGE_Y;
    509514
    510     int iy = range2int(fy, RANGE_Y);
    511     int ix = range2int(fx, RANGE_X);
    512 
    513     int ir = range2int(r, RANGE_R);
    514     int ig = range2int(g, RANGE_G);
    515     int ib = range2int(b, RANGE_B);
    516 
    517     int is = range2int(s, RANGE_S);
    518 
    519     points[index] = iy + RANGE_Y * (ix + RANGE_X * (ir + RANGE_R *
    520                       (ig + (RANGE_G * ib + (RANGE_B * is)))));
     515    points[index].x = range2int(fx, RANGE_X);
     516    points[index].y = range2int(fy, RANGE_Y);
     517
     518    points[index].r = range2int(r, RANGE_R);
     519    points[index].g = range2int(g, RANGE_G);
     520    points[index].b = range2int(b, RANGE_B);
     521
     522    points[index].s = range2int(s, RANGE_S);
    521523}
    522524
     
    524526                             float *g, float *b, float *s, bool final = false)
    525527{
    526     uint32_t pt = points[index];
    527528    int dx, dy;
    528529
    529530    index2cell(index, &dx, &dy);
    530531
    531     float fy = int2midrange(pt % RANGE_Y, RANGE_Y); pt /= RANGE_Y;
    532     float fx = int2midrange(pt % RANGE_X, RANGE_X); pt /= RANGE_X;
     532    float fx = int2midrange(points[index].x, RANGE_X);
     533    float fy = int2midrange(points[index].y, RANGE_Y);
    533534
    534535    *y = (fy + dy) * RANGE_Y /*+ 0.5 * (index & 1)*/;
     
    537538    if(final)
    538539    {
    539         *r = int2fullrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
    540         *g = int2fullrange(pt % RANGE_G, RANGE_G); pt /= RANGE_G;
    541         *b = int2fullrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B;
     540        *r = int2fullrange(points[index].r, RANGE_R);
     541        *g = int2fullrange(points[index].g, RANGE_G);
     542        *b = int2fullrange(points[index].b, RANGE_B);
    542543    }
    543544    else
    544545    {
    545         *r = int2midrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
    546         *g = int2midrange(pt % RANGE_G, RANGE_G); pt /= RANGE_G;
    547         *b = int2midrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B;
    548     }
    549 
    550     *s = int2fullrange(pt % RANGE_S, RANGE_S); pt /= RANGE_S;
     546        *r = int2midrange(points[index].r, RANGE_R);
     547        *g = int2midrange(points[index].g, RANGE_G);
     548        *b = int2midrange(points[index].b, RANGE_B);
     549    }
     550
     551    *s = int2fullrange(points[index].s, RANGE_S);
    551552}
    552553
     
    590591static void add_random_point()
    591592{
    592     points[npoints] = det_rand(RANGE_SBGRXY);
     593    points[npoints].x = det_rand(RANGE_X);
     594    points[npoints].y = det_rand(RANGE_Y);
     595    points[npoints].r = det_rand(RANGE_R);
     596    points[npoints].g = det_rand(RANGE_G);
     597    points[npoints].b = det_rand(RANGE_B);
     598    points[npoints].s = det_rand(RANGE_S);
    593599    npoints++;
    594600}
     
    614620}
    615621
    616 static uint32_t apply_op(uint8_t op, uint32_t val)
    617 {
    618     uint32_t rem, ext;
    619 
     622static void apply_op(uint8_t op, point_t *val)
     623{
    620624    switch(op)
    621625    {
     
    624628        /* Statistics show that this helps often, but does not reduce
    625629         * the error significantly. */
    626         rem = val % RANGE_BGRXY;
    627         ext = val / RANGE_BGRXY;
    628         ext ^= 1;
    629         return ext * RANGE_BGRXY + rem;
     630        val->s ^= 1; break;
    630631    case 2: /* Move up; if impossible, down */
    631         ext = val % RANGE_Y;
    632         ext = ext > 0 ? ext - 1 : ext + 1;
    633         return val / RANGE_Y * RANGE_Y + ext;
     632        val->y = val->y > 0 ? val->y - 1 : val->y + 1; break;
    634633    case 3: /* Move down; if impossible, up */
    635         ext = val % RANGE_Y;
    636         ext = ext < RANGE_Y - 1 ? ext + 1 : ext - 1;
    637         return val / RANGE_Y * RANGE_Y + ext;
     634        val->y = val->y + 1U < RANGE_Y ? val->y + 1 : val->y - 1; break;
    638635    case 4: /* Move left; if impossible, right */
    639         rem = val % RANGE_Y;
    640         ext = (val / RANGE_Y) % RANGE_X;
    641         ext = ext > 0 ? ext - 1 : ext + 1;
    642         return (val / RANGE_XY * RANGE_X + ext) * RANGE_Y + rem;
    643     case 5: /* Move left; if impossible, right */
    644         rem = val % RANGE_Y;
    645         ext = (val / RANGE_Y) % RANGE_X;
    646         ext = ext < RANGE_X - 1 ? ext + 1 : ext - 1;
    647         return (val / RANGE_XY * RANGE_X + ext) * RANGE_Y + rem;
     636        val->x = val->x > 0 ? val->x - 1 : val->x + 1; break;
     637    case 5: /* Move right; if impossible, left */
     638        val->x = val->x + 1U < RANGE_X ? val->x + 1 : val->x - 1; break;
    648639    case 6: /* Corner 1 */
    649         return apply_op(2, apply_op(4, val));
     640        val->y = val->y > 0 ? val->y - 1 : val->y + 1;
     641        val->x = val->x > 0 ? val->x - 1 : val->x + 1; break;
    650642    case 7: /* Corner 2 */
    651         return apply_op(2, apply_op(5, val));
     643        val->y = val->y > 0 ? val->y - 1 : val->y + 1;
     644        val->x = val->x + 1U < RANGE_X ? val->x + 1 : val->x - 1; break;
    652645    case 8: /* Corner 3 */
    653         return apply_op(3, apply_op(5, val));
     646        val->y = val->y + 1U < RANGE_Y ? val->y + 1 : val->y - 1;
     647        val->x = val->x + 1U < RANGE_X ? val->x + 1 : val->x - 1; break;
    654648    case 9: /* Corner 4 */
    655         return apply_op(3, apply_op(4, val));
     649        val->y = val->y + 1U < RANGE_Y ? val->y + 1 : val->y - 1;
     650        val->x = val->x > 0 ? val->x - 1 : val->x + 1; break;
    656651    case 16: /* Double up */
    657         return apply_op(2, apply_op(2, val));
     652        val->y = val->y > 1 ? val->y - 2 : val->y + 2; break;
    658653    case 17: /* Double down */
    659         return apply_op(3, apply_op(3, val));
     654        val->y = val->y + 2U < RANGE_Y ? val->y + 2 : val->y - 2; break;
    660655    case 18: /* Double left */
    661         return apply_op(4, apply_op(4, val));
     656        val->x = val->x > 1 ? val->x - 2 : val->x + 2; break;
    662657    case 19: /* Double right */
    663         return apply_op(5, apply_op(5, val));
     658        val->x = val->x + 2U < RANGE_X ? val->x + 2 : val->x - 2; break;
    664659    case 10: /* R-- (or R++) */
    665         rem = val % RANGE_XY;
    666         ext = (val / RANGE_XY) % RANGE_R;
    667         ext = ext > 0 ? ext - 1 : ext + 1;
    668         return (val / RANGE_RXY * RANGE_R + ext) * RANGE_XY + rem;
     660        val->r = val->r > 0 ? val->r - 1 : val->r + 1; break;
    669661    case 11: /* R++ (or R--) */
    670         rem = val % RANGE_XY;
    671         ext = (val / RANGE_XY) % RANGE_R;
    672         ext = ext < RANGE_R - 1 ? ext + 1 : ext - 1;
    673         return (val / RANGE_RXY * RANGE_R + ext) * RANGE_XY + rem;
     662        val->r = val->r + 1U < RANGE_R ? val->r + 1 : val->r - 1; break;
    674663    case 12: /* G-- (or G++) */
    675         rem = val % RANGE_RXY;
    676         ext = (val / RANGE_RXY) % RANGE_G;
    677         ext = ext > 0 ? ext - 1 : ext + 1;
    678         return (val / RANGE_GRXY * RANGE_G + ext) * RANGE_RXY + rem;
     664        val->g = val->g > 0 ? val->g - 1 : val->g + 1; break;
    679665    case 13: /* G++ (or G--) */
    680         rem = val % RANGE_RXY;
    681         ext = (val / RANGE_RXY) % RANGE_G;
    682         ext = ext < RANGE_G - 1 ? ext + 1 : ext - 1;
    683         return (val / RANGE_GRXY * RANGE_G + ext) * RANGE_RXY + rem;
     666        val->g = val->g + 1U < RANGE_G ? val->g + 1 : val->g - 1; break;
    684667    case 14: /* B-- (or B++) */
    685         rem = val % RANGE_GRXY;
    686         ext = (val / RANGE_GRXY) % RANGE_B;
    687         ext = ext > 0 ? ext - 1 : ext + 1;
    688         return (val / RANGE_BGRXY * RANGE_B + ext) * RANGE_GRXY + rem;
     668        val->b = val->b > 0 ? val->g - 1 : val->b + 1; break;
    689669    case 15: /* B++ (or B--) */
    690         rem = val % RANGE_GRXY;
    691         ext = (val / RANGE_GRXY) % RANGE_B;
    692         ext = ext < RANGE_B - 1 ? ext + 1 : ext - 1;
    693         return (val / RANGE_BGRXY * RANGE_B + ext) * RANGE_GRXY + rem;
     670        val->b = val->b + 1U < RANGE_B ? val->b + 1 : val->b - 1; break;
    694671#if 0
    695672    case 15: /* Brightness-- */
    696         return apply_op(9, apply_op(11, apply_op(13, val)));
     673        apply_op(9, val); apply_op(11, val); apply_op(13, val); break;
    697674    case 16: /* Brightness++ */
    698         return apply_op(10, apply_op(12, apply_op(14, val)));
     675        apply_op(10, val); apply_op(12, val); apply_op(14, val); break;
    699676    case 17: /* RG-- */
    700         return apply_op(9, apply_op(11, val));
     677        apply_op(9, val); apply_op(11, val); break;
    701678    case 18: /* RG++ */
    702         return apply_op(10, apply_op(12, val));
     679        apply_op(10, val); apply_op(12, val); break;
    703680    case 19: /* GB-- */
    704         return apply_op(11, apply_op(13, val));
     681        apply_op(11, val); apply_op(13, val); break;
    705682    case 20: /* GB++ */
    706         return apply_op(12, apply_op(14, val));
     683        apply_op(12, val); apply_op(14, val); break;
    707684    case 21: /* RB-- */
    708         return apply_op(9, apply_op(13, val));
     685        apply_op(9, val); apply_op(13, val); break;
    709686    case 22: /* RB++ */
    710         return apply_op(10, apply_op(14, val));
     687        apply_op(10, val); apply_op(14, val); break;
    711688#endif
    712689    default:
    713         return val;
     690        break;
    714691    }
    715692}
     
    10731050            b.push(uni2index(unicode_data[i]), NUM_CHARACTERS);
    10741051
     1052        /* The first thing we pop from the stream is the version information */
     1053        version = b.pop(RANGE_V);
     1054
    10751055        /* Read width and height from bitstream */
    1076         src = NULL;
    10771056        width = b.pop(RANGE_W) + 1;
    10781057        height = b.pop(RANGE_H) + 1;
     1058        src = NULL;
    10791059    }
    10801060    else
     
    10891069        }
    10901070
     1071        version = 1;
    10911072        width = pipi_get_image_width(src);
    10921073        height = pipi_get_image_height(src);
     
    10971078        fprintf(stderr, "Error: image size %ix%i is out of bounds\n",
    10981079                width, height);
     1080        return EXIT_FAILURE;
     1081    }
     1082
     1083    if(version > 1)
     1084    {
     1085        fprintf(stderr, "Error: unsupported algorithm version %i\n", version);
    10991086        return EXIT_FAILURE;
    11001087    }
     
    11421129        fprintf(stderr, "Available bits: %f\n", TOTAL_BITS);
    11431130        fprintf(stderr, "Width/Height ranges: %ix%i\n", RANGE_W, RANGE_H);
     1131        fprintf(stderr, "Algorithm version: %i\n", RANGE_V);
    11441132        fprintf(stderr, "Image resolution: %ix%i\n", width, height);
    11451133        fprintf(stderr, "Header bits: %f\n", HEADER_BITS);
     
    11951183            /* Choose a point at random */
    11961184            int pt = det_rand(npoints);
    1197             uint32_t oldval = points[pt];
     1185            point_t oldpt = points[pt];
    11981186
    11991187            /* Compute the affected image zone */
     
    12131201            //uint8_t op2 = rand_op();
    12141202
    1215             uint32_t candidates[3];
    1216             double besterr = error + 1.0;
    1217             int bestop = -1;
    1218             candidates[0] = apply_op(op1, oldval);
    1219             //candidates[1] = apply_op(op2, oldval);
    1220             //candidates[2] = apply_op(op1, apply_op(op2, oldval));
    1221 
    1222             for(int i = 0; i < 1; i++)
    1223             //for(int i = 0; i < 3; i++)
     1203            apply_op(op1, &points[pt]);
     1204
     1205#if POINTS_PER_CELL == 2
     1206            /* Check that two points don't fall at the same place */
     1207            while(points[pt].x == points[pt ^ 1].x
     1208                   && points[pt].y == points[pt ^ 1].y)
    12241209            {
    1225                 if(oldval == candidates[i])
    1226                     continue;
    1227 
    1228                 points[pt] = candidates[i];
    1229 
    1230                 render(scrap, zonex * RANGE_X, zoney * RANGE_Y,
    1231                        zonew * RANGE_X, zoneh * RANGE_Y, false);
    1232 
    1233                 double newerr = pipi_measure_rmsd(src, scrap);
    1234                 if(newerr < besterr)
    1235                 {
    1236                     besterr = newerr;
    1237                     bestop = i;
    1238                 }
     1210                points[pt] = oldpt;
     1211                op1 = rand_op();
     1212                apply_op(op1, &points[pt]);
    12391213            }
     1214#endif
     1215
     1216            render(scrap, zonex * RANGE_X, zoney * RANGE_Y,
     1217                   zonew * RANGE_X, zoneh * RANGE_Y, false);
     1218
     1219            double newerr = pipi_measure_rmsd(src, scrap);
    12401220
    12411221            opstats[op1 * 2]++;
    12421222            //opstats[op2 * 2]++;
    12431223
    1244             if(besterr < error)
     1224            if(newerr < error)
    12451225            {
    1246                 points[pt] = candidates[bestop];
    1247                 /* Redraw image if the last check wasn't the best one */
    1248                 if(bestop != 0)
    1249                     render(scrap, zonex * RANGE_X, zoney * RANGE_Y,
    1250                            zonew * RANGE_X, zoneh * RANGE_Y, false);
    1251 
    12521226                pipi_free(tmp);
     1227
     1228#if 0
     1229                /* Save image! */
     1230                if((success % 10) == 0)
     1231                {
     1232                    char buf[128];
     1233                    sprintf(buf, "twit%08i.bmp", success);
     1234                    tmp = pipi_new(width, height);
     1235                    render(tmp, 0, 0, width, height, true);
     1236                    pipi_save(tmp, buf);
     1237                    pipi_free(tmp);
     1238                }
     1239#endif
     1240
    12531241                tmp = scrap;
    12541242
    12551243                if(DEBUG_MODE)
    1256                     fprintf(stderr, "%08i -.%08i %2.010g after op%i(%i)\n",
    1257                             iter, (int)((error - besterr) * 100000000), error,
    1258                             op1, pt);
    1259 
    1260                 error = besterr;
     1244                    fprintf(stderr, "%08i -0.%010i %2.010g after op%i(%i)\n",
     1245                            iter, (int)((error - newerr) * 10000000000L),
     1246                            error, op1, pt);
     1247
     1248                error = newerr;
    12611249                opstats[op1 * 2 + 1]++;
    12621250                //opstats[op2 * 2 + 1]++;
    12631251                failures = 0;
    12641252                success++;
    1265 
    1266                 /* Save image! */
    1267                 char buf[128];
    1268                 sprintf(buf, "twit%08i.bmp", success);
    1269                 if((success % 10) == 0)
    1270                     pipi_save(tmp, buf);
    12711253            }
    12721254            else
    12731255            {
    12741256                pipi_free(scrap);
    1275                 points[pt] = oldval;
     1257                points[pt] = oldpt;
    12761258                failures++;
    12771259            }
     
    12991281            fprintf(stderr, "\r                    \r");
    13001282
    1301 #if 0
     1283#if 1
    13021284        dst = pipi_resize(tmp, width, height);
    13031285        pipi_free(tmp);
     
    13131295#if POINTS_PER_CELL == 2
    13141296            int x1, y1, x2, y2;
    1315             x1 = (points[i] / RANGE_Y) % RANGE_X;
    1316             y1 = points[i] % RANGE_Y;
    1317             x2 = (points[i + 1] / RANGE_Y) % RANGE_X;
    1318             y2 = points[i + 1] % RANGE_Y;
     1297            x1 = points[i].x;
     1298            y1 = points[i].y;
     1299            x2 = points[i + 1].x;
     1300            y2 = points[i + 1].y;
    13191301
    13201302            bool swap;
    13211303            uint32_t pack = pack_coords(x1, y1, x2, y2, &swap);
    13221304
    1323             b.push(points[i + (swap ? 1 : 0)] / RANGE_XY, RANGE_SBGR);
    1324             b.push(points[i + (swap ? 0 : 1)] / RANGE_XY, RANGE_SBGR);
     1305            b.push(points[i + (swap ? 1 : 0)].s, RANGE_S);
     1306            b.push(points[i + (swap ? 1 : 0)].b, RANGE_B);
     1307            b.push(points[i + (swap ? 1 : 0)].g, RANGE_G);
     1308            b.push(points[i + (swap ? 1 : 0)].r, RANGE_R);
     1309            b.push(points[i + (swap ? 0 : 1)].s, RANGE_S);
     1310            b.push(points[i + (swap ? 0 : 1)].b, RANGE_B);
     1311            b.push(points[i + (swap ? 0 : 1)].g, RANGE_G);
     1312            b.push(points[i + (swap ? 0 : 1)].r, RANGE_R);
    13251313            b.push(pack, RANGE_XY2);
    13261314#else
    1327             b.push(points[i], RANGE_SBGRXY);
     1315            b.push(points[i].s, RANGE_S);
     1316            b.push(points[i].b, RANGE_B);
     1317            b.push(points[i].g, RANGE_G);
     1318            b.push(points[i].r, RANGE_R);
     1319            b.push(points[i].x, RANGE_X);
     1320            b.push(points[i].y, RANGE_Y);
    13281321#endif
    13291322        }
    13301323        b.push(height - 1, RANGE_H);
    13311324        b.push(width - 1, RANGE_W);
     1325        b.push(version, RANGE_V);
    13321326
    13331327        /* Pop Unicode characters from the bitstream and print them */
     
    13431337#if POINTS_PER_CELL == 2
    13441338            uint32_t pack = b.pop(RANGE_XY2);
    1345             uint32_t p2 = b.pop(RANGE_SBGR);
    1346             uint32_t p1 = b.pop(RANGE_SBGR);
    13471339            int x1, y1, x2, y2;
    1348 
    13491340            unpack_coords(pack, &x1, &y1, &x2, &y2);
    1350             points[i * 2] = p1 * RANGE_XY + x1 * RANGE_Y + y1;
    1351             points[i * 2 + 1] = p2 * RANGE_XY + x2 * RANGE_Y + y2;
     1341
     1342            points[i * 2 + 1].y = y2;
     1343            points[i * 2 + 1].x = x2;
     1344            points[i * 2 + 1].r = b.pop(RANGE_R);
     1345            points[i * 2 + 1].g = b.pop(RANGE_G);
     1346            points[i * 2 + 1].b = b.pop(RANGE_B);
     1347            points[i * 2 + 1].s = b.pop(RANGE_S);
     1348            points[i * 2].y = y1;
     1349            points[i * 2].x = x1;
     1350            points[i * 2].r = b.pop(RANGE_R);
     1351            points[i * 2].g = b.pop(RANGE_G);
     1352            points[i * 2].b = b.pop(RANGE_B);
     1353            points[i * 2].s = b.pop(RANGE_S);
    13521354#else
    1353             points[i] = b.pop(RANGE_SBGRXY);
     1355            points[i].y = b.pop(RANGE_Y);
     1356            points[i].x = b.pop(RANGE_X);
     1357            points[i].r = b.pop(RANGE_R);
     1358            points[i].g = b.pop(RANGE_G);
     1359            points[i].b = b.pop(RANGE_B);
     1360            points[i].s = b.pop(RANGE_S);
    13541361#endif
    13551362        }
Note: See TracChangeset for help on using the changeset viewer.