source: other-projects/nz-flag-design/trunk/similarity-2d/flag-processing.js@ 29633

Last change on this file since 29633 was 29628, checked in by davidb, 9 years ago

Caching of histograms through HTML5 localStorage

File size: 8.8 KB
Line 
1"use strict";
2
3var progressVal = 0;
4
5var show_progress = 5;
6
7var start_hist_delay = 4000;
8var mini_delay = 300;
9
10
11var hasLocalStorage = false;
12var needToComputeHistograms = true;
13var quantHSLHistogramArray;
14
15
16function drawImage(imageObj, canvasId) {
17 "use strict";
18 var imgCanvas = document.getElementById(canvasId),
19 context, imageData, data,
20 imageX = 0, imageY = 0,
21 imageWidth = imageObj.width,
22 imageHeight = imageObj.height;
23
24 context = imgCanvas.getContext('2d');
25 context.drawImage(imageObj, imageX, imageY, imageWidth, imageHeight);
26 imageData = context.getImageData(imageX, imageY, imageWidth, imageHeight);
27
28 return imageData;
29}
30
31function createHSLHistogram(imageObj, quant)
32{
33 var i;
34
35 if (!$('#hsl_canvas').length) {
36 $('<canvas>', {id: 'hsl_canvas'}).hide().appendTo('body');
37 }
38
39 var imageData = drawImage(imageObj,'hsl_canvas');
40
41 var outputLength = quant * quant * quant;
42 var outputArray = new Array(outputLength);
43 for (i=0; i<outputLength; i++) {
44 outputArray[i] = 0;
45 }
46
47 var total = 0.0;
48
49 var log2 = Math.log(2);
50
51 //calculate value to shift by (log base 2)
52
53 var shift_sat = Math.floor(Math.log(quant)/log2);
54 var shift_hue = Math.floor(Math.log(quant*quant)/log2);
55
56 //console.log("bit-shift sat = " + shift_sat);
57 //console.log("bit-shift hue = " + shift_hue);
58
59 var data = imageData.data;
60
61 //Loop through each pixel
62 var y,p;
63 for (y=0,p=0; y<imageObj.height; y++) {
64// setTimeout(function() {
65 var x;
66 for (x=0; x<imageObj.width; x++,p+=4) {
67 // convert 4 byte data value into a colour pixel
68 var rgb_c = new RGBColour(data[p],data[p+1],data[p+2],data[p+3]/255.0);
69 var hsl = new rgb_c.getHSL();
70
71 // express h,s and b in the range 0..1
72
73 var h = hsl.h / 360.0;
74 var s = hsl.s / 100.0;
75 var b = hsl.l / 100.0;
76
77 var result = (Math.floor(h * (quant - 1)) << shift_hue)
78 | (Math.floor(s * (quant - 1)) << shift_sat)
79 | Math.floor(b * (quant - 1));
80
81 //number of opaque pixels
82 var count = hsl.a; // 'a' is naturally in the range 0..1
83
84 //add to the total number of opaque pixels
85 total += count;
86
87 //add the frequency of each colour to the histogram
88 outputArray[result] += count;
89 }
90// },4);
91 }
92
93 //Normalise the histogram, based on the number of opaque pixels
94 for (i=0; i<outputArray.length; i++) {
95 outputArray[i] = outputArray[i] / total;
96 }
97
98 return outputArray;
99}
100
101var flag_comparison_array = Array(2);
102var clicked_on_count = 0;
103
104function quantizedColourHistogramComparison(quant_colour_hist1,quant_colour_hist2)
105{
106 // Assumes both histograms are of the same length
107
108 var i;
109 var quant_product = 0.0;
110
111 //Loop through and compare the histograms
112 for (i=0; i<quant_colour_hist1.length; i++) {
113 //take the overlap
114 quant_product += Math.min(quant_colour_hist1[i], quant_colour_hist2[i]);
115
116 // consider replacing with abs for difference
117 }
118
119 alert("Product for HSL histogram: " + quant_product);
120
121}
122
123
124function displayFlags(img_list,$displayDiv,$progressArea,$progressBar)
125{
126 var img_list_len = img_list.length;
127
128 if (img_list_len==0) {
129 return;
130 }
131 else if (img_list_len>show_progress) {
132 $progressArea.slideDown();
133 }
134
135 img_list.sort();
136
137 var root_img_re = /^.*\/(.*?)\..*?$/;
138
139 var progress_step = 100.0 / img_list_len;
140
141 var callback_count = 0;
142
143 var i;
144 for (i=0; i<img_list.length; i++) {
145 var img_url = img_list[i];
146 var img_matches = root_img_re.exec(img_url);
147 var title = img_matches[1];
148
149 var imageObj = new Image();
150 imageObj.onload = function() {
151 callback_count++;
152 progressVal += progress_step;
153 $progressBar.progressbar('value',progressVal);
154
155 if (callback_count == img_list_len) {
156 if (img_list_len>show_progress) {
157 progressVal = 100;
158 $progressBar.progressbar('value',progressVal);
159 //$progressArea.slideUp();
160
161 // Now move on and start computing colour histograms
162 setTimeout(function()
163 { doneDisplayFlags(img_list,$progressArea,$progressBar); }
164 ,start_hist_delay);
165 }
166 }
167 };
168
169
170 /*
171$("h2").live('mousedown', function(e) {
172 if( (e.which == 1) ) {
173 alert("left button");
174 }if( (e.which == 3) ) {
175 alert("right button");
176 }else if( (e.which == 2) ) {
177 alert("middle button");
178 }
179 e.preventDefault();
180}).live('contextmenu', function(e){
181 e.preventDefault();
182});
183 */
184
185
186
187 imageObj.onclick = function(e) {
188 // Store result of HSL quantization in the image object/tag
189 if (!this.quantHSLHist) {
190 // Only need to compute this if it is not already stored in the object/tag
191 this.quantHSLHist = createHSLHistogram(this,16);
192 console.log(this.quantHSLHist);
193 }
194
195 if (e.which == 1 ) {
196 // Left => use in comparison pair
197 flag_comparison_array[clicked_on_count] = this.quantHSLHist;
198
199 clicked_on_count++;
200 if (clicked_on_count==2) {
201 // trigger comparison
202 quantizedColourHistogramComparison(flag_comparison_array[0],flag_comparison_array[1]);
203 clicked_on_count=0;
204 }
205 }
206 else if (e.which == 2) {
207 // Middle => fix on this and do similarity with everything else
208 var fix_id = this.id;
209 e.preventDefault();
210 }
211
212 };
213
214
215 imageObj.src = img_url;
216 imageObj.title = title;
217 imageObj.id = "flag-img-" + i;
218
219 $displayDiv.append(imageObj);
220 }
221}
222
223function computeFlagHistogramChain(chain_count, img_list_len,
224 progressVal, progress_step,
225 $progressArea,$progressBar)
226{
227 var flag_id = "flag-img-" + chain_count;
228 console.log("Processing Image ID: " + flag_id);
229 var imageObj = document.getElementById(flag_id);
230
231 if (!imageObj.quantHSLHist) {
232 // Only need to compute this if it is not
233 // already stored in the object/tag
234 imageObj.quantHSLHist = createHSLHistogram(imageObj,16);
235 //console.log(imageObj.quantHSLHist);
236 }
237
238 if (chain_count < img_list_len-1) {
239 progressVal += progress_step;
240 $progressBar.progressbar('value',progressVal);
241
242 setTimeout(function()
243 { computeFlagHistogramChain(chain_count+1,img_list_len,
244 progressVal, progress_step,
245 $progressArea,$progressBar)
246 }
247 ,mini_delay // any time delay causes break in 'rendering' thread, even 0!
248 );
249
250 }
251 else {
252 $progressArea.find('span:first').text("Done.");
253 if (img_list_len>show_progress) {
254 progressVal = 100;
255 $progressBar.progressbar('value',progressVal);
256 $progressArea.slideUp();
257 }
258
259 doneComputingHistograms(img_list_len);
260 }
261}
262
263
264function computeFlagHistograms(img_list,$progressArea,$progressBar)
265{
266 var img_list_len = img_list.length;
267
268
269 if (img_list_len==0) {
270 $progressArea.find('span:first').text("Empty list: no computation needed.");
271 return;
272 }
273
274
275 $progressArea.find('span:first').text("Computing histograms:");
276 progressVal = 0;
277
278 if (img_list_len>show_progress) {
279 $progressArea.slideDown();
280 }
281
282 var progress_step = 100.0 / img_list_len;
283
284 // Start the chaining process
285 setTimeout(function()
286 { computeFlagHistogramChain(0,img_list_len,
287 progressVal, progress_step,
288 $progressArea,$progressBar)
289 }
290 ,mini_delay // any time delay causes break in 'rendering' thread, even 0!
291 );
292
293}
294
295function doneComputingHistograms(img_list_len)
296{
297 if (hasLocalStorage) {
298 // build up quantHSLHistogramArray from all the images
299
300 quantHSLHistogramArray = new Array(img_list_len);
301 var i;
302 for (i=0; i<img_list_len; i++) {
303 var flag_id = "flag-img-" + i;
304 var imageObj = document.getElementById(flag_id);
305 quantHSLHistogramArray[i] = imageObj.quantHSLHist;
306 }
307
308 console.log("Storing computed HSL histograms in localStorage");
309 localStorage.quantHSLHistogramArray = JSON.stringify(quantHSLHistogramArray);
310 }
311}
312
313function doneDisplayFlags(img_list,$progressArea,$progressBar)
314{
315 hasLocalStorage = false;
316 needToComputeHistograms = true;
317
318 if (typeof(Storage) !== "undefined") {
319 hasLocalStorage = true;
320
321 if (localStorage.quantHSLHistogramArray) {
322
323 console.log("Retrieving quantized HSL histograms");
324
325 var stored_hist_array = JSON.parse(localStorage["quantHSLHistogramArray"]);
326 if (stored_hist_array.length == img_list.length) {
327 console.log("Different number of images detected => regenerating");
328
329 // Assume if the number of images process hasn't changed, then neither
330 // has the stored historgram values
331
332 quantHSLHistogramArray = stored_hist_array;
333
334 var i;
335 for (i=0; i<img_list.length; i++) {
336 var flag_id = "flag-img-" + i;
337 var imageObj = document.getElementById(flag_id);
338 imageObj.quantHSLHist = quantHSLHistogramArray[i];
339 }
340
341
342 needToComputeHistograms = false;
343 }
344 }
345 }
346
347
348 if (needToComputeHistograms) {
349 computeFlagHistograms(img_list,$progressArea,$progressBar);
350 }
351 else {
352 $progressArea.slideUp();
353 doneComputingHistograms(img_list.length);
354 }
355
356
357
358}
Note: See TracBrowser for help on using the repository browser.