1 package org.catacomb.movie.gif;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 public class NeuQuant {
28
29 protected static final int netsize = 256;
30
31
32
33 protected static final int prime1 = 499;
34 protected static final int prime2 = 491;
35 protected static final int prime3 = 487;
36 protected static final int prime4 = 503;
37
38 protected static final int minpicturebytes = (3 * prime4);
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 protected static final int maxnetpos = (netsize - 1);
57 protected static final int netbiasshift = 4;
58 protected static final int ncycles = 100;
59
60
61 protected static final int intbiasshift = 16;
62 protected static final int intbias = (1 << intbiasshift);
63 protected static final int gammashift = 10;
64 protected static final int gamma = (1 << gammashift);
65 protected static final int betashift = 10;
66 protected static final int beta = (intbias >> betashift);
67 protected static final int betagamma =
68 (intbias << (gammashift - betashift));
69
70
71 protected static final int initrad = (netsize >> 3);
72 protected static final int radiusbiasshift = 6;
73 protected static final int radiusbias = (1 << radiusbiasshift);
74 protected static final int initradius = (initrad * radiusbias);
75 protected static final int radiusdec = 30;
76
77
78 protected static final int alphabiasshift = 10;
79 protected static final int initalpha = (1 << alphabiasshift);
80
81 protected int alphadec;
82
83
84 protected static final int radbiasshift = 8;
85 protected static final int radbias = (1 << radbiasshift);
86 protected static final int alpharadbshift = (alphabiasshift + radbiasshift);
87 protected static final int alpharadbias = (1 << alpharadbshift);
88
89
90
91
92 protected byte[] thepicture;
93 protected int lengthcount;
94
95 protected int samplefac;
96
97
98 protected int[][] network;
99
100 protected int[] netindex = new int[256];
101
102
103 protected int[] bias = new int[netsize];
104
105 protected int[] freq = new int[netsize];
106 protected int[] radpower = new int[initrad];
107
108
109
110
111 public NeuQuant(byte[] thepic, int len, int sample) {
112
113 int i;
114 int[] p;
115
116 thepicture = thepic;
117 lengthcount = len;
118 samplefac = sample;
119
120 network = new int[netsize][];
121 for (i = 0; i < netsize; i++) {
122 network[i] = new int[4];
123 p = network[i];
124 p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;
125 freq[i] = intbias / netsize;
126 bias[i] = 0;
127 }
128 }
129
130 public byte[] colorMap() {
131 byte[] map = new byte[3 * netsize];
132 int[] index = new int[netsize];
133 for (int i = 0; i < netsize; i++) {
134 index[network[i][3]] = i;
135 }
136 int k = 0;
137 for (int i = 0; i < netsize; i++) {
138 int j = index[i];
139 map[k++] = (byte)(network[j][0]);
140 map[k++] = (byte)(network[j][1]);
141 map[k++] = (byte)(network[j][2]);
142 }
143 return map;
144 }
145
146
147
148 public void inxbuild() {
149
150 int i, j, smallpos, smallval;
151 int[] p;
152 int[] q;
153 int previouscol, startpos;
154
155 previouscol = 0;
156 startpos = 0;
157 for (i = 0; i < netsize; i++) {
158 p = network[i];
159 smallpos = i;
160 smallval = p[1];
161
162 for (j = i + 1; j < netsize; j++) {
163 q = network[j];
164 if (q[1] < smallval) {
165 smallpos = j;
166 smallval = q[1];
167 }
168 }
169 q = network[smallpos];
170
171 if (i != smallpos) {
172 j = q[0];
173 q[0] = p[0];
174 p[0] = j;
175 j = q[1];
176 q[1] = p[1];
177 p[1] = j;
178 j = q[2];
179 q[2] = p[2];
180 p[2] = j;
181 j = q[3];
182 q[3] = p[3];
183 p[3] = j;
184 }
185
186 if (smallval != previouscol) {
187 netindex[previouscol] = (startpos + i) >> 1;
188 for (j = previouscol + 1; j < smallval; j++) {
189 netindex[j] = i;
190 }
191 previouscol = smallval;
192 startpos = i;
193 }
194 }
195 netindex[previouscol] = (startpos + maxnetpos) >> 1;
196 for (j = previouscol + 1; j < 256; j++) {
197 netindex[j] = maxnetpos;
198 }
199 }
200
201
202
203 public void learn() {
204
205 int i, j, b, g, r;
206 int radius, rad, alpha, step, delta, samplepixels;
207 byte[] p;
208 int pix, lim;
209
210 if (lengthcount < minpicturebytes) {
211 samplefac = 1;
212 }
213 alphadec = 30 + ((samplefac - 1) / 3);
214 p = thepicture;
215 pix = 0;
216 lim = lengthcount;
217 samplepixels = lengthcount / (3 * samplefac);
218 delta = samplepixels / ncycles;
219 alpha = initalpha;
220 radius = initradius;
221
222 rad = radius >> radiusbiasshift;
223 if (rad <= 1) {
224 rad = 0;
225 }
226 for (i = 0; i < rad; i++) {
227 radpower[i] =
228 alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
229 }
230
231
232
233 if (lengthcount < minpicturebytes) {
234 step = 3;
235 } else if ((lengthcount % prime1) != 0) {
236 step = 3 * prime1;
237 } else {
238 if ((lengthcount % prime2) != 0) {
239 step = 3 * prime2;
240 } else {
241 if ((lengthcount % prime3) != 0) {
242 step = 3 * prime3;
243 } else {
244 step = 3 * prime4;
245 }
246 }
247 }
248
249 i = 0;
250 while (i < samplepixels) {
251 b = (p[pix + 0] & 0xff) << netbiasshift;
252 g = (p[pix + 1] & 0xff) << netbiasshift;
253 r = (p[pix + 2] & 0xff) << netbiasshift;
254 j = contest(b, g, r);
255
256 altersingle(alpha, j, b, g, r);
257 if (rad != 0) {
258 alterneigh(rad, j, b, g, r);
259 }
260 pix += step;
261 if (pix >= lim) {
262 pix -= lengthcount;
263 }
264 i++;
265 if (delta == 0) {
266 delta = 1;
267 }
268 if (i % delta == 0) {
269 alpha -= alpha / alphadec;
270 radius -= radius / radiusdec;
271 rad = radius >> radiusbiasshift;
272 if (rad <= 1) {
273 rad = 0;
274 }
275 for (j = 0; j < rad; j++) {
276 radpower[j] =
277 alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
278 }
279 }
280 }
281
282 }
283
284
285
286 public int map(int b, int g, int r) {
287
288 int i, j, dist, a, bestd;
289 int[] p;
290 int best;
291
292 bestd = 1000;
293 best = -1;
294 i = netindex[g];
295 j = i - 1;
296
297 while ((i < netsize) || (j >= 0)) {
298 if (i < netsize) {
299 p = network[i];
300 dist = p[1] - g;
301 if (dist >= bestd) {
302 i = netsize;
303 } else {
304 i++;
305 if (dist < 0) {
306 dist = -dist;
307 }
308 a = p[0] - b;
309 if (a < 0) {
310 a = -a;
311 }
312 dist += a;
313 if (dist < bestd) {
314 a = p[2] - r;
315 if (a < 0) {
316 a = -a;
317 }
318 dist += a;
319 if (dist < bestd) {
320 bestd = dist;
321 best = p[3];
322 }
323 }
324 }
325 }
326 if (j >= 0) {
327 p = network[j];
328 dist = g - p[1];
329 if (dist >= bestd) {
330 j = -1;
331 } else {
332 j--;
333 if (dist < 0) {
334 dist = -dist;
335 }
336 a = p[0] - b;
337 if (a < 0) {
338 a = -a;
339 }
340 dist += a;
341 if (dist < bestd) {
342 a = p[2] - r;
343 if (a < 0) {
344 a = -a;
345 }
346 dist += a;
347 if (dist < bestd) {
348 bestd = dist;
349 best = p[3];
350 }
351 }
352 }
353 }
354 }
355 return (best);
356 }
357 public byte[] process() {
358 learn();
359 unbiasnet();
360 inxbuild();
361 return colorMap();
362 }
363
364
365
366 public void unbiasnet() {
367
368 int i;
369
370 for (i = 0; i < netsize; i++) {
371 network[i][0] >>= netbiasshift;
372 network[i][1] >>= netbiasshift;
373 network[i][2] >>= netbiasshift;
374 network[i][3] = i;
375 }
376 }
377
378
379
380 protected void alterneigh(int rad, int i, int b, int g, int r) {
381
382 int j, k, lo, hi, a, m;
383 int[] p;
384
385 lo = i - rad;
386 if (lo < -1) {
387 lo = -1;
388 }
389 hi = i + rad;
390 if (hi > netsize) {
391 hi = netsize;
392 }
393
394 j = i + 1;
395 k = i - 1;
396 m = 1;
397 while ((j < hi) || (k > lo)) {
398 a = radpower[m++];
399 if (j < hi) {
400 p = network[j++];
401 try {
402 p[0] -= (a * (p[0] - b)) / alpharadbias;
403 p[1] -= (a * (p[1] - g)) / alpharadbias;
404 p[2] -= (a * (p[2] - r)) / alpharadbias;
405 } catch (Exception e) {
406 }
407 }
408 if (k > lo) {
409 p = network[k--];
410 try {
411 p[0] -= (a * (p[0] - b)) / alpharadbias;
412 p[1] -= (a * (p[1] - g)) / alpharadbias;
413 p[2] -= (a * (p[2] - r)) / alpharadbias;
414 } catch (Exception e) {
415 }
416 }
417 }
418 }
419
420
421
422 protected void altersingle(int alpha, int i, int b, int g, int r) {
423
424
425 int[] n = network[i];
426 n[0] -= (alpha * (n[0] - b)) / initalpha;
427 n[1] -= (alpha * (n[1] - g)) / initalpha;
428 n[2] -= (alpha * (n[2] - r)) / initalpha;
429 }
430
431
432
433 protected int contest(int b, int g, int r) {
434
435
436
437
438
439
440 int i, dist, a, biasdist, betafreq;
441 int bestpos, bestbiaspos, bestd, bestbiasd;
442 int[] n;
443
444 bestd = ~(1 << 31);
445 bestbiasd = bestd;
446 bestpos = -1;
447 bestbiaspos = bestpos;
448
449 for (i = 0; i < netsize; i++) {
450 n = network[i];
451 dist = n[0] - b;
452 if (dist < 0) {
453 dist = -dist;
454 }
455
456 a = n[1] - g;
457 if (a < 0) {
458 a = -a;
459 }
460
461 dist += a;
462 a = n[2] - r;
463 if (a < 0) {
464 a = -a;
465 }
466 dist += a;
467 if (dist < bestd) {
468 bestd = dist;
469 bestpos = i;
470 }
471 biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));
472 if (biasdist < bestbiasd) {
473 bestbiasd = biasdist;
474 bestbiaspos = i;
475 }
476 betafreq = (freq[i] >> betashift);
477 freq[i] -= betafreq;
478 bias[i] += (betafreq << gammashift);
479 }
480 freq[bestpos] += beta;
481 bias[bestpos] -= betagamma;
482 return (bestbiaspos);
483 }
484 }