From e23268c286ef826fdc3b8f3a04f0a4746513035d Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 16 Aug 2008 00:54:11 +0000 Subject: [PATCH] * img2rubik.c: factor out the hull generation so that we can also build a convex hull of the Neugebauer primaries. git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@2730 92316355-f0b4-4df1-b90c-862c8a59935f --- examples/img2rubik.c | 213 +++++++++++++++++++++++++++++-------------- 1 file changed, 143 insertions(+), 70 deletions(-) diff --git a/examples/img2rubik.c b/examples/img2rubik.c index f52259b..d12b452 100644 --- a/examples/img2rubik.c +++ b/examples/img2rubik.c @@ -14,77 +14,94 @@ #define BRIGHT(x) (0.299*(x)[0] + 0.587*(x)[1] + 0.114*(x)[2]) -#define STEPS 1024 +#define MAXCOLORS 16 +#define STEPS 256 #define EPSILON (0.000001) -int main(int argc, char *argv[]) +typedef struct { - double palette[][3] = - { - { 0.8, 0.0, 0.0 }, /* red */ - { 0.0, 0.8, 0.0 }, /* green */ - { 0.0, 0.0, 0.7 }, /* blue */ - { 1.0, 1.0, 1.0 }, /* white */ - { 0.9, 0.9, 0.0 }, /* yellow */ - { 0.8, 0.4, 0.0 }, /* orange */ - }; -#define NCOLORS ((int)(sizeof(palette)/sizeof(*palette))) + double pts[STEPS + 1][MAXCOLORS * (MAXCOLORS - 1) / 2][6]; + int hullsize[STEPS + 1]; + double bary[STEPS + 1][3]; +} +hull_t; +static double const y[3] = { .299, .587, .114 }; +static double u[3], v[3]; +static int ylen; + +/* + * Find two base vectors for the chrominance planes. + */ +static void init_uv(void) +{ + double tmp; + + ylen = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); + + u[0] = y[1]; + u[1] = -y[0]; + u[2] = 0; + tmp = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]); + u[0] /= tmp; u[1] /= tmp; u[2] /= tmp; + + v[0] = y[1] * u[2] - y[2] * u[1]; + v[1] = y[2] * u[0] - y[0] * u[2]; + v[2] = y[0] * u[1] - y[1] * u[0]; + tmp = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] /= tmp; v[1] /= tmp; v[2] /= tmp; +} + +/* + * Compute the convex hull of a given palette. + */ +static hull_t *compute_hull(int ncolors, double const *palette) +{ + hull_t *ret = malloc(sizeof(hull_t)); double tmp; int i, j; + double pal[ncolors][3]; + for(i = 0; i < ncolors; i++) + { + pal[i][0] = palette[i * 3]; + pal[i][1] = palette[i * 3 + 1]; + pal[i][2] = palette[i * 3 + 2]; + } + /* * 1. Find the darkest and lightest colours */ double *dark = NULL, *light = NULL; double min = 1.0, max = 0.0; - for(i = 0; i < NCOLORS; i++) + for(i = 0; i < ncolors; i++) { - double p = BRIGHT(palette[i]); + double p = BRIGHT(pal[i]); if(p < min) { - dark = palette[i]; + dark = pal[i]; min = p; } if(p > max) { - light = palette[i]; + light = pal[i]; max = p; } } - /* - * 2. Find two base vectors for the chrominance planes - * FIXME: this doesn't work in all cases because u can be null - */ - double y[3], u[3], v[3]; - double ylen; + double gray[3]; - y[0] = light[0] - dark[0]; - y[1] = light[1] - dark[1]; - y[2] = light[2] - dark[2]; - ylen = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); - - u[0] = y[1]; - u[1] = -y[0]; - u[2] = 0; - tmp = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]); - u[0] /= tmp; u[1] /= tmp; u[2] /= tmp; - - v[0] = y[1] * u[2] - y[2] * u[1]; - v[1] = y[2] * u[0] - y[0] * u[2]; - v[2] = y[0] * u[1] - y[1] * u[0]; - tmp = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - v[0] /= tmp; v[1] /= tmp; v[2] /= tmp; + gray[0] = light[0] - dark[0]; + gray[1] = light[1] - dark[1]; + gray[2] = light[2] - dark[2]; /* * 3. Browse the grey axis and do stuff */ - double bary[STEPS + 1][3]; int n; for(n = 0; n <= STEPS; n++) { - double pts[NCOLORS * (NCOLORS - 1) / 2][6]; + double pts[ncolors * (ncolors - 1) / 2][6]; double ptmp[6]; #define SWAP(p1,p2) do { memcpy(ptmp, p1, sizeof(ptmp)); \ memcpy(p1, p2, sizeof(ptmp)); \ @@ -93,19 +110,19 @@ int main(int argc, char *argv[]) int npts = 0; double p0[3]; - p0[0] = dark[0] + t * y[0]; - p0[1] = dark[1] + t * y[1]; - p0[2] = dark[2] + t * y[2]; + p0[0] = dark[0] + t * gray[0]; + p0[1] = dark[1] + t * gray[1]; + p0[2] = dark[2] + t * gray[2]; /* * 3.1. Find all edges that intersect the t.y + (u,v) plane */ - for(i = 0; i < NCOLORS; i++) + for(i = 0; i < ncolors; i++) { double k1[3]; - k1[0] = palette[i][0] - dark[0]; - k1[1] = palette[i][1] - dark[1]; - k1[2] = palette[i][2] - dark[2]; + k1[0] = pal[i][0] - p0[0]; + k1[1] = pal[i][1] - p0[1]; + k1[2] = pal[i][2] - p0[2]; tmp = sqrt(k1[0] * k1[0] + k1[1] * k1[1] + k1[2] * k1[2]); /* If k1.y > t.y.y, we don't want this point */ @@ -113,15 +130,15 @@ int main(int argc, char *argv[]) if(yk1 > t * ylen * ylen + EPSILON) continue; - for(j = 0; j < NCOLORS; j++) + for(j = 0; j < ncolors; j++) { if(i == j) continue; double k2[3]; - k2[0] = palette[j][0] - dark[0]; - k2[1] = palette[j][1] - dark[1]; - k2[2] = palette[j][2] - dark[2]; + k2[0] = pal[j][0] - p0[0]; + k2[1] = pal[j][1] - p0[1]; + k2[2] = pal[j][2] - p0[2]; tmp = sqrt(k2[0] * k2[0] + k2[1] * k2[1] + k2[2] * k2[2]); /* If k2.y < t.y.y, we don't want this point */ @@ -135,9 +152,9 @@ int main(int argc, char *argv[]) double s = yk1 == yk2 ? 0.5 : (t * ylen * ylen - yk1) / (yk2 - yk1); - pts[npts][0] = dark[0] + k1[0] + s * (k2[0] - k1[0]); - pts[npts][1] = dark[1] + k1[1] + s * (k2[1] - k1[1]); - pts[npts][2] = dark[2] + k1[2] + s * (k2[2] - k1[2]); + pts[npts][0] = p0[0] + k1[0] + s * (k2[0] - k1[0]); + pts[npts][1] = p0[1] + k1[1] + s * (k2[1] - k1[1]); + pts[npts][2] = p0[2] + k1[2] + s * (k2[2] - k1[2]); npts++; } } @@ -150,12 +167,12 @@ int main(int argc, char *argv[]) /* Make our problem a 2-D problem. */ for(i = 0; i < npts; i++) { - pts[i][X] = (pts[i][0] - dark[0]) * u[0] - + (pts[i][1] - dark[1]) * u[1] - + (pts[i][2] - dark[2]) * u[2]; - pts[i][Y] = (pts[i][0] - dark[0]) * v[0] - + (pts[i][1] - dark[1]) * v[1] - + (pts[i][2] - dark[2]) * v[2]; + pts[i][X] = (pts[i][0] - p0[0]) * u[0] + + (pts[i][1] - p0[1]) * u[1] + + (pts[i][2] - p0[2]) * u[2]; + pts[i][Y] = (pts[i][0] - p0[0]) * v[0] + + (pts[i][1] - p0[1]) * v[1] + + (pts[i][2] - p0[2]) * v[2]; } /* Find the leftmost point */ @@ -234,18 +251,59 @@ int main(int argc, char *argv[]) cty = 0.5 * (pts[0][Y] + pts[right][Y]); } - bary[n][0] = p0[0] + ctx * u[0] + cty * v[0]; - bary[n][1] = p0[1] + ctx * u[1] + cty * v[1]; - bary[n][2] = p0[2] + ctx * u[2] + cty * v[2]; + /* + * 3.3. Store the barycentre and convex hull information. + */ + + ret->bary[n][0] = p0[0] + ctx * u[0] + cty * v[0]; + ret->bary[n][1] = p0[1] + ctx * u[1] + cty * v[1]; + ret->bary[n][2] = p0[2] + ctx * u[2] + cty * v[2]; +//if(ncolors == 6) printf("%i %g %g %g\n", n, ret->bary[n][0], ret->bary[n][1], ret->bary[n][2]); + + for(i = 0; i < npts; i++) + { + ret->pts[n][i][0] = pts[i][0]; + ret->pts[n][i][1] = pts[i][1]; + ret->pts[n][i][2] = pts[i][2]; + } + ret->hullsize[n] = npts; } + return ret; +} + + +int main(int argc, char *argv[]) +{ + static double const rgbpal[] = + { + 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, + 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, + }; + + static double const mypal[] = + { + 0.8, 0.0, 0.0, /* red */ + 0.0, 0.8, 0.0, /* green */ + 0.0, 0.0, 0.6, /* blue */ + 1.0, 1.0, 1.0, /* white */ + 0.9, 0.9, 0.0, /* yellow */ + 0.8, 0.4, 0.0, /* orange */ + }; + + int i, j; + + init_uv(); + hull_t *rgbhull = compute_hull(8, rgbpal); + hull_t *myhull = compute_hull(6, mypal); /* - * Last step: load image and change its palette. + * 4. Load image and change its palette. */ + pipi_image_t *src = pipi_load(argv[1]); - pipi_pixels_t *srcp = pipi_getpixels(src, PIPI_PIXELS_Y_F); + pipi_pixels_t *srcp = pipi_getpixels(src, PIPI_PIXELS_RGBA_F); float *srcdata = (float *)srcp->pixels; int w = srcp->w, h = srcp->h; @@ -257,11 +315,26 @@ int main(int argc, char *argv[]) for(j = 0; j < h; j++) for(i = 0; i < w; i++) { - /* FIXME: Imlib fucks this up */ - double p = srcdata[j * w + i]; - dstdata[4 * (j * w + i)] = bary[(int)(p * STEPS)][2]; - dstdata[4 * (j * w + i) + 1] = bary[(int)(p * STEPS)][1]; - dstdata[4 * (j * w + i) + 2] = bary[(int)(p * STEPS)][0]; + double p[3]; + /* FIXME: Imlib fucks up the RGB order. */ + p[2] = srcdata[4 * (j * w + i)]; + p[1] = srcdata[4 * (j * w + i) + 1]; + p[0] = srcdata[4 * (j * w + i) + 2]; + double gray = BRIGHT(p); + + double dx = (p[0] - gray * y[0]) * u[0] + + (p[1] - gray * y[1]) * u[1] + + (p[2] - gray * y[2]) * u[2]; + double dy = (p[0] - gray * y[0]) * v[0] + + (p[1] - gray * y[1]) * v[1] + + (p[2] - gray * y[2]) * v[2]; + + dstdata[4 * (j * w + i)] = myhull->bary[(int)(gray * STEPS)][2] + + dx * u[2] * .3 + dy * v[2] * .3; + dstdata[4 * (j * w + i) + 1] = myhull->bary[(int)(gray * STEPS)][1] + + dx * u[1] * .3 + dy * v[1] * .3; + dstdata[4 * (j * w + i) + 2] = myhull->bary[(int)(gray * STEPS)][0] + + dx * u[0] * .3 + dy * v[0] * .3; } pipi_save(dst, argv[2]);