summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg/src/Quantizers.h
blob: a59f6851deb0699f5b4aa97103c8a1ca25e05d37 (plain)
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
// =============================================================
// Quantizer objects and functions
//
// Design and implementation by:
// - Hervé Drolon <drolon@infonie.fr>
// - Carsten Klein (cklein05@users.sourceforge.net)
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// =============================================================

// 
////////////////////////////////////////////////////////////////

#include "FreeImage.h"

////////////////////////////////////////////////////////////////

/**
  Xiaolin Wu color quantization algorithm
*/
class WuQuantizer
{
public:

typedef struct tagBox {
    int r0;			 // min value, exclusive
    int r1;			 // max value, inclusive
    int g0;  
    int g1;  
    int b0;  
    int b1;
    int vol;
} Box;

protected:
    float *gm2;
	LONG *wt, *mr, *mg, *mb;
	WORD *Qadd;

	// DIB data
	unsigned width, height;
	unsigned pitch;
	FIBITMAP *m_dib;

protected:
    void Hist3D(LONG *vwt, LONG *vmr, LONG *vmg, LONG *vmb, float *m2, int ReserveSize, RGBQUAD *ReservePalette);
	void M3D(LONG *vwt, LONG *vmr, LONG *vmg, LONG *vmb, float *m2);
	LONG Vol(Box *cube, LONG *mmt);
	LONG Bottom(Box *cube, BYTE dir, LONG *mmt);
	LONG Top(Box *cube, BYTE dir, int pos, LONG *mmt);
	float Var(Box *cube);
	float Maximize(Box *cube, BYTE dir, int first, int last , int *cut,
				   LONG whole_r, LONG whole_g, LONG whole_b, LONG whole_w);
	bool Cut(Box *set1, Box *set2);
	void Mark(Box *cube, int label, BYTE *tag);

public:
	// Constructor - Input parameter: DIB 24-bit to be quantized
    WuQuantizer(FIBITMAP *dib);
	// Destructor
	~WuQuantizer();
	// Quantizer - Return value: quantized 8-bit (color palette) DIB
	FIBITMAP* Quantize(int PaletteSize, int ReserveSize, RGBQUAD *ReservePalette);
};


/**
  NEUQUANT Neural-Net quantization algorithm by Anthony Dekker
*/

// ----------------------------------------------------------------
// Constant definitions
// ----------------------------------------------------------------

/** number of colours used: 
	for 256 colours, fixed arrays need 8kb, plus space for the image
*/
//static const int netsize = 256;

/**@name network definitions */
//@{
//static const int maxnetpos = (netsize - 1);
/// bias for colour values
static const int netbiasshift = 4;
/// no. of learning cycles
static const int ncycles = 100;
//@}

/**@name defs for freq and bias */
//@{
/// bias for fractions
static const int intbiasshift = 16;
static const int intbias = (((int)1) << intbiasshift);
/// gamma = 1024
static const int gammashift = 10;
// static const int gamma = (((int)1) << gammashift);
/// beta = 1 / 1024
static const int betashift = 10;
static const int beta = (intbias >> betashift);
static const int betagamma = (intbias << (gammashift-betashift));
//@}

/**@name defs for decreasing radius factor */
//@{
/// for 256 cols, radius starts
//static const int initrad = (netsize >> 3);
/// at 32.0 biased by 6 bits
static const int radiusbiasshift = 6;
static const int radiusbias = (((int)1) << radiusbiasshift);
/// and decreases by a 
//static const int initradius	= (initrad * radiusbias);
// factor of 1/30 each cycle
static const int radiusdec = 30;
//@}

/**@name defs for decreasing alpha factor */
//@{
/// alpha starts at 1.0
static const int alphabiasshift = 10;
static const int initalpha = (((int)1) << alphabiasshift);
//@}

/**@name radbias and alpharadbias used for radpower calculation */
//@{
static const int radbiasshift = 8;
static const int radbias = (((int)1) << radbiasshift);
static const int alpharadbshift = (alphabiasshift+radbiasshift);
static const int alpharadbias = (((int)1) << alpharadbshift);	
//@}

class NNQuantizer
{
protected:
	/**@name image parameters */
	//@{
	/// pointer to input dib
	FIBITMAP *dib_ptr;
	/// image width
	int img_width;
	/// image height
	int img_height;
	/// image line length
	int img_line;
	//@}

	/**@name network parameters */
	//@{

	int netsize, maxnetpos, initrad, initradius;

	/// BGRc
	typedef int pixel[4];
	/// the network itself
	pixel *network;

	/// for network lookup - really 256
	int netindex[256];

	/// bias array for learning
	int *bias;
	/// freq array for learning
	int *freq;
	/// radpower for precomputation
	int *radpower;
	//@}

protected:
	/// Initialise network in range (0,0,0) to (255,255,255) and set parameters
	void initnet();	

	/// Unbias network to give byte values 0..255 and record position i to prepare for sort
	void unbiasnet();

	/// Insertion sort of network and building of netindex[0..255] (to do after unbias)
	void inxbuild();

	/// Search for BGR values 0..255 (after net is unbiased) and return colour index
	int inxsearch(int b, int g, int r);

	/// Search for biased BGR values
	int contest(int b, int g, int r);
	
	/// Move neuron i towards biased (b,g,r) by factor alpha
	void altersingle(int alpha, int i, int b, int g, int r);

	/// Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]
	void alterneigh(int rad, int i, int b, int g, int r);

	/** Main Learning Loop
	@param sampling_factor sampling factor in [1..30]
	*/
	void learn(int sampling_factor);

	/// Get a pixel sample at position pos. Handle 4-byte boundary alignment.
	void getSample(long pos, int *b, int *g, int *r);


public:
	/// Constructor
	NNQuantizer(int PaletteSize);

	/// Destructor
	~NNQuantizer();

	/** Quantizer
	@param dib input 24-bit dib to be quantized
	@param sampling a sampling factor in range 1..30. 
	1 => slower (but better), 30 => faster. Default value is 1
	@return returns the quantized 8-bit (color palette) DIB
	*/
	FIBITMAP* Quantize(FIBITMAP *dib, int ReserveSize, RGBQUAD *ReservePalette, int sampling = 1);

};

/**
 * LFPQUANT - Lossless Fast Pseudo-Quantization Algorithm
 *
 * The Lossless Fast Pseudo-Quantization algorithm is no real quantization
 * algorithm, since it makes no attempt to create a palette, that is suitable
 * for all colors of the 24-bit source image. However, it provides very fast
 * conversions from 24-bit to 8-bit images, if the number of distinct colors
 * in the source image is not greater than the desired palette size. If the
 * number of colors in the source image is exceeded, the Quantize method of
 * this implementation stops the process and returns NULL.
 *
 * This implementation uses a very fast hash map implementation to collect
 * the source image's colors. It turned out that a customized implementation
 * of a hash table with open addressing (using linear probing) provides the
 * best performance. The hash table has 512 entries, which prevents the load
 * factor to exceed 0.5 as we have 256 entries at most. Each entry consumes
 * 64 bits, so the whole hash table takes 4KB of memory.
 *
 * For large images, the LFPQuantizer is typically up to three times faster
 * than the WuQuantizer.
 */
class LFPQuantizer {
public:
	/** Constructor */
	LFPQuantizer(unsigned PaletteSize);

	/** Destructor */
	~LFPQuantizer();

	/**
	 * Quantizer
	 * @param dib input 24-bit or 32-bit bitmap to be quantized
	 * @return returns the pseudo-quantized 8-bit bitmap
	 */
	FIBITMAP* Quantize(FIBITMAP *dib, int ReserveSize, RGBQUAD *ReservePalette);

protected:
	/** The maximum size of a palette. */
	static const unsigned MAX_SIZE = 256;

	/**
	 * The size of the hash table. Must be a power of 2. By sizing it
	 * MAX_SIZE * 2, we ensure the load factor not to exceed 0.5 at any
	 * time, since we will have MAX_SIZE entries at most.
	 */
	static const unsigned MAP_SIZE = MAX_SIZE * 2;

	/**
	 * With open addressing we need a special value for empty buckets.
	 * Both entry.color and entry.index are 0xFFFFFFFF for an empty
	 * entry.
	 */
	static const unsigned EMPTY_BUCKET = 0xFFFFFFFF;

	/**
	 * This structure defines a single entry in the hash table. We use
	 * color as the entry's key.
	 */
	typedef struct MapEntry {
		unsigned color;
		unsigned index;
	} MapEntry;

	/** The hash table. */
	MapEntry *m_map;

	/**
	 * The current size of the newly created palette. Since the provided
	 * reserve palette could contain duplicates, this is not necessarily
	 * the number of entries in the hash table. Initialized to zero.
	 */
	unsigned m_size;

	/**
	 * The desired maximum number of entries in the newly created palette.
	 * If m_size exceeds this value, the palette is full and the
	 * quantization process is stopped. Initialized to the desired
	 * palette size.
	 */
	unsigned m_limit;

	/**
	 *  The palette index used for the next color added. Initialized to
	 *  zero (the reserve palette is put to the end of the palette).
	 */
	unsigned m_index;

	/**
	 * Ensures that hash codes that differ only by constant multiples
	 * at each bit position have a bounded number of collisions.
	 * @param h the initial (aka raw) hash code
	 * @return the modified hash code
	 */
	static inline unsigned hash(unsigned h) {
		h ^= (h >> 20) ^ (h >> 12);
		return h ^ (h >> 7) ^ (h >> 4);
	}

	/**
	 * Returns the palette index of the specified color. Tries to put the
	 * color into the map, if it's not already present in the map. In that
	 * case, a new index is used for the color. Returns -1, if adding the
	 * color would exceed the desired maximum number of colors in the
	 * palette.
	 * @param color the color to get the index from
	 * @return the palette index of the specified color or -1, if there
	 * is no space left in the palette
	 */
	int GetIndexForColor(unsigned color);

	/**
	 * Adds the specified number of entries of the specified reserve
	 * palette to the newly created palette.
	 * @param *palette a pointer to the reserve palette to copy from
	 * @param size the number of entries to copy
	 */
	void AddReservePalette(const void *palette, unsigned size);

	/**
	 * Copies the newly created palette into the specified destination
	 * palettte. Although unused palette entries are not overwritten in
	 * the destination palette, it is assumed to have space for at
	 * least 256 entries.
	 * @param palette a pointer to the destination palette
	 */
	void WritePalette(void *palette);

};