/src/freeimage-svn/FreeImage/trunk/Source/Quantizers.h
Line | Count | Source (jump to first uncovered line) |
1 | | // ============================================================= |
2 | | // Quantizer objects and functions |
3 | | // |
4 | | // Design and implementation by: |
5 | | // - Hervé Drolon <drolon@infonie.fr> |
6 | | // - Carsten Klein (cklein05@users.sourceforge.net) |
7 | | // |
8 | | // This file is part of FreeImage 3 |
9 | | // |
10 | | // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY |
11 | | // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES |
12 | | // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE |
13 | | // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED |
14 | | // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT |
15 | | // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY |
16 | | // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL |
17 | | // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
18 | | // THIS DISCLAIMER. |
19 | | // |
20 | | // Use at your own risk! |
21 | | // ============================================================= |
22 | | |
23 | | #ifndef FREEIMAGE_QUANTIZER_H |
24 | | #define FREEIMAGE_QUANTIZER_H |
25 | | |
26 | | // |
27 | | //////////////////////////////////////////////////////////////// |
28 | | |
29 | | #include "FreeImage.h" |
30 | | |
31 | | //////////////////////////////////////////////////////////////// |
32 | | |
33 | | /** |
34 | | Xiaolin Wu color quantization algorithm |
35 | | */ |
36 | | class WuQuantizer |
37 | | { |
38 | | public: |
39 | | |
40 | | typedef struct tagBox { |
41 | | int r0; // min value, exclusive |
42 | | int r1; // max value, inclusive |
43 | | int g0; |
44 | | int g1; |
45 | | int b0; |
46 | | int b1; |
47 | | int vol; |
48 | | } Box; |
49 | | |
50 | | protected: |
51 | | float *gm2; |
52 | | LONG *wt, *mr, *mg, *mb; |
53 | | WORD *Qadd; |
54 | | |
55 | | // DIB data |
56 | | unsigned width, height; |
57 | | unsigned pitch; |
58 | | FIBITMAP *m_dib; |
59 | | |
60 | | protected: |
61 | | void Hist3D(LONG *vwt, LONG *vmr, LONG *vmg, LONG *vmb, float *m2, int ReserveSize, RGBQUAD *ReservePalette); |
62 | | void M3D(LONG *vwt, LONG *vmr, LONG *vmg, LONG *vmb, float *m2); |
63 | | LONG Vol(Box *cube, LONG *mmt); |
64 | | LONG Bottom(Box *cube, BYTE dir, LONG *mmt); |
65 | | LONG Top(Box *cube, BYTE dir, int pos, LONG *mmt); |
66 | | float Var(Box *cube); |
67 | | float Maximize(Box *cube, BYTE dir, int first, int last , int *cut, |
68 | | LONG whole_r, LONG whole_g, LONG whole_b, LONG whole_w); |
69 | | bool Cut(Box *set1, Box *set2); |
70 | | void Mark(Box *cube, int label, BYTE *tag); |
71 | | |
72 | | public: |
73 | | // Constructor - Input parameter: DIB 24-bit to be quantized |
74 | | WuQuantizer(FIBITMAP *dib); |
75 | | // Destructor |
76 | | ~WuQuantizer(); |
77 | | // Quantizer - Return value: quantized 8-bit (color palette) DIB |
78 | | FIBITMAP* Quantize(int PaletteSize, int ReserveSize, RGBQUAD *ReservePalette); |
79 | | }; |
80 | | |
81 | | |
82 | | /** |
83 | | NEUQUANT Neural-Net quantization algorithm by Anthony Dekker |
84 | | */ |
85 | | |
86 | | // ---------------------------------------------------------------- |
87 | | // Constant definitions |
88 | | // ---------------------------------------------------------------- |
89 | | |
90 | | /** number of colours used: |
91 | | for 256 colours, fixed arrays need 8kb, plus space for the image |
92 | | */ |
93 | | //static const int netsize = 256; |
94 | | |
95 | | /**@name network definitions */ |
96 | | //@{ |
97 | | //static const int maxnetpos = (netsize - 1); |
98 | | /// bias for colour values |
99 | | static const int netbiasshift = 4; |
100 | | /// no. of learning cycles |
101 | | static const int ncycles = 100; |
102 | | //@} |
103 | | |
104 | | /**@name defs for freq and bias */ |
105 | | //@{ |
106 | | /// bias for fractions |
107 | | static const int intbiasshift = 16; |
108 | | static const int intbias = (((int)1) << intbiasshift); |
109 | | /// gamma = 1024 |
110 | | static const int gammashift = 10; |
111 | | // static const int gamma = (((int)1) << gammashift); |
112 | | /// beta = 1 / 1024 |
113 | | static const int betashift = 10; |
114 | | static const int beta = (intbias >> betashift); |
115 | | static const int betagamma = (intbias << (gammashift-betashift)); |
116 | | //@} |
117 | | |
118 | | /**@name defs for decreasing radius factor */ |
119 | | //@{ |
120 | | /// for 256 cols, radius starts |
121 | | //static const int initrad = (netsize >> 3); |
122 | | /// at 32.0 biased by 6 bits |
123 | | static const int radiusbiasshift = 6; |
124 | | static const int radiusbias = (((int)1) << radiusbiasshift); |
125 | | /// and decreases by a |
126 | | //static const int initradius = (initrad * radiusbias); |
127 | | // factor of 1/30 each cycle |
128 | | static const int radiusdec = 30; |
129 | | //@} |
130 | | |
131 | | /**@name defs for decreasing alpha factor */ |
132 | | //@{ |
133 | | /// alpha starts at 1.0 |
134 | | static const int alphabiasshift = 10; |
135 | | static const int initalpha = (((int)1) << alphabiasshift); |
136 | | //@} |
137 | | |
138 | | /**@name radbias and alpharadbias used for radpower calculation */ |
139 | | //@{ |
140 | | static const int radbiasshift = 8; |
141 | | static const int radbias = (((int)1) << radbiasshift); |
142 | | static const int alpharadbshift = (alphabiasshift+radbiasshift); |
143 | | static const int alpharadbias = (((int)1) << alpharadbshift); |
144 | | //@} |
145 | | |
146 | | class NNQuantizer |
147 | | { |
148 | | protected: |
149 | | /**@name image parameters */ |
150 | | //@{ |
151 | | /// pointer to input dib |
152 | | FIBITMAP *dib_ptr; |
153 | | /// image width |
154 | | int img_width; |
155 | | /// image height |
156 | | int img_height; |
157 | | /// image line length |
158 | | int img_line; |
159 | | //@} |
160 | | |
161 | | /**@name network parameters */ |
162 | | //@{ |
163 | | |
164 | | int netsize, maxnetpos, initrad, initradius; |
165 | | |
166 | | /// BGRc |
167 | | typedef int pixel[4]; |
168 | | /// the network itself |
169 | | pixel *network; |
170 | | |
171 | | /// for network lookup - really 256 |
172 | | int netindex[256]; |
173 | | |
174 | | /// bias array for learning |
175 | | int *bias; |
176 | | /// freq array for learning |
177 | | int *freq; |
178 | | /// radpower for precomputation |
179 | | int *radpower; |
180 | | //@} |
181 | | |
182 | | protected: |
183 | | /// Initialise network in range (0,0,0) to (255,255,255) and set parameters |
184 | | void initnet(); |
185 | | |
186 | | /// Unbias network to give byte values 0..255 and record position i to prepare for sort |
187 | | void unbiasnet(); |
188 | | |
189 | | /// Insertion sort of network and building of netindex[0..255] (to do after unbias) |
190 | | void inxbuild(); |
191 | | |
192 | | /// Search for BGR values 0..255 (after net is unbiased) and return colour index |
193 | | int inxsearch(int b, int g, int r); |
194 | | |
195 | | /// Search for biased BGR values |
196 | | int contest(int b, int g, int r); |
197 | | |
198 | | /// Move neuron i towards biased (b,g,r) by factor alpha |
199 | | void altersingle(int alpha, int i, int b, int g, int r); |
200 | | |
201 | | /// Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|] |
202 | | void alterneigh(int rad, int i, int b, int g, int r); |
203 | | |
204 | | /** Main Learning Loop |
205 | | @param sampling_factor sampling factor in [1..30] |
206 | | */ |
207 | | void learn(int sampling_factor); |
208 | | |
209 | | /// Get a pixel sample at position pos. Handle 4-byte boundary alignment. |
210 | | void getSample(long pos, int *b, int *g, int *r); |
211 | | |
212 | | |
213 | | public: |
214 | | /// Constructor |
215 | | NNQuantizer(int PaletteSize); |
216 | | |
217 | | /// Destructor |
218 | | ~NNQuantizer(); |
219 | | |
220 | | /** Quantizer |
221 | | @param dib input 24-bit dib to be quantized |
222 | | @param sampling a sampling factor in range 1..30. |
223 | | 1 => slower (but better), 30 => faster. Default value is 1 |
224 | | @return returns the quantized 8-bit (color palette) DIB |
225 | | */ |
226 | | FIBITMAP* Quantize(FIBITMAP *dib, int ReserveSize, RGBQUAD *ReservePalette, int sampling = 1); |
227 | | |
228 | | }; |
229 | | |
230 | | /** |
231 | | * LFPQUANT - Lossless Fast Pseudo-Quantization Algorithm |
232 | | * |
233 | | * The Lossless Fast Pseudo-Quantization algorithm is no real quantization |
234 | | * algorithm, since it makes no attempt to create a palette, that is suitable |
235 | | * for all colors of the 24-bit source image. However, it provides very fast |
236 | | * conversions from 24-bit to 8-bit images, if the number of distinct colors |
237 | | * in the source image is not greater than the desired palette size. If the |
238 | | * number of colors in the source image is exceeded, the Quantize method of |
239 | | * this implementation stops the process and returns NULL. |
240 | | * |
241 | | * This implementation uses a very fast hash map implementation to collect |
242 | | * the source image's colors. It turned out that a customized implementation |
243 | | * of a hash table with open addressing (using linear probing) provides the |
244 | | * best performance. The hash table has 512 entries, which prevents the load |
245 | | * factor to exceed 0.5 as we have 256 entries at most. Each entry consumes |
246 | | * 64 bits, so the whole hash table takes 4KB of memory. |
247 | | * |
248 | | * For large images, the LFPQuantizer is typically up to three times faster |
249 | | * than the WuQuantizer. |
250 | | */ |
251 | | class LFPQuantizer { |
252 | | public: |
253 | | /** Constructor */ |
254 | | LFPQuantizer(unsigned PaletteSize); |
255 | | |
256 | | /** Destructor */ |
257 | | ~LFPQuantizer(); |
258 | | |
259 | | /** |
260 | | * Quantizer |
261 | | * @param dib input 24-bit or 32-bit bitmap to be quantized |
262 | | * @return returns the pseudo-quantized 8-bit bitmap |
263 | | */ |
264 | | FIBITMAP* Quantize(FIBITMAP *dib, int ReserveSize, RGBQUAD *ReservePalette); |
265 | | |
266 | | protected: |
267 | | /** The maximum size of a palette. */ |
268 | | static const unsigned MAX_SIZE = 256; |
269 | | |
270 | | /** |
271 | | * The size of the hash table. Must be a power of 2. By sizing it |
272 | | * MAX_SIZE * 2, we ensure the load factor not to exceed 0.5 at any |
273 | | * time, since we will have MAX_SIZE entries at most. |
274 | | */ |
275 | | static const unsigned MAP_SIZE = MAX_SIZE * 2; |
276 | | |
277 | | /** |
278 | | * With open addressing we need a special value for empty buckets. |
279 | | * Both entry.color and entry.index are 0xFFFFFFFF for an empty |
280 | | * entry. |
281 | | */ |
282 | | static const unsigned EMPTY_BUCKET = 0xFFFFFFFF; |
283 | | |
284 | | /** |
285 | | * This structure defines a single entry in the hash table. We use |
286 | | * color as the entry's key. |
287 | | */ |
288 | | typedef struct MapEntry { |
289 | | unsigned color; |
290 | | unsigned index; |
291 | | } MapEntry; |
292 | | |
293 | | /** The hash table. */ |
294 | | MapEntry *m_map; |
295 | | |
296 | | /** |
297 | | * The current size of the newly created palette. Since the provided |
298 | | * reserve palette could contain duplicates, this is not necessarily |
299 | | * the number of entries in the hash table. Initialized to zero. |
300 | | */ |
301 | | unsigned m_size; |
302 | | |
303 | | /** |
304 | | * The desired maximum number of entries in the newly created palette. |
305 | | * If m_size exceeds this value, the palette is full and the |
306 | | * quantization process is stopped. Initialized to the desired |
307 | | * palette size. |
308 | | */ |
309 | | unsigned m_limit; |
310 | | |
311 | | /** |
312 | | * The palette index used for the next color added. Initialized to |
313 | | * zero (the reserve palette is put to the end of the palette). |
314 | | */ |
315 | | unsigned m_index; |
316 | | |
317 | | /** |
318 | | * Ensures that hash codes that differ only by constant multiples |
319 | | * at each bit position have a bounded number of collisions. |
320 | | * @param h the initial (aka raw) hash code |
321 | | * @return the modified hash code |
322 | | */ |
323 | 0 | static inline unsigned hash(unsigned h) { |
324 | 0 | h ^= (h >> 20) ^ (h >> 12); |
325 | 0 | return h ^ (h >> 7) ^ (h >> 4); |
326 | 0 | } |
327 | | |
328 | | /** |
329 | | * Returns the palette index of the specified color. Tries to put the |
330 | | * color into the map, if it's not already present in the map. In that |
331 | | * case, a new index is used for the color. Returns -1, if adding the |
332 | | * color would exceed the desired maximum number of colors in the |
333 | | * palette. |
334 | | * @param color the color to get the index from |
335 | | * @return the palette index of the specified color or -1, if there |
336 | | * is no space left in the palette |
337 | | */ |
338 | | int GetIndexForColor(unsigned color); |
339 | | |
340 | | /** |
341 | | * Adds the specified number of entries of the specified reserve |
342 | | * palette to the newly created palette. |
343 | | * @param *palette a pointer to the reserve palette to copy from |
344 | | * @param size the number of entries to copy |
345 | | */ |
346 | | void AddReservePalette(const void *palette, unsigned size); |
347 | | |
348 | | /** |
349 | | * Copies the newly created palette into the specified destination |
350 | | * palettte. Although unused palette entries are not overwritten in |
351 | | * the destination palette, it is assumed to have space for at |
352 | | * least 256 entries. |
353 | | * @param palette a pointer to the destination palette |
354 | | */ |
355 | | void WritePalette(void *palette); |
356 | | |
357 | | }; |
358 | | |
359 | | #endif // FREEIMAGE_QUANTIZER_H |