|
|
@@ -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]); |
|
|
|