|
7 | 7 | #include <vector> |
8 | 8 | #include <map> /* For associative container, std::map<> */ |
9 | 9 |
|
10 | | -//////////////////////////////////////////////////// |
11 | | -#if 0 |
12 | | -#include <utility> // for std::pair |
13 | | -#include "alloc/FSBAllocator.hh" |
14 | | - |
15 | | -/* kd-tree implementation translated to C++ |
16 | | - * from java implementation in VideoMosaic |
17 | | - * at http://www.intelegance.net/video/videomosaic.shtml. |
18 | | - */ |
19 | | - |
20 | | -template<typename V, unsigned K = 3> |
21 | | -class KDTree { |
22 | | -public: |
23 | | - struct KDPoint { |
24 | | - double coord[K]; |
25 | | - |
26 | | - KDPoint() { } |
27 | | - |
28 | | - KDPoint(double a,double b,double c) { |
29 | | - coord[0] = a; |
30 | | - coord[1] = b; |
31 | | - coord[2] = c; |
32 | | - } |
33 | | - |
34 | | - KDPoint(double v[K]) { |
35 | | - for(unsigned n=0; n<K; ++n) |
36 | | - coord[n] = v[n]; |
37 | | - } |
38 | | - |
39 | | - bool operator==(const KDPoint& b) const { |
40 | | - for(unsigned n=0; n<K; ++n) |
41 | | - if(coord[n] != b.coord[n]) return false; |
42 | | - return true; |
43 | | - } |
44 | | - double sqrdist(const KDPoint& b) const { |
45 | | - double result = 0; |
46 | | - for(unsigned n=0; n<K; ++n) { |
47 | | - double diff = coord[n] - b.coord[n]; |
48 | | - result += diff*diff; |
49 | | - } |
50 | | - return result; |
51 | | - } |
52 | | - }; |
53 | | -private: |
54 | | - struct KDRect { |
55 | | - KDPoint min, max; |
56 | | - |
57 | | - KDPoint bound(const KDPoint& t) const { |
58 | | - KDPoint p; |
59 | | - for(unsigned i=0; i<K; ++i) |
60 | | - if(t.coord[i] <= min.coord[i]) |
61 | | - p.coord[i] = min.coord[i]; |
62 | | - else if(t.coord[i] >= max.coord[i]) |
63 | | - p.coord[i] = max.coord[i]; |
64 | | - else |
65 | | - p.coord[i] = t.coord[i]; |
66 | | - return p; |
67 | | - } |
68 | | - void MakeInfinite() { |
69 | | - for(unsigned i=0; i<K; ++i) { |
70 | | - min.coord[i] = -1e99; |
71 | | - max.coord[i] = 1e99; |
72 | | - } |
73 | | - } |
74 | | - }; |
75 | | - |
76 | | - struct KDNode { |
77 | | - KDPoint k; |
78 | | - V v; |
79 | | - KDNode *left, *right; |
80 | | - public: |
81 | | - KDNode() : k(),v(),left(0),right(0) { } |
82 | | - KDNode(const KDPoint& kk, const V& vv) : k(kk), v(vv), left(0), right(0) { } |
83 | | - |
84 | | - virtual ~KDNode() { |
85 | | - delete (left); |
86 | | - delete (right); |
87 | | - } |
88 | | - |
89 | | - static KDNode* ins( const KDPoint& key, const V& val, |
90 | | - KDNode*& t, int lev) { |
91 | | - if(!t) |
92 | | - return (t = new KDNode(key, val)); |
93 | | - else if(key == t->k) |
94 | | - return 0; /* key duplicate */ |
95 | | - else if(key.coord[lev] > t->k.coord[lev]) |
96 | | - return ins(key, val, t->right, (lev+1)%K); |
97 | | - else |
98 | | - return ins(key, val, t->left, (lev+1)%K); |
99 | | - } |
100 | | - struct Nearest { |
101 | | - const KDNode* kd; |
102 | | - double dist_sqd; |
103 | | - }; |
104 | | - // Method Nearest Neighbor from Andrew Moore's thesis. Numbered |
105 | | - // comments are direct quotes from there. Step "SDL" is added to |
106 | | - // make the algorithm work correctly. |
107 | | - static void nnbr(const KDNode* kd, const KDPoint& target, |
108 | | - KDRect& hr, // in-param and temporary; not an out-param. |
109 | | - int lev, |
110 | | - Nearest& nearest) { |
111 | | - // 1. if kd is empty then set dist-sqd to infinity and exit. |
112 | | - if (!kd) return; |
113 | | - |
114 | | - // 2. s := split field of kd |
115 | | - int s = lev % K; |
116 | | - |
117 | | - // 3. pivot := dom-elt field of kd |
118 | | - const KDPoint& pivot = kd->k; |
119 | | - double pivot_to_target = pivot.sqrdist(target); |
120 | | - |
121 | | - // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr. |
122 | | - // The cut plane is through pivot and perpendicular to the s |
123 | | - // dimension. |
124 | | - KDRect& left_hr = hr; // optimize by not cloning |
125 | | - KDRect right_hr = hr; |
126 | | - left_hr.max.coord[s] = pivot.coord[s]; |
127 | | - right_hr.min.coord[s] = pivot.coord[s]; |
128 | | - |
129 | | - // 5. target-in-left := target_s <= pivot_s |
130 | | - bool target_in_left = target.coord[s] < pivot.coord[s]; |
131 | | - |
132 | | - const KDNode* nearer_kd; |
133 | | - const KDNode* further_kd; |
134 | | - KDRect nearer_hr; |
135 | | - KDRect further_hr; |
136 | | - |
137 | | - // 6. if target-in-left then nearer is left, further is right |
138 | | - if (target_in_left) { |
139 | | - nearer_kd = kd->left; |
140 | | - nearer_hr = left_hr; |
141 | | - further_kd = kd->right; |
142 | | - further_hr = right_hr; |
143 | | - } |
144 | | - // 7. if not target-in-left then nearer is right, further is left |
145 | | - else { |
146 | | - nearer_kd = kd->right; |
147 | | - nearer_hr = right_hr; |
148 | | - further_kd = kd->left; |
149 | | - further_hr = left_hr; |
150 | | - } |
151 | | - |
152 | | - // 8. Recursively call Nearest Neighbor with parameters |
153 | | - // (nearer-kd, target, nearer-hr, max-dist-sqd), storing the |
154 | | - // results in nearest and dist-sqd |
155 | | - nnbr(nearer_kd, target, nearer_hr, lev + 1, nearest); |
156 | | - |
157 | | - // 10. A nearer point could only lie in further-kd if there were some |
158 | | - // part of further-hr within distance sqrt(max-dist-sqd) of |
159 | | - // target. If this is the case then |
160 | | - const KDPoint closest = further_hr.bound(target); |
161 | | - if (closest.sqrdist(target) < nearest.dist_sqd) { |
162 | | - // 10.1 if (pivot-target)^2 < dist-sqd then |
163 | | - if (pivot_to_target < nearest.dist_sqd) { |
164 | | - // 10.1.1 nearest := (pivot, range-elt field of kd) |
165 | | - nearest.kd = kd; |
166 | | - // 10.1.2 dist-sqd = (pivot-target)^2 |
167 | | - nearest.dist_sqd = pivot_to_target; |
168 | | - } |
169 | | - |
170 | | - // 10.2 Recursively call Nearest Neighbor with parameters |
171 | | - // (further-kd, target, further-hr, max-dist_sqd) |
172 | | - nnbr(further_kd, target, further_hr, lev + 1, nearest); |
173 | | - } |
174 | | - // SDL: otherwise, current point is nearest |
175 | | - else if (pivot_to_target < nearest.dist_sqd) { |
176 | | - nearest.kd = kd; |
177 | | - nearest.dist_sqd = pivot_to_target; |
178 | | - } |
179 | | - } |
180 | | - private: |
181 | | - void operator=(const KDNode&); |
182 | | - public: |
183 | | - KDNode(const KDNode& b) |
184 | | - : k(b.k), v(b.v), |
185 | | - left( b.left ? new KDNode(*b.left) : 0), |
186 | | - right( b.right ? new KDNode(*b.right) : 0 ) { } |
187 | | - }; |
188 | | -private: |
189 | | - KDNode* m_root; |
190 | | -public: |
191 | | - KDTree() : m_root(0) { } |
192 | | - virtual ~KDTree() { |
193 | | - delete (m_root); |
194 | | - } |
195 | | - |
196 | | - bool insert(const KDPoint& key, const V& val) { |
197 | | - return KDNode::ins(key, val, m_root, 0); |
198 | | - } |
199 | | - |
200 | | - const std::pair<V,double> nearest(const KDPoint& key) const { |
201 | | - KDRect hr; |
202 | | - hr.MakeInfinite(); |
203 | | - |
204 | | - typename KDNode::Nearest nn; |
205 | | - nn.kd = 0; |
206 | | - nn.dist_sqd = 1e99; |
207 | | - KDNode::nnbr(m_root, key, hr, 0, nn); |
208 | | - if(!nn.kd) return std::pair<V,double> ( V(), 1e99 ); |
209 | | - return std::pair<V,double> ( nn.kd->v, nn.dist_sqd); |
210 | | - } |
211 | | -public: |
212 | | - KDTree& operator=(const KDTree&b) { |
213 | | - if(this != &b) { |
214 | | - if(m_root) delete (m_root); |
215 | | - m_root = b.m_root ? new KDNode(*b.m_root) : 0; |
216 | | - m_count = b.m_count; |
217 | | - } |
218 | | - return *this; |
219 | | - } |
220 | | - KDTree(const KDTree& b) |
221 | | - : m_root( b.m_root ? new KDNode(*b.m_root) : 0 ), |
222 | | - m_count( b.m_count ) { } |
223 | | -}; |
224 | | -#endif |
225 | | -//////////////////////////////////////////////////// |
226 | | - |
227 | 10 | #define COMPARE_RGB 1 |
228 | 11 |
|
229 | | -/* 8x8 threshold map */ |
230 | | -static const unsigned char map[8*8] = { |
231 | | - 0,48,12,60, 3,51,15,63, |
232 | | - 32,16,44,28,35,19,47,31, |
233 | | - 8,56, 4,52,11,59, 7,55, |
234 | | - 40,24,36,20,43,27,39,23, |
235 | | - 2,50,14,62, 1,49,13,61, |
236 | | - 34,18,46,30,33,17,45,29, |
237 | | - 10,58, 6,54, 9,57, 5,53, |
238 | | - 42,26,38,22,41,25,37,21 |
239 | | -}; |
240 | | - |
241 | 12 | static const double Gamma = 2.2; // Gamma correction we use. |
242 | 13 |
|
243 | 14 | double GammaCorrect(double v) { |
@@ -377,13 +148,8 @@ double ColorCompare(int r1,int g1,int b1, int r2,int g2,int b2) { |
377 | 148 | + lumadiff*lumadiff; |
378 | 149 | } |
379 | 150 |
|
380 | | - |
381 | 151 | /* Palette */ |
382 | 152 | static const unsigned palettesize = 16; |
383 | | -static const unsigned pal[palettesize] = { |
384 | | - 0x080000,0x201A0B,0x432817,0x492910, 0x234309,0x5D4F1E,0x9C6B20,0xA9220F, |
385 | | - 0x2B347C,0x2B7409,0xD0CA40,0xE8A077, 0x6A94AB,0xD5C4B3,0xFCE76E,0xFCFAE2 |
386 | | -}; |
387 | 153 |
|
388 | 154 | /* Luminance for each palette entry, to be initialized as soon as the program begins */ |
389 | 155 | static unsigned luma[palettesize]; |
@@ -457,37 +223,4 @@ MixingPlan DeviseBestMixingPlan(unsigned color, size_t limit) { |
457 | 223 | std::sort(result.begin(), result.end(), PaletteCompareLuma); |
458 | 224 | return result; |
459 | 225 | } |
460 | | -#if 0 |
461 | | -int main(int argc, char**argv) { |
462 | | - FILE* fp = fopen(argv[1], "rb"); |
463 | | - gdImagePtr srcim = gdImageCreateFromPng(fp); |
464 | | - fclose(fp); |
465 | 226 |
|
466 | | - unsigned w = gdImageSX(srcim), h = gdImageSY(srcim); |
467 | | - gdImagePtr im = gdImageCreate(w, h); |
468 | | - for(unsigned c=0; c<palettesize; ++c) { |
469 | | - unsigned r = pal[c]>>16, g = (pal[c]>>8) & 0xFF, b = pal[c] & 0xFF; |
470 | | - gdImageColorAllocate(im, r,g,b); |
471 | | - luma[c] = r*299 + g*587 + b*114; |
472 | | - meta[c].Set(pal[c]); |
473 | | - pal_g[c][0] = GammaCorrect(r/255.0); |
474 | | - pal_g[c][1] = GammaCorrect(g/255.0); |
475 | | - pal_g[c][2] = GammaCorrect(b/255.0); |
476 | | - } |
477 | | - #pragma omp parallel for |
478 | | - for(unsigned y=0; y<h; ++y) |
479 | | - for(unsigned x=0; x<w; ++x) { |
480 | | - unsigned color = gdImageGetTrueColorPixel(srcim, x, y); |
481 | | - unsigned map_value = map[(x & 7) + ((y & 7) << 3)]; |
482 | | - MixingPlan plan = DeviseBestMixingPlan(color, 16); |
483 | | - map_value = map_value * plan.size() / 64; |
484 | | - gdImageSetPixel(im, x,y, plan[ map_value ]); |
485 | | - } |
486 | | - fp = fopen(argv[2], "wb"); |
487 | | - gdImagePng(im, fp); |
488 | | - fclose(fp); |
489 | | - gdImageDestroy(im); |
490 | | - gdImageDestroy(srcim); |
491 | | - return 0; |
492 | | -} |
493 | | -#endif |
0 commit comments