|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- #include "config.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
-
- #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
- #include <CGAL/Delaunay_triangulation_2.h>
- #include <CGAL/natural_neighbor_coordinates_2.h>
-
- #include <pipi.h>
-
- #define TOTAL_POINTS 138
- #define POINTS_PER_CELL 2
-
- #define RANGE_X 16
- #define RANGE_Y 16
- #define RANGE_R 5
- #define RANGE_G 5
- #define RANGE_B 5
- #define RANGE_S 1
-
- #define RANGE_SY (RANGE_S*RANGE_Y)
- #define RANGE_SYX (RANGE_S*RANGE_Y*RANGE_X)
- #define RANGE_SYXR (RANGE_S*RANGE_Y*RANGE_X*RANGE_R)
- #define RANGE_SYXRG (RANGE_S*RANGE_Y*RANGE_X*RANGE_R*RANGE_G)
- #define RANGE_SYXRGB (RANGE_S*RANGE_Y*RANGE_X*RANGE_R*RANGE_G*RANGE_B)
-
- struct K : CGAL::Exact_predicates_inexact_constructions_kernel {};
- typedef CGAL::Delaunay_triangulation_2<K> Delaunay_triangulation;
- typedef std::vector<std::pair<K::Point_2, K::FT> > Point_coordinate_vector;
-
- /* Global aspect ratio */
- static int dw, dh;
-
- /* Global point encoding */
- static uint32_t points[1024];
- static int npoints = 0;
-
- /* Global triangulation */
- static Delaunay_triangulation dt;
-
- static unsigned int det_rand(unsigned int mod)
- {
- static unsigned long next = 1;
- next = next * 1103515245 + 12345;
- return ((unsigned)(next / 65536) % 32768) % mod;
- }
-
- static inline int float2int(float val, int range)
- {
- int ret = (int)(val * ((float)range - 0.0001));
- return ret < 0 ? 0 : ret > range - 1? range - 1 : ret;
- }
-
- static inline float int2float(int val, int range)
- {
- return (float)(1 + 2 * val) / (float)(2 * range);
- }
-
- static inline uint32_t set_point(int index, float x, float y, float r,
- float g, float b, float s)
- {
- int dx = (index / POINTS_PER_CELL) % dw;
- int dy = (index / POINTS_PER_CELL) / dw;
-
- float fx = (x - dx * RANGE_X) / RANGE_X;
- float fy = (y - dy * RANGE_Y) / RANGE_Y;
-
- int is = float2int(s, RANGE_S);
-
- int ix = float2int(fx, RANGE_X);
- int iy = float2int(fy, RANGE_Y);
-
- int ir = float2int(r, RANGE_R);
- int ig = float2int(g, RANGE_G);
- int ib = float2int(b, RANGE_B);
-
- points[index] = is + RANGE_S * (iy + RANGE_Y * (ix + RANGE_X *
- (ib + RANGE_B * (ig + (RANGE_R * ir)))));
- }
-
- static inline void get_point(int index, float *x, float *y, float *r,
- float *g, float *b, float *s)
- {
- uint32_t pt = points[index];
-
- unsigned int dx = (index / POINTS_PER_CELL) % dw;
- unsigned int dy = (index / POINTS_PER_CELL) / dw;
-
- float fs = int2float(pt % RANGE_S, RANGE_S); pt /= RANGE_S;
-
- *s = fs < 0.5 ? 0.0 : 1.0;
-
- float fy = int2float(pt % RANGE_Y, RANGE_Y); pt /= RANGE_Y;
- float fx = int2float(pt % RANGE_X, RANGE_X); pt /= RANGE_X;
-
- *x = (fx + dx) * RANGE_X;
- *y = (fy + dy) * RANGE_Y;
-
- *b = int2float(pt % RANGE_R, RANGE_R); pt /= RANGE_R;
- *g = int2float(pt % RANGE_G, RANGE_G); pt /= RANGE_G;
- *r = int2float(pt % RANGE_B, RANGE_B); pt /= RANGE_B;
- }
-
- static inline float clip(float x, int modulo)
- {
- float mul = (float)modulo + 0.9999;
- int round = (int)(x * mul);
- return (float)round / (float)modulo;
- }
-
- static void add_point(float x, float y, float r, float g, float b, float s)
- {
- set_point(npoints, x, y, r, g, b, s);
- get_point(npoints, &x, &y, &r, &g, &b, &s);
- npoints++;
- }
-
- #define MAX_OPS 15
-
- static uint32_t apply_op(uint8_t op, uint32_t val)
- {
- uint32_t rem, ext;
-
- switch(op)
- {
- case 0: /* Flip strength value */
- return val ^ 1;
- case 1: /* Move up; if impossible, down */
- rem = val % RANGE_S;
- ext = (val / RANGE_S) % RANGE_Y;
- ext = ext > 0 ? ext - 1 : ext + 1;
- return (val / RANGE_SY * RANGE_Y + ext) * RANGE_S + rem;
- case 2: /* Move down; if impossible, up */
- rem = val % RANGE_S;
- ext = (val / RANGE_S) % RANGE_Y;
- ext = ext < RANGE_Y - 1 ? ext + 1 : ext - 1;
- return (val / RANGE_SY * RANGE_Y + ext) * RANGE_S + rem;
- case 3: /* Move left; if impossible, right */
- rem = val % RANGE_SY;
- ext = (val / RANGE_SY) % RANGE_X;
- ext = ext > 0 ? ext - 1 : ext + 1;
- return (val / RANGE_SYX * RANGE_X + ext) * RANGE_SY + rem;
- case 4: /* Move left; if impossible, right */
- rem = val % RANGE_SY;
- ext = (val / RANGE_SY) % RANGE_X;
- ext = ext < RANGE_X - 1 ? ext + 1 : ext - 1;
- return (val / RANGE_SYX * RANGE_X + ext) * RANGE_SY + rem;
- case 5: /* Corner 1 */
- return apply_op(1, apply_op(3, val));
- case 6: /* Corner 2 */
- return apply_op(1, apply_op(4, val));
- case 7: /* Corner 3 */
- return apply_op(2, apply_op(4, val));
- case 8: /* Corner 4 */
- return apply_op(2, apply_op(3, val));
- case 9: /* R-- (or R++) */
- rem = val % RANGE_SYX;
- ext = (val / RANGE_SYX) % RANGE_R;
- ext = ext > 0 ? ext - 1 : ext + 1;
- return (val / RANGE_SYXR * RANGE_R + ext) * RANGE_SYX + rem;
- case 10: /* R++ (or R--) */
- rem = val % RANGE_SYX;
- ext = (val / RANGE_SYX) % RANGE_R;
- ext = ext < RANGE_R - 1 ? ext + 1 : ext - 1;
- return (val / RANGE_SYXR * RANGE_R + ext) * RANGE_SYX + rem;
- case 11: /* G-- (or G++) */
- rem = val % RANGE_SYXR;
- ext = (val / RANGE_SYXR) % RANGE_G;
- ext = ext > 0 ? ext - 1 : ext + 1;
- return (val / RANGE_SYXRG * RANGE_G + ext) * RANGE_SYXR + rem;
- case 12: /* G++ (or G--) */
- rem = val % RANGE_SYXR;
- ext = (val / RANGE_SYXR) % RANGE_G;
- ext = ext < RANGE_G - 1 ? ext + 1 : ext - 1;
- return (val / RANGE_SYXRG * RANGE_G + ext) * RANGE_SYXR + rem;
- case 13: /* B-- (or B++) */
- rem = val % RANGE_SYXRG;
- ext = (val / RANGE_SYXRG) % RANGE_B;
- ext = ext > 0 ? ext - 1 : ext + 1;
- return ext * RANGE_SYXRG + rem;
- case 14: /* B++ (or B--) */
- rem = val % RANGE_SYXRG;
- ext = (val / RANGE_SYXRG) % RANGE_B;
- ext = ext < RANGE_B - 1 ? ext + 1 : ext - 1;
- return ext * RANGE_SYXRG + rem;
- #if 0
- case 15: /* Brightness-- */
- return apply_op(9, apply_op(11, apply_op(13, val)));
- case 16: /* Brightness++ */
- return apply_op(10, apply_op(12, apply_op(14, val)));
- case 17: /* RG-- */
- return apply_op(9, apply_op(11, val));
- case 18: /* RG++ */
- return apply_op(10, apply_op(12, val));
- case 19: /* GB-- */
- return apply_op(11, apply_op(13, val));
- case 20: /* GB++ */
- return apply_op(12, apply_op(14, val));
- case 21: /* RB-- */
- return apply_op(9, apply_op(13, val));
- case 22: /* RB++ */
- return apply_op(10, apply_op(14, val));
- #endif
- default:
- return val;
- }
- }
-
- static void render(pipi_image_t *dst, int rx, int ry, int rw, int rh)
- {
- uint8_t lookup[TOTAL_POINTS / POINTS_PER_CELL * RANGE_X * RANGE_Y];
- pipi_pixels_t *p = pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
- float *data = (float *)p->pixels;
- float fx, fy, fr, fg, fb, fs;
- int i, x, y;
-
- memset(lookup, 0, sizeof(lookup));
- dt.clear();
- for(i = 0; i < npoints; i++)
- {
- get_point(i, &fx, &fy, &fr, &fg, &fb, &fs);
- lookup[(int)fx + dw * RANGE_X * (int)fy] = i; /* Keep link to point */
- dt.insert(K::Point_2(fx, fy));
- }
-
- /* Add fake points to close the triangulation */
- dt.insert(K::Point_2(-p->w, -p->h));
- dt.insert(K::Point_2(2 * p->w, -p->h));
- dt.insert(K::Point_2(-p->w, 2 * p->h));
- dt.insert(K::Point_2(2 * p->w, 2 * p->h));
-
- for(y = ry; y < ry + rh; y++)
- {
- for(x = rx; x < rx + rw; x++)
- {
- int i1 = 0, i2 = 0, i3 = 0;
- float d1 = 1000000, d2 = 0, d3 = 0;
-
- K::Point_2 m(x, y);
- Point_coordinate_vector coords;
- CGAL::Triple<
- std::back_insert_iterator<Point_coordinate_vector>,
- K::FT, bool> result =
- CGAL::natural_neighbor_coordinates_2(dt, m,
- std::back_inserter(coords));
-
- float r = 0.0f, g = 0.0f, b = 0.0f, norm = 0.0f;
-
- Point_coordinate_vector::iterator it;
- for(it = coords.begin(); it != coords.end(); ++it)
- {
- float fx = (*it).first.x();
- float fy = (*it).first.y();
-
- if(fx < 0 || fy < 0 || fx > p->w - 1 || fy > p->h - 1)
- continue;
-
- int index = lookup[(int)fx + dw * RANGE_X * (int)fy];
-
- get_point(index, &fx, &fy, &fr, &fg, &fb, &fs);
-
- float k = (*it).second;
- if(fs > 0.5) k = pow(k, 1.2);
- else k = pow(k, 0.8);
- //float k = (*it).second * (1.0f + fs);
-
- r += k * fr;
- g += k * fg;
- b += k * fb;
- norm += k;
- }
-
- data[4 * (x + y * p->w) + 0] = r / norm;
- data[4 * (x + y * p->w) + 1] = g / norm;
- data[4 * (x + y * p->w) + 2] = b / norm;
- data[4 * (x + y * p->w) + 3] = 0.0;
- }
- }
-
- pipi_release_pixels(dst, p);
- }
-
- static void analyse(pipi_image_t *src)
- {
- pipi_pixels_t *p = pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
- float *data = (float *)p->pixels;
- int i;
-
- for(int dy = 0; dy < dh; dy++)
- for(int dx = 0; dx < dw; dx++)
- {
- float min = 1.1f, max = -0.1f;
- float total = 0.0;
- int xmin = 0, xmax = 0, ymin = 0, ymax = 0;
- int npixels = 0;
-
- for(int iy = RANGE_Y * dy; iy < RANGE_Y * (dy + 1); iy++)
- for(int ix = RANGE_X * dx; ix < RANGE_X * (dx + 1); ix++)
- {
- float lum = 0.0f;
-
- lum += data[4 * (ix + iy * p->w) + 0];
- lum += data[4 * (ix + iy * p->w) + 1];
- lum += data[4 * (ix + iy * p->w) + 2];
-
- if(lum < min)
- {
- min = lum;
- xmin = ix;
- ymin = iy;
- }
-
- if(lum > max)
- {
- max = lum;
- xmax = ix;
- ymax = iy;
- }
-
- total += lum;
- npixels++;
- }
-
- total /= npixels;
-
- float wmin, wmax;
-
- if(total < min + (max - min) / 4)
- wmin = 1.0, wmax = 0.0;
- else if(total < min + (max - min) / 4 * 2)
- wmin = 0.0, wmax = 0.0;
- else if(total < min + (max - min) / 4 * 3)
- wmin = 0.0, wmax = 0.0;
- else
- wmin = 0.0, wmax = 1.0;
-
- //wmin = wmax = 1.0;
- //if(total < min + (max - min) /3 )
- //if((dx + dy) & 1)
- {
- 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],
- wmin);
- }
- //else
- {
- 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],
- wmax);
- }
- }
- }
-
- int main(int argc, char *argv[])
- {
- int opstats[2 * MAX_OPS];
- pipi_image_t *src, *tmp, *dst;
- double error = 1.0;
- int width, height, ret = 0;
-
- /* Load image */
- pipi_set_gamma(1.0);
- src = pipi_load(argv[1]);
- width = pipi_get_image_width(src);
- height = pipi_get_image_height(src);
-
- /* Compute best w/h ratio */
- dw = 1;
- for(int i = 1; i <= TOTAL_POINTS / POINTS_PER_CELL; i++)
- {
- float r = (float)width / (float)height;
- float ir = (float)i / (float)(TOTAL_POINTS / POINTS_PER_CELL / i);
- float dwr = (float)dw / (float)(TOTAL_POINTS / POINTS_PER_CELL / dw);
-
- if(fabs(logf(r / ir)) < fabs(logf(r / dwr)))
- dw = i;
- }
- dh = TOTAL_POINTS / POINTS_PER_CELL / dw;
- fprintf(stderr, "Chosen image ratio: %i:%i\n", dw, dh);
-
- /* Resize and filter image to better state */
- tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y);
- pipi_free(src);
- src = pipi_median_ext(tmp, 2, 2);
-
- /* Analyse image */
- analyse(src);
-
- /* Render what we just computed */
- tmp = pipi_new(dw * RANGE_X, dh * RANGE_Y);
- render(tmp, 0, 0, dw * RANGE_X, dh * RANGE_Y);
- error = pipi_measure_rmsd(src, tmp);
-
- fprintf(stderr, "Distance: %2.10g\n", error);
-
- memset(opstats, 0, sizeof(opstats));
- for(int iter = 0, failures = 0; /*failures < 200 &&*/ iter < 3000; iter++)
- {
- uint32_t oldval;
- pipi_image_t *scrap = pipi_copy(tmp);
-
- /* Choose a point at random */
- int pt = det_rand(npoints);
- oldval = points[pt];
-
- /* Apply a random operation and measure its effect */
- uint8_t op = det_rand(MAX_OPS);
- points[pt] = apply_op(op, oldval);
- render(scrap, 0, 0, dw * RANGE_X, dh * RANGE_Y);
-
- opstats[op * 2]++;
-
- double newerr = pipi_measure_rmsd(src, scrap);
- if(newerr < error)
- {
- pipi_free(tmp);
- tmp = scrap;
- error = newerr;
- fprintf(stderr, "%06i %2.010g after op%i(%i)\n",
- iter, error, op, pt);
- opstats[op * 2 + 1]++;
- failures = 0;
- }
- else
- {
- pipi_free(scrap);
- points[pt] = oldval;
- failures++;
- }
- }
-
- fprintf(stderr, "operation: ");
- for(int i = 0; i < MAX_OPS; i++)
- fprintf(stderr, "%3i ", i);
- fprintf(stderr, "\nattempts: ");
- for(int i = 0; i < MAX_OPS; i++)
- fprintf(stderr, "%3i ", opstats[i * 2]);
- fprintf(stderr, "\nsuccesses: ");
- for(int i = 0; i < MAX_OPS; i++)
- fprintf(stderr, "%3i ", opstats[i * 2 + 1]);
- fprintf(stderr, "\n");
-
- fprintf(stderr, "Distance: %2.10g\n", error);
-
- dst = pipi_resize(tmp, width, height);
- pipi_free(tmp);
-
- /* Save image and bail out */
- pipi_save(dst, "lol.bmp");
- pipi_free(dst);
-
- return ret;
- }
-
|