1
//-----------------------------------------------------------------------
2
// Color Quantization Demo
4
// Author: Roman Podobedov
6
// Romka Graphics: www.ut.ee/~romka
8
// Also in this file implemented Wu's Color Quantizer algorithm (v. 2)
9
// For details see Graphics Gems vol. II, pp. 126-133
11
// Wu's Color Quantizer Algorithm:
13
// Dept. of Computer Science
14
// Univ. of Western Ontario
15
// London, Ontario N6A 5B7
17
// http://www.csd.uwo.ca/faculty/wu/
18
//-----------------------------------------------------------------------
20
//-----------------------------------------------------------------------------
24
// Last modified: 02/02/2002 <--Y2K Compliant! =]
26
// Filename: src-IL/src/il_quantizer.c
28
// Description: Heavily modified by Denton Woods.
30
// 20040223 XIX : Modified so it works better with color requests < 256
31
// pallete always has memory space for 256 entries
32
// used so we can quant down to 255 colors then add a transparent color in there.
34
//-----------------------------------------------------------------------------
36
#include "il_internal.h"
45
ILint r0; // min value, exclusive
46
ILint r1; // max value, inclusive
54
/* Histogram is in elements 1..HISTSIZE along each axis,
55
* element 0 is for base or marginal value
56
* NB: these must start out 0!
59
ILfloat gm2[33][33][33];
60
ILint wt[33][33][33], mr[33][33][33], mg[33][33][33], mb[33][33][33];
61
ILuint size; //image size
62
ILint K; //colour look-up table size
66
ILint WindW, WindH, WindD;
69
static ILint Width, Height, Depth, Comp;
72
ILubyte *buf1, *buf2;*/
80
for (i = 0; i < s; i++) {
88
// Build 3-D color histogram of counts, r/g/b, c^2
89
ILboolean Hist3d(ILubyte *Ir, ILubyte *Ig, ILubyte *Ib, ILint *vwt, ILint *vmr, ILint *vmg, ILint *vmb, ILfloat *m2)
92
ILint inr, ing, inb, table[2560];
95
for (i = 0; i < 256; i++) {
98
Qadd = (ILushort*)ialloc(sizeof(ILushort) * size);
103
imemclear(Qadd, sizeof(ILushort) * size);
105
for (i = 0; i < size; i++) {
106
r = Ir[i]; g = Ig[i]; b = Ib[i];
110
Qadd[i] = ind = (inr<<10)+(inr<<6)+inr+(ing<<5)+ing+inb;
116
m2[ind] += (ILfloat)(table[r]+table[g]+table[b]);
121
/* At conclusion of the histogram step, we can interpret
122
* wt[r][g][b] = sum over voxel of P(c)
123
* mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb
124
* m2[r][g][b] = sum over voxel of c^2*P(c)
125
* Actually each of these should be divided by 'size' to give the usual
126
* interpretation of P() as ranging from 0 to 1, but we needn't do that here.
129
/* We now convert histogram into moments so that we can rapidly calculate
130
* the sums of the above quantities over any desired Box.
134
// Compute cumulative moments
135
ILvoid M3d(ILint *vwt, ILint *vmr, ILint *vmg, ILint *vmb, ILfloat *m2)
139
ILint line, line_r, line_g, line_b, area[33], area_r[33], area_g[33], area_b[33];
140
ILfloat line2, area2[33];
142
for (r = 1; r <= 32; r++) {
143
for (i = 0; i <= 32; i++) {
145
area[i]=area_r[i]=area_g[i]=area_b[i]=0;
147
for (g = 1; g <= 32; g++) {
149
line = line_r = line_g = line_b = 0;
150
for (b = 1; b <= 32; b++) {
151
ind1 = (r<<10) + (r<<6) + r + (g<<5) + g + b; // [r][g][b]
162
ind2 = ind1 - 1089; // [r-1][g][b]
163
vwt[ind1] = vwt[ind2] + area[b];
164
vmr[ind1] = vmr[ind2] + area_r[b];
165
vmg[ind1] = vmg[ind2] + area_g[b];
166
vmb[ind1] = vmb[ind2] + area_b[b];
167
m2[ind1] = m2[ind2] + area2[b];
176
// Compute sum over a Box of any given statistic
177
ILint Vol(Box *cube, ILint mmt[33][33][33])
179
return( mmt[cube->r1][cube->g1][cube->b1]
180
-mmt[cube->r1][cube->g1][cube->b0]
181
-mmt[cube->r1][cube->g0][cube->b1]
182
+mmt[cube->r1][cube->g0][cube->b0]
183
-mmt[cube->r0][cube->g1][cube->b1]
184
+mmt[cube->r0][cube->g1][cube->b0]
185
+mmt[cube->r0][cube->g0][cube->b1]
186
-mmt[cube->r0][cube->g0][cube->b0] );
189
/* The next two routines allow a slightly more efficient calculation
190
* of Vol() for a proposed subBox of a given Box. The sum of Top()
191
* and Bottom() is the Vol() of a subBox split in the given direction
192
* and with the specified new upper bound.
195
// Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1
196
// (depending on dir)
197
ILint Bottom(Box *cube, ILubyte dir, ILint mmt[33][33][33])
202
return( -mmt[cube->r0][cube->g1][cube->b1]
203
+mmt[cube->r0][cube->g1][cube->b0]
204
+mmt[cube->r0][cube->g0][cube->b1]
205
-mmt[cube->r0][cube->g0][cube->b0] );
208
return( -mmt[cube->r1][cube->g0][cube->b1]
209
+mmt[cube->r1][cube->g0][cube->b0]
210
+mmt[cube->r0][cube->g0][cube->b1]
211
-mmt[cube->r0][cube->g0][cube->b0] );
214
return( -mmt[cube->r1][cube->g1][cube->b0]
215
+mmt[cube->r1][cube->g0][cube->b0]
216
+mmt[cube->r0][cube->g1][cube->b0]
217
-mmt[cube->r0][cube->g0][cube->b0] );
224
// Compute remainder of Vol(cube, mmt), substituting pos for
225
// r1, g1, or b1 (depending on dir)
226
ILint Top(Box *cube, ILubyte dir, ILint pos, ILint mmt[33][33][33])
231
return( mmt[pos][cube->g1][cube->b1]
232
-mmt[pos][cube->g1][cube->b0]
233
-mmt[pos][cube->g0][cube->b1]
234
+mmt[pos][cube->g0][cube->b0] );
237
return( mmt[cube->r1][pos][cube->b1]
238
-mmt[cube->r1][pos][cube->b0]
239
-mmt[cube->r0][pos][cube->b1]
240
+mmt[cube->r0][pos][cube->b0] );
243
return( mmt[cube->r1][cube->g1][pos]
244
-mmt[cube->r1][cube->g0][pos]
245
-mmt[cube->r0][cube->g1][pos]
246
+mmt[cube->r0][cube->g0][pos] );
254
// Compute the weighted variance of a Box
255
// NB: as with the raw statistics, this is really the variance * size
256
ILfloat Var(Box *cube)
258
ILfloat dr, dg, db, xx;
260
dr = (ILfloat)Vol(cube, mr);
261
dg = (ILfloat)Vol(cube, mg);
262
db = (ILfloat)Vol(cube, mb);
263
xx = gm2[cube->r1][cube->g1][cube->b1]
264
-gm2[cube->r1][cube->g1][cube->b0]
265
-gm2[cube->r1][cube->g0][cube->b1]
266
+gm2[cube->r1][cube->g0][cube->b0]
267
-gm2[cube->r0][cube->g1][cube->b1]
268
+gm2[cube->r0][cube->g1][cube->b0]
269
+gm2[cube->r0][cube->g0][cube->b1]
270
-gm2[cube->r0][cube->g0][cube->b0];
272
return xx - (dr*dr+dg*dg+db*db) / (ILfloat)Vol(cube, wt);
275
/* We want to minimize the sum of the variances of two subBoxes.
276
* The sum(c^2) terms can be ignored since their sum over both subBoxes
277
* is the same (the sum for the whole Box) no matter where we split.
278
* The remaining terms have a minus sign in the variance formula,
279
* so we drop the minus sign and MAXIMIZE the sum of the two terms.
282
ILfloat Maximize(Box *cube, ILubyte dir, ILint first, ILint last, ILint *cut,
283
ILint whole_r, ILint whole_g, ILint whole_b, ILint whole_w)
285
ILint half_r, half_g, half_b, half_w;
286
ILint base_r, base_g, base_b, base_w;
290
base_r = Bottom(cube, dir, mr);
291
base_g = Bottom(cube, dir, mg);
292
base_b = Bottom(cube, dir, mb);
293
base_w = Bottom(cube, dir, wt);
297
for (i = first; i < last; ++i) {
298
half_r = base_r + Top(cube, dir, i, mr);
299
half_g = base_g + Top(cube, dir, i, mg);
300
half_b = base_b + Top(cube, dir, i, mb);
301
half_w = base_w + Top(cube, dir, i, wt);
302
// Now half_x is sum over lower half of Box, if split at i
303
if (half_w == 0) { // subBox could be empty of pixels!
304
continue; // never split into an empty Box
307
temp = ((ILfloat)half_r*half_r + (ILfloat)half_g * half_g +
308
(ILfloat)half_b*half_b) / half_w;
311
half_r = whole_r - half_r;
312
half_g = whole_g - half_g;
313
half_b = whole_b - half_b;
314
half_w = whole_w - half_w;
315
if (half_w == 0) { // subBox could be empty of pixels!
316
continue; // never split into an empty Box
319
temp += ((ILfloat)half_r*half_r + (ILfloat)half_g * half_g +
320
(ILfloat)half_b*half_b) / half_w;
333
ILint Cut(Box *set1, Box *set2)
336
ILint cutr, cutg, cutb;
337
ILfloat maxr, maxg, maxb;
338
ILint whole_r, whole_g, whole_b, whole_w;
340
whole_r = Vol(set1, mr);
341
whole_g = Vol(set1, mg);
342
whole_b = Vol(set1, mb);
343
whole_w = Vol(set1, wt);
345
maxr = Maximize(set1, RED, set1->r0+1, set1->r1, &cutr, whole_r, whole_g, whole_b, whole_w);
346
maxg = Maximize(set1, GREEN, set1->g0+1, set1->g1, &cutg, whole_r, whole_g, whole_b, whole_w);
347
maxb = Maximize(set1, BLUE, set1->b0+1, set1->b1, &cutb, whole_r, whole_g, whole_b, whole_w);
349
if ((maxr >= maxg) && (maxr >= maxb)) {
352
return 0; // can't split the Box
354
else if ((maxg >= maxr) && (maxg >= maxb))
366
set2->r0 = set1->r1 = cutr;
371
set2->g0 = set1->g1 = cutg;
376
set2->b0 = set1->b1 = cutb;
382
set1->vol = (set1->r1-set1->r0) * (set1->g1-set1->g0) * (set1->b1-set1->b0);
383
set2->vol = (set2->r1-set2->r0) * (set2->g1-set2->g0) * (set2->b1-set2->b0);
389
void Mark(struct Box *cube, int label, unsigned char *tag)
393
for (r = cube->r0 + 1; r <= cube->r1; r++) {
394
for (g = cube->g0 + 1; g <= cube->g1; g++) {
395
for (b = cube->b0 + 1; b <= cube->b1; b++) {
396
tag[(r<<10) + (r<<6) + r + (g<<5) + g + b] = label;
404
ILimage *iQuantizeImage(ILimage *Image, ILuint NumCols)
408
ILubyte lut_r[MAXCOLOR], lut_g[MAXCOLOR], lut_b[MAXCOLOR];
412
ILfloat vv[MAXCOLOR], temp;
414
ILubyte *NewData = NULL, *Palette = NULL;
415
ILimage *TempImage = NULL, *NewImage = NULL;
416
ILubyte *Ir = NULL, *Ig = NULL, *Ib = NULL;
418
ILint num_alloced_colors; // number of colors we allocated space for in palette, as NumCols but eill not be less than 256
420
num_alloced_colors=NumCols;
421
if(num_alloced_colors<256) { num_alloced_colors=256; }
424
NewImage = iCurImage;
426
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
427
iCurImage = NewImage;
431
if (TempImage == NULL)
434
buffer = Image->Data;
435
WindW = Width = Image->Width;
436
WindH = Height = Image->Height;
437
WindD = Depth = Image->Depth;
441
//color_num = ImagePrecalculate(Image);
443
NewData = (ILubyte*)ialloc(Image->Width * Image->Height * Image->Depth);
444
Palette = (ILubyte*)ialloc(3 * num_alloced_colors);
445
if (!NewData || !Palette) {
451
Ir = ialloc(Width * Height * Depth);
452
Ig = ialloc(Width * Height * Depth);
453
Ib = ialloc(Width * Height * Depth);
454
if (!Ir || !Ig || !Ib) {
463
size = Width * Height * Depth;
466
register ILuint v_size = size>>4;
467
register ILuint pos = 0;
469
register vector unsigned char d0,d1,d2;
470
register vector unsigned char red[3],blu[3],green[3];
473
vector unsigned char vec;
474
vector unsigned int load;
475
} mask_1, mask_2, mask_3;
477
mask_1.load = (vector unsigned int){0xFF0000FF,0x0000FF00,0x00FF0000,0xFF0000FF};
478
mask_2.load = (vector unsigned int){0x00FF0000,0xFF0000FF,0x0000FF00,0x00FF0000};
479
mask_2.load = (vector unsigned int){0x0000FF00,0x00FF0000,0xFF0000FF,0x0000FF00};
481
while( v_size >= 0 ) {
482
d0 = vec_ld(pos,TempImage->Data);
483
d1 = vec_ld(pos+16,TempImage->Data);
484
d2 = vec_ld(pos+32,TempImage->Data);
486
red[0] = vec_and(d0,mask_1.vec);
487
green[0] = vec_and(d0,mask_2.vec);
488
blu[0] = vec_and(d0,mask_3.vec);
490
red[1] = vec_and(d1,mask_3.vec);
491
green[1] = vec_and(d1,mask_1.vec);
492
blu[1] = vec_and(d1,mask_2.vec);
494
red[2] = vec_and(d2,mask_2.vec);
495
green[2] = vec_and(d2,mask_3.vec);
496
blu[2] = vec_and(d2,mask_1.vec);
498
vec_st(red[0],pos,Ir);
499
vec_st(red[1],pos+16,Ir);
500
vec_st(red[2],pos+32,Ir);
502
vec_st(blu[0],pos,Ib);
503
vec_st(blu[1],pos+16,Ib);
504
vec_st(blu[2],pos+32,Ib);
506
vec_st(green[0],pos,Ig);
507
vec_st(green[1],pos+16,Ig);
508
vec_st(green[2],pos+32,Ig);
515
for (k = 0; k < size; k++) {
516
Ir[k] = TempImage->Data[k * 3];
517
Ig[k] = TempImage->Data[k * 3 + 1];
518
Ib[k] = TempImage->Data[k * 3 + 2];
522
size = Width * Height * Depth;
525
// Set new colors number
529
// Begin Wu's color quantization algorithm
531
// May have "leftovers" from a previous run.
533
imemclear(gm2, 33 * 33 * 33 * sizeof(ILfloat));
534
imemclear(wt, 33 * 33 * 33 * sizeof(ILint));
535
imemclear(mr, 33 * 33 * 33 * sizeof(ILint));
536
imemclear(mg, 33 * 33 * 33 * sizeof(ILint));
537
imemclear(mb, 33 * 33 * 33 * sizeof(ILint));
539
if (!Hist3d(Ir, Ig, Ib, (ILint*)wt, (ILint*)mr, (ILint*)mg, (ILint*)mb, (ILfloat*)gm2))
542
M3d((ILint*)wt, (ILint*)mr, (ILint*)mg, (ILint*)mb, (ILfloat*)gm2);
544
cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
545
cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
547
for (i = 1; i < K; ++i) {
548
if (Cut(&cube[next], &cube[i])) { // volume test ensures we won't try to cut one-cell Box */
549
vv[next] = (cube[next].vol>1) ? Var(&cube[next]) : 0.0f;
550
vv[i] = (cube[i].vol>1) ? Var(&cube[i]) : 0.0f;
553
vv[next] = 0.0; // don't try to split this Box again
554
i--; // didn't create Box i
558
for (k = 1; (ILint)k <= i; ++k) {
560
temp = vv[k]; next = k;
571
tag = (ILubyte*)ialloc(33 * 33 * 33 * sizeof(ILubyte));
574
for (k = 0; (ILint)k < K; k++) {
575
Mark(&cube[k], k, tag);
576
weight = Vol(&cube[k], wt);
578
lut_r[k] = (ILubyte)(Vol(&cube[k], mr) / weight);
579
lut_g[k] = (ILubyte)(Vol(&cube[k], mg) / weight);
580
lut_b[k] = (ILubyte)(Vol(&cube[k], mb) / weight);
584
lut_r[k] = lut_g[k] = lut_b[k] = 0;
588
for (i = 0; i < (ILint)size; i++) {
589
NewData[i] = tag[Qadd[i]];
594
for (k = 0; k < NumCols; k++) {
595
Palette[k * 3] = lut_b[k];
596
Palette[k * 3 + 1] = lut_g[k];
597
Palette[k * 3 + 2] = lut_r[k];
600
else { // If colors more than 256
601
// Begin Octree quantization
602
//Quant_Octree(Image->Width, Image->Height, Image->Bpp, buffer2, NewData, Palette, K);
603
ilSetError(IL_INTERNAL_ERROR); // Can't get much more specific than this.
610
ilCloseImage(TempImage);
612
NewImage = (ILimage*)icalloc(sizeof(ILimage), 1);
613
if (NewImage == NULL) {
616
ilCopyImageAttr(NewImage, Image);
618
NewImage->Bps = Image->Width;
619
NewImage->SizeOfPlane = NewImage->Bps * Image->Height;
620
NewImage->SizeOfData = NewImage->SizeOfPlane;
621
NewImage->Format = IL_COLOUR_INDEX;
622
NewImage->Type = IL_UNSIGNED_BYTE;
624
NewImage->Pal.Palette = Palette;
625
NewImage->Pal.PalSize = 256 * 3;
626
NewImage->Pal.PalType = IL_PAL_BGR24;
627
NewImage->Data = NewData;