/Users/lyon/j4p/src/ip/color/Wu.java
|
1 /*
2 Master's Project step1
3 Color quantization using Wu's method
4 "Efficient Statistical Computations for
5 Optimal Color Quantization"
6 in Graphics Gem Vol II, edited by James Arvo, AP.
7 pp 116-125
8 Based on C code available from:
9 <http://www.cis.ohio-state.edu/~parent/classes/781/ip.graphics/GG2>
10
11 Hak Kywn Roh
12
13 */
14
15 package ip.color;
16
17
18 class Box {
19 public int r0; /* min value, exclusive */
20 public int r1; /* max value, inclusive */
21 public int g0;
22 public int g1;
23 public int b0;
24 public int b1;
25 public int vol;
26
27 public Box() {
28 }
29
30
31 }
32
33 public class Wu {
34 static final int MAXCOLOR = 256;
35 static final int RED = 2;
36 static final int GREEN = 1;
37 static final int BLUE = 0;
38
39 int size, K;
40 int qs = 33; //quant size
41 float m2[][][] = new float[qs][qs][qs];
42 int wt[][][] = new int[qs][qs][qs];
43 int mr[][][] = new int[qs][qs][qs];
44 int mg[][][] = new int[qs][qs][qs];
45 int mb[][][] = new int[qs][qs][qs];
46 int qadd[][];
47 short ir[][], ig[][], ib[][];
48 int height, width;
49
50
51 public void wuQuantization(short r[][],
52 short g[][],
53 short b[][],
54 int w,
55 int h,
56 int nK) {
57 width = w;
58 height = h;
59 ir = r;
60 ig = g;
61 ib = b;
62 size = width * height;
63 K = nK;
64
65 int next, i, k, x, y, z;
66 Box[] cube = new Box[MAXCOLOR];
67 int tag[][][] = new int[qs][qs][qs];
68 short lutr[] = new short[MAXCOLOR];
69 short lutg[] = new short[MAXCOLOR];
70 short lutb[] = new short[MAXCOLOR];
71 float vv[] = new float[MAXCOLOR];
72 float temp;
73 long weight;
74
75 Hist3d(wt, mr, mg, mb, m2);
76 System.out.println("Histogram done...");
77
78 M3d(wt, mr, mg, mb, m2);
79 System.out.println("Moments done...");
80
81 for (z = 0; z < MAXCOLOR; z++)
82 cube[z] = new Box();
83
84 cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
85 cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
86
87 next = 0;
88
89 for (i = 1; i < K; i++) {
90 if (Cut(cube[next], cube[i]) != -1) {
91 if (cube[next].vol > 1)
92 vv[next] = Var(cube[next]);
93 else
94 vv[next] = (float) 0.0;
95
96 if (cube[i].vol > 1)
97 vv[i] = Var(cube[i]);
98 else
99 vv[i] = (float) 0.0;
100 } else {
101 vv[next] = (float) 0.0;
102 i--;
103 }
104 next = 0;
105 temp = vv[0];
106 for (k = 1; k <= i; k++)
107 if (vv[k] > temp) {
108 temp = vv[k];
109 next = k;
110 }
111 if (temp <= 0.0) {
112 K = i + 1;
113 System.out.println("Only got " + K + " boxes.");
114 break;
115 }
116 }
117 System.out.println("Partition done...");
118
119
120 for (k = 0; k < K; k++) {
121 Mark(cube[k], k, tag);
122
123 weight = Vol(cube[k], wt);
124 if (weight != 0) {
125 lutr[k] = (short) (Vol(cube[k], mr) / weight);
126 lutg[k] = (short) (Vol(cube[k], mg) / weight);
127 lutb[k] = (short) (Vol(cube[k], mb) / weight);
128 } else {
129 System.out.println("Bogus box " + k);
130 lutr[k] = lutg[k] = lutb[k] = 0;
131 }
132 }
133
134
135 for (y = 0; y < h; y++)
136 for (x = 0; x < w; x++) {
137 int pr = qadd[x][y] / 1089;
138 int pt = qadd[x][y] % 1089;
139 int pg = pt / 33;
140 int pb = pt % 33;
141
142 qadd[x][y] = tag[pr][pg][pb];
143 }
144
145
146 for (y = 0; y < h; y++)
147 for (x = 0; x < w; x++) {
148 r[x][y] = lutr[qadd[x][y]];
149 g[x][y] = lutg[qadd[x][y]];
150 b[x][y] = lutb[qadd[x][y]];
151 }
152
153 }
154
155 public void Hist3d(int vwt[][][],
156 int vmr[][][],
157 int vmg[][][],
158 int vmb[][][],
159 float vm2[][][]) {
160 short red, green, blue;
161 int i, inr, ing, inb;
162 int table[] = new int[MAXCOLOR];
163 short tr, tg, tb;
164
165 for (i = 0; i < MAXCOLOR; i++)
166 table[i] = i * i;
167
168 qadd = new int[width][height];
169
170 for (int y = 0; y < height; y++)
171 for (int x = 0; x < width; x++) {
172 tr = ir[x][y];
173 tg = ig[x][y];
174 tb = ib[x][y];
175 inr = (tr >> 3) + 1;
176 ing = (tg >> 3) + 1;
177 inb = (tb >> 3) + 1;
178 qadd[x][y] = ((inr << 10) +
179 (inr << 6) +
180 inr +
181 (ing << 5) +
182 ing +
183 inb);
184 vwt[inr][ing][inb]++;
185 vmr[inr][ing][inb] += tr;
186 vmg[inr][ing][inb] += tg;
187 vmb[inr][ing][inb] += tb;
188 vm2[inr][ing][inb] +=
189 (float) (table[tr] + table[tg] + table[tb]);
190 }
191 }
192
193 public void M3d(int vwt[][][],
194 int vmr[][][],
195 int vmg[][][],
196 int vmb[][][],
197 float vm2[][][]) {
198 short i, tr, tg, tb;
199 int line, liner, lineg, lineb;
200 int area[] = new int[33];
201 int arear[] = new int[33];
202 int areag[] = new int[33];
203 int areab[] = new int[33];
204 float line2;
205 float area2[] = new float[33];
206
207 for (tr = 1; tr <= 32; tr++) {
208 for (i = 0; i <= 32; i++)
209 area2[i] = area[i] = arear[i] = areag[i] = areab[i] = 0;
210 for (tg = 1; tg <= 32; tg++) {
211 line2 = line = liner = lineg = lineb = 0;
212 for (tb = 1; tb <= 32; tb++) {
213 line += vwt[tr][tg][tb];
214 liner += vmr[tr][tg][tb];
215 lineg += vmg[tr][tg][tb];
216 lineb += vmb[tr][tg][tb];
217 line2 += vm2[tr][tg][tb];
218
219 area[tb] += line;
220 arear[tb] += liner;
221 areag[tb] += lineg;
222 areab[tb] += lineb;
223 area2[tb] += line2;
224
225 vwt[tr][tg][tb] = vwt[tr - 1][tg][tb] + area[tb];
226 vmr[tr][tg][tb] = vmr[tr - 1][tg][tb] + arear[tb];
227 vmg[tr][tg][tb] = vmg[tr - 1][tg][tb] + areag[tb];
228 vmb[tr][tg][tb] = vmb[tr - 1][tg][tb] + areab[tb];
229 vm2[tr][tg][tb] = vm2[tr - 1][tg][tb] + area2[tb];
230
231 }
232 }
233 }
234
235 }
236
237 public long Vol(Box cube, int mmt[][][]) {
238 return (mmt[cube.r1][cube.g1][cube.b1]
239 -
240 mmt[cube.r1][cube.g1][cube.b0]
241 - mmt[cube.r1][cube.g0][cube.b1]
242 + mmt[cube.r1][cube.g0][cube.b0]
243 - mmt[cube.r0][cube.g1][cube.b1]
244 +
245 mmt[cube.r0][cube.g1][cube.b0]
246 + mmt[cube.r0][cube.g0][cube.b1]
247 - mmt[cube.r0][cube.g0][cube.b0]);
248 }
249
250 public long Bottom(Box cube, int dir, int mmt[][][]) {
251 switch (dir) {
252 case RED:
253 return (-mmt[cube.r0][cube.g1][cube.b1]
254 +
255 mmt[cube.r0][cube.g1][cube.b0]
256 + mmt[cube.r0][cube.g0][cube.b1]
257 - mmt[cube.r0][cube.g0][cube.b0]);
258 case GREEN:
259 return (-mmt[cube.r1][cube.g0][cube.b1]
260 +
261 mmt[cube.r1][cube.g0][cube.b0]
262 + mmt[cube.r0][cube.g0][cube.b1]
263 - mmt[cube.r0][cube.g0][cube.b0]);
264 case BLUE:
265 return (-mmt[cube.r1][cube.g1][cube.b0]
266 +
267 mmt[cube.r1][cube.g0][cube.b0]
268 + mmt[cube.r0][cube.g1][cube.b0]
269 - mmt[cube.r0][cube.g0][cube.b0]);
270 }
271
272 return (long) 1;
273 }
274
275 public long Top(Box cube, int dir, int pos,
276 int mmt[][][]) {
277 switch (dir) {
278 case RED:
279 return (mmt[pos][cube.g1][cube.b1]
280 -
281 mmt[pos][cube.g1][cube.b0]
282 - mmt[pos][cube.g0][cube.b1]
283 + mmt[pos][cube.g0][cube.b0]);
284 case GREEN:
285 return (mmt[cube.r1][pos][cube.b1]
286 -
287 mmt[cube.r1][pos][cube.b0]
288 - mmt[cube.r0][pos][cube.b1]
289 + mmt[cube.r0][pos][cube.b0]);
290 case BLUE:
291 return (mmt[cube.r1][cube.g1][pos]
292 -
293 mmt[cube.r1][cube.g0][pos]
294 - mmt[cube.r0][cube.g1][pos]
295 + mmt[cube.r0][cube.g0][pos]);
296 }
297
298 return (long) 1;
299 }
300
301 public float Var(Box cube) {
302 float dr, dg, db, xx;
303
304 dr = Vol(cube, mr);
305 dg = Vol(cube, mg);
306 db = Vol(cube, mb);
307 xx = m2[cube.r1][cube.g1][cube.b1]
308 -
309 m2[cube.r1][cube.g1][cube.b0]
310 - m2[cube.r1][cube.g0][cube.b1]
311 + m2[cube.r1][cube.g0][cube.b0]
312 - m2[cube.r0][cube.g1][cube.b1]
313 +
314 m2[cube.r0][cube.g1][cube.b0]
315 + m2[cube.r0][cube.g0][cube.b1]
316 - m2[cube.r0][cube.g0][cube.b0];
317
318 return (xx -
319 (dr * dr + dg * dg + db * db) / (float) Vol(cube, wt));
320 }
321
322 public float Maximize(Box cube, int dir, int first, int last,
323 int cut[],
324 long wholer,
325 long wholeg,
326 long wholeb,
327 long wholew) {
328 long halfr, halfg, halfb, halfw;
329 long baser, baseg, baseb, basew;
330 int i;
331 float temp, max;
332
333 baser = Bottom(cube, dir, mr);
334 baseg = Bottom(cube, dir, mg);
335 baseb = Bottom(cube, dir, mb);
336 basew = Bottom(cube, dir, wt);
337 max = (float) 0.0;
338 cut[0] = -1;
339
340 for (i = first; i < last; i++) {
341 halfr = baser + Top(cube, dir, i, mr);
342 halfg = baseg + Top(cube, dir, i, mg);
343 halfb = baseb + Top(cube, dir, i, mb);
344 halfw = basew + Top(cube, dir, i, wt);
345
346 if (halfw == 0)
347 continue;
348 else
349 temp = ((float) halfr * halfr +
350 (float) halfg * halfg +
351 (float) halfb * halfb) / halfw;
352
353 halfr = wholer - halfr;
354 halfg = wholeg - halfg;
355 halfb = wholeb - halfb;
356 halfw = wholew - halfw;
357
358 if (halfw == 0)
359 continue;
360 else
361 temp += ((float) halfr * halfr +
362 (float) halfg * halfg +
363 (float) halfb * halfb) / halfw;
364
365 if (temp > max) {
366 max = temp;
367 cut[0] = i;
368 }
369 }
370
371 return (max);
372 }
373
374 public int Cut(Box set1, Box set2) {
375 int dir;
376 int cutr[] = new int[1];
377 int cutg[] = new int[1];
378 int cutb[] = new int[1];
379 float maxr, maxg, maxb;
380 long wholer, wholeg, wholeb, wholew;
381
382 wholer = Vol(set1, mr);
383 wholeg = Vol(set1, mg);
384 wholeb = Vol(set1, mb);
385 wholew = Vol(set1, wt);
386
387
388 maxr = Maximize(set1, RED, set1.r0 + 1, set1.r1, cutr,
389 wholer, wholeg, wholeb, wholew);
390 maxg = Maximize(set1, GREEN, set1.g0 + 1, set1.g1, cutg,
391 wholer, wholeg, wholeb, wholew);
392 maxb = Maximize(set1, BLUE, set1.b0 + 1, set1.b1, cutb,
393 wholer, wholeg, wholeb, wholew);
394 if ((maxr >= maxg) && (maxr >= maxg)) {
395 dir = RED;
396 if (cutr[0] < 0)
397 return 0;
398 } else if ((maxg >= maxr) && (maxg >= maxb)) {
399 dir = GREEN;
400 } else
401 dir = BLUE;
402
403
404 set2.r1 = set1.r1;
405 set2.g1 = set1.g1;
406 set2.b1 = set1.b1;
407
408 switch (dir) {
409 case RED:
410 set2.r0 = set1.r1 = cutr[0];
411 set2.g0 = set1.g0;
412 set2.b0 = set1.b0;
413 break;
414 case GREEN:
415 set2.r0 = set1.r0;
416 set2.g0 = set1.g1 = cutg[0];
417 set2.b0 = set1.b0;
418 break;
419 case BLUE:
420 set2.r0 = set1.r0;
421 set2.g0 = set1.g0;
422 set2.b0 = set1.b1 = cutb[0];
423 break;
424 }
425
426 set1.vol = (set1.r1 - set1.r0) *
427 (set1.g1 - set1.g0) *
428 (set1.b1 - set1.b0);
429 set2.vol = (set2.r1 - set2.r0) *
430 (set2.g1 - set2.g0) *
431 (set2.b1 - set2.b0);
432 return 1;
433 }
434
435 public void Mark(Box cube, int label, int tag[][][]) {
436 int tr, tg, tb;
437
438 for (tr = cube.r0 + 1; tr <= cube.r1; tr++)
439 for (tg = cube.g0 + 1; tg <= cube.g1; tg++)
440 for (tb = cube.b0 + 1; tb <= cube.b1; tb++)
441 tag[tr][tg][tb] = label;
442 }
443 }
444