From e23268c286ef826fdc3b8f3a04f0a4746513035d Mon Sep 17 00:00:00 2001
From: sam <sam@92316355-f0b4-4df1-b90c-862c8a59935f>
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]);