File: | home/HaikuArchives/ArtPaint/addons/AddOns/Halftone/../../UtilityClasses/ImageProcessingLibrary.cpp |
Warning: | line 504, column 9 Value stored to 'y_dist' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright 2003, Heikki Suhonen |
3 | * Distributed under the terms of the MIT License. |
4 | * |
5 | * Authors: |
6 | * Heikki Suhonen <heikki.suhonen@gmail.com> |
7 | */ |
8 | #include <OS.h> |
9 | #include <stdio.h> |
10 | |
11 | #include "ImageProcessingLibrary.h" |
12 | |
13 | |
14 | status_t ImageProcessingLibrary::gaussian_blur(BBitmap *bitmap,float radius) |
15 | { |
16 | int32 kernel_radius = int32(ceil(radius)); |
17 | float *kernel_array = new float[2*kernel_radius+1]; |
18 | float *kernel = &kernel_array[kernel_radius]; |
19 | float sum = 0; |
20 | int32 *fixed_kernel_array = new int32[2*kernel_radius+1]; |
21 | int32 *fixed_kernel = &fixed_kernel_array[kernel_radius]; |
22 | |
23 | // was before -log(0.002) |
24 | float p = -log(0.004)/(pow(radius,2)*log(2)); |
25 | for (int32 i=-kernel_radius;i<=kernel_radius;i++) { |
26 | kernel[i] = pow(2,-p*i*i); |
27 | sum += kernel[i]; |
28 | } |
29 | for (int32 i = -kernel_radius; i <= kernel_radius; i++) { |
30 | kernel[i] /= sum; |
31 | fixed_kernel[i] = kernel[i] * 32768; |
32 | } |
33 | |
34 | BBitmap *intermediate; |
35 | BRect bitmap_bounds = bitmap->Bounds(); |
36 | BRect intermediate_bounds; |
37 | intermediate_bounds.left = bitmap_bounds.top; |
38 | intermediate_bounds.top = bitmap_bounds.left; |
39 | intermediate_bounds.right = bitmap_bounds.bottom; |
40 | intermediate_bounds.bottom = bitmap_bounds.right; |
41 | |
42 | intermediate = new BBitmap(intermediate_bounds,B_RGB32,false); |
43 | |
44 | uint32 *b_bits = (uint32*)bitmap->Bits(); |
45 | uint32 *i_bits = (uint32*)intermediate->Bits(); |
46 | int32 b_bpr = bitmap->BytesPerRow()/4; |
47 | int32 i_bpr = intermediate->BytesPerRow()/4; |
48 | |
49 | // Blur from bitmap to intermediate and rotate |
50 | int32 width = bitmap_bounds.IntegerWidth() + 1; |
51 | int32 height = bitmap_bounds.IntegerHeight() + 1; |
52 | uint32 *source_array = new uint32[width + kernel_radius*2]; |
53 | uint32 *target_array = new uint32[width]; |
54 | |
55 | |
56 | for (int32 y=0;y<height;y++) { |
57 | uint32 *source_array_position = source_array; |
58 | for (int32 dx = 0;dx<kernel_radius;dx++) { |
59 | *source_array_position++ = *b_bits; |
60 | } |
61 | for (int32 dx=0;dx<width;dx++) { |
62 | *source_array_position++ = *b_bits++; |
63 | } |
64 | b_bits--; |
65 | for (int32 dx = 0;dx<kernel_radius;dx++) { |
66 | *source_array_position++ = *b_bits; |
67 | } |
68 | b_bits++; |
69 | convolve_1d_fixed(source_array+kernel_radius,target_array,width,fixed_kernel,kernel_radius); |
70 | |
71 | uint32 *target_array_position = target_array; |
72 | for (int32 x = 0;x<width;x++) { |
73 | *(i_bits + (height-y-1) + x*i_bpr) = *target_array_position++; |
74 | } |
75 | |
76 | } |
77 | |
78 | |
79 | b_bits = (uint32*)bitmap->Bits(); |
80 | i_bits = (uint32*)intermediate->Bits(); |
81 | |
82 | |
83 | delete[] source_array; |
84 | delete[] target_array; |
85 | |
86 | |
87 | // Blur from intermediate to bitmap and rotate |
88 | width = intermediate_bounds.IntegerWidth() + 1; |
89 | height = intermediate_bounds.IntegerHeight() + 1; |
90 | source_array = new uint32[width + kernel_radius*2]; |
91 | target_array = new uint32[width]; |
92 | |
93 | for (int32 y=0;y<height;y++) { |
94 | uint32 *source_array_position = source_array; |
95 | for (int32 dx = 0;dx<kernel_radius;dx++) { |
96 | *source_array_position++ = *i_bits; |
97 | } |
98 | for (int32 dx=0;dx<width;dx++) { |
99 | *source_array_position++ = *i_bits++; |
100 | } |
101 | i_bits--; |
102 | for (int32 dx = 0;dx<kernel_radius;dx++) { |
103 | *source_array_position++ = *i_bits; |
104 | } |
105 | i_bits++; |
106 | convolve_1d_fixed(source_array+kernel_radius,target_array,width,fixed_kernel,kernel_radius); |
107 | |
108 | uint32 *target_array_position = target_array; |
109 | for (int32 dx = 0;dx<width;dx++) { |
110 | *(b_bits + y + (width-dx-1)*b_bpr) = *target_array_position++; |
111 | } |
112 | |
113 | } |
114 | |
115 | delete[] source_array; |
116 | delete[] target_array; |
117 | delete[] kernel_array; |
118 | delete[] fixed_kernel_array; |
119 | delete intermediate; |
120 | |
121 | return B_OK((int)0); |
122 | } |
123 | |
124 | |
125 | status_t ImageProcessingLibrary::gaussian_blur(BBitmap *bitmap,float radius, int32 threadCount) |
126 | { |
127 | int32 kernel_radius = ceil(radius); |
128 | float *kernel_array = new float[2*kernel_radius+1]; |
129 | float *kernel = &kernel_array[kernel_radius]; |
130 | float sum = 0; |
131 | int32 *fixed_kernel_array = new int32[2*kernel_radius+1]; |
132 | int32 *fixed_kernel = &fixed_kernel_array[kernel_radius]; |
133 | |
134 | float p = -log(0.004)/(pow(radius,2)*log(2)); |
135 | for (int32 i=-kernel_radius;i<=kernel_radius;i++) { |
136 | kernel[i] = pow(2,-p*i*i); |
137 | sum += kernel[i]; |
138 | } |
139 | for (int32 i=-kernel_radius;i<=kernel_radius;i++) { |
140 | kernel[i] /= sum; |
141 | fixed_kernel[i] = kernel[i] * 32768; |
142 | } |
143 | |
144 | |
145 | // Use thread-count threads. |
146 | // First blur horizontally and rotate by 90 clockwise. |
147 | /* |
148 | Rotation changes things like this |
149 | *.... ..* |
150 | ..... ... |
151 | ..... ... |
152 | ... |
153 | ... |
154 | */ |
155 | |
156 | |
157 | BRect bitmap_bounds = bitmap->Bounds(); |
158 | BRect intermediate_bounds(0,0,bitmap_bounds.Height(),bitmap_bounds.Width()); |
159 | BBitmap *intermediate = new BBitmap(intermediate_bounds,B_RGB32,false); |
160 | |
161 | int32 *s_bits = (int32*)bitmap->Bits(); |
162 | int32 s_bpr = bitmap->BytesPerRow()/4; |
163 | |
164 | int32 *d_bits = (int32*)intermediate->Bits(); |
165 | int32 d_bpr = intermediate->BytesPerRow()/4; |
166 | |
167 | // Start the threads. |
168 | thread_id blur_thread_array[8]; //TODO - Was B_MAX_CPU_COUNT, find way to decide amount of threads to use based on cpu count |
169 | for (int32 i=0;i<threadCount;i++) { |
170 | int32 height = bitmap_bounds.Height() / threadCount + 1; |
171 | filter_thread_data *data = new filter_thread_data(); |
172 | data->left = 0; |
173 | data->right = bitmap_bounds.right; |
174 | int32 top; |
175 | top = data->top = min_c(bitmap_bounds.bottom,bitmap_bounds.top + i*height)((bitmap_bounds.bottom)>(bitmap_bounds.top + i*height)?(bitmap_bounds .top + i*height):(bitmap_bounds.bottom)); |
176 | data->bottom = min_c(bitmap_bounds.bottom,top+height-1)((bitmap_bounds.bottom)>(top+height-1)?(top+height-1):(bitmap_bounds .bottom)); |
177 | |
178 | data->s_bpr = s_bpr; |
179 | data->s_bits = s_bits + top*s_bpr; |
180 | data->d_bpr = d_bpr; |
181 | data->d_bits = d_bits; |
182 | |
183 | data->kernel = fixed_kernel; |
184 | data->kernel_radius = kernel_radius; |
185 | |
186 | blur_thread_array[i] = spawn_thread(start_filter_1d_thread_clockwise,"filter_1d_thread",B_NORMAL_PRIORITY10,data); |
187 | resume_thread(blur_thread_array[i]); |
188 | } |
189 | |
190 | for (int32 i=0;i<threadCount;i++) { |
191 | int32 return_value; |
192 | wait_for_thread(blur_thread_array[i],&return_value); |
193 | } |
194 | |
195 | s_bits = (int32*)intermediate->Bits(); |
196 | s_bpr = intermediate->BytesPerRow() / 4; |
197 | |
198 | d_bits = (int32*)bitmap->Bits(); |
199 | d_bpr = bitmap->BytesPerRow()/4; |
200 | |
201 | // Here blur from intermediate to bitmap horizontally and rotate |
202 | // by 90 degrees counterclockwise |
203 | // Start the threads. |
204 | for (int32 i=0;i<threadCount;i++) { |
205 | int32 height = intermediate_bounds.Height() / threadCount + 1; |
206 | filter_thread_data *data = new filter_thread_data(); |
207 | data->left = 0; |
208 | data->right = intermediate_bounds.right; |
209 | int32 top; |
210 | top = data->top = min_c(intermediate_bounds.bottom,intermediate_bounds.top + i*height)((intermediate_bounds.bottom)>(intermediate_bounds.top + i *height)?(intermediate_bounds.top + i*height):(intermediate_bounds .bottom)); |
211 | data->bottom = min_c(intermediate_bounds.bottom,top+height-1)((intermediate_bounds.bottom)>(top+height-1)?(top+height-1 ):(intermediate_bounds.bottom)); |
212 | |
213 | data->s_bpr = s_bpr; |
214 | data->s_bits = s_bits + top*s_bpr; |
215 | data->d_bpr = d_bpr; |
216 | data->d_bits = d_bits; |
217 | |
218 | data->kernel = fixed_kernel; |
219 | data->kernel_radius = kernel_radius; |
220 | |
221 | blur_thread_array[i] = spawn_thread(start_filter_1d_thread_counterclockwise,"filter_1d_thread",B_NORMAL_PRIORITY10,data); |
222 | resume_thread(blur_thread_array[i]); |
223 | } |
224 | |
225 | for (int32 i=0;i<threadCount;i++) { |
226 | int32 return_value; |
227 | wait_for_thread(blur_thread_array[i],&return_value); |
228 | } |
229 | |
230 | delete[] kernel_array; |
231 | delete[] fixed_kernel_array; |
232 | delete intermediate; |
233 | |
234 | return B_OK((int)0); |
235 | } |
236 | |
237 | int32 ImageProcessingLibrary::start_filter_1d_thread_clockwise(void *d) |
238 | { |
239 | filter_thread_data *data = (filter_thread_data*)d; |
240 | |
241 | filter_1d_and_rotate_clockwise(data->s_bits,data->s_bpr,data->d_bits,data->d_bpr, |
242 | data->left,data->right,data->top,data->bottom,data->kernel,data->kernel_radius); |
243 | |
244 | delete data; |
245 | |
246 | return B_OK((int)0); |
247 | } |
248 | |
249 | |
250 | int32 ImageProcessingLibrary::start_filter_1d_thread_counterclockwise(void *d) |
251 | { |
252 | filter_thread_data *data = (filter_thread_data*)d; |
253 | |
254 | filter_1d_and_rotate_counterclockwise(data->s_bits,data->s_bpr,data->d_bits,data->d_bpr, |
255 | data->left,data->right,data->top,data->bottom,data->kernel,data->kernel_radius); |
256 | |
257 | delete data; |
258 | |
259 | return B_OK((int)0); |
260 | } |
261 | |
262 | |
263 | void ImageProcessingLibrary::filter_1d_and_rotate_clockwise(int32 *s_bits,int32 s_bpr,int32 *d_bits,int32 d_bpr,int32 left,int32 right,int32 top,int32 bottom,int32 *kernel,int32 kernel_radius) |
264 | { |
265 | int32 width = right - left + 1; |
266 | uint32 *source_array = new uint32[width + kernel_radius*2]; |
267 | uint32 *target_array = new uint32[width]; |
268 | |
269 | for (int32 y=top;y<=bottom;++y) { |
270 | uint32 *source_array_position = source_array; |
271 | for (int32 dx = 0;dx<kernel_radius;++dx) { |
272 | *source_array_position++ = *s_bits; |
273 | } |
274 | for (int32 dx=left;dx<=right;++dx) { |
275 | *source_array_position++ = *s_bits++; |
276 | } |
277 | s_bits--; |
278 | for (int32 dx = 0;dx<kernel_radius;++dx) { |
279 | *source_array_position++ = *s_bits; |
280 | } |
281 | s_bits++; |
282 | |
283 | convolve_1d_fixed(source_array+kernel_radius,target_array,width,kernel,kernel_radius); |
284 | |
285 | uint32 *target_array_position = target_array; |
286 | for (int32 x = left;x<=right;x++) { |
287 | *(d_bits + (d_bpr-1-y) + x*d_bpr) = *target_array_position++; |
288 | } |
289 | } |
290 | |
291 | delete[] source_array; |
292 | delete[] target_array; |
293 | } |
294 | |
295 | |
296 | void ImageProcessingLibrary::filter_1d_and_rotate_counterclockwise(int32 *s_bits,int32 s_bpr,int32 *d_bits,int32 d_bpr,int32 left,int32 right,int32 top,int32 bottom,int32 *kernel,int32 kernel_radius) |
297 | { |
298 | int32 width = right - left + 1; |
299 | uint32 *source_array = new uint32[width + kernel_radius*2]; |
300 | uint32 *target_array = new uint32[width]; |
301 | |
302 | |
303 | for (int32 y=top;y<=bottom;++y) { |
304 | uint32 *source_array_position = source_array; |
305 | for (int32 dx = 0;dx<kernel_radius;++dx) { |
306 | *source_array_position++ = *s_bits; |
307 | } |
308 | for (int32 dx=left;dx<=right;++dx) { |
309 | *source_array_position++ = *s_bits++; |
310 | } |
311 | s_bits--; |
312 | for (int32 dx = 0;dx<kernel_radius;++dx) { |
313 | *source_array_position++ = *s_bits; |
314 | } |
315 | s_bits++; |
316 | |
317 | convolve_1d_fixed(source_array+kernel_radius,target_array,width,kernel,kernel_radius); |
318 | |
319 | uint32 *target_array_position = target_array; |
320 | for (int32 x = left;x<=right;x++) { |
321 | *(d_bits + y + (right-x)*d_bpr) = *target_array_position++; |
322 | } |
323 | } |
324 | |
325 | delete[] source_array; |
326 | delete[] target_array; |
327 | } |
328 | |
329 | |
330 | void ImageProcessingLibrary::convolve_1d(uint32 *s, uint32 *t,int32 length,float *kernel,int32 kernel_radius) |
331 | { |
332 | union { |
333 | uint8 bytes[4]; |
334 | uint32 word; |
335 | } c; |
336 | |
337 | for (int32 x=0;x<length;x++) { |
338 | float red=0; |
339 | float green=0; |
340 | float blue=0; |
341 | float alpha=0; |
342 | for (int32 index = -kernel_radius;index<=kernel_radius;index++) { |
343 | c.word = *(s + index); |
344 | red += c.bytes[2] * kernel[index]; |
345 | green += c.bytes[1] * kernel[index]; |
346 | blue += c.bytes[0] * kernel[index]; |
347 | alpha += c.bytes[3] * kernel[index]; |
348 | } |
349 | |
350 | c.bytes[0] = blue; |
351 | c.bytes[1] = green; |
352 | c.bytes[2] = red; |
353 | c.bytes[3] = alpha; |
354 | |
355 | *t++ = c.word; |
356 | s++; |
357 | } |
358 | } |
359 | |
360 | |
361 | void ImageProcessingLibrary::convolve_1d_fixed(uint32 *s, uint32 *t,int32 length,int32 *kernel,int32 kernel_radius) |
362 | { |
363 | union { |
364 | uint8 bytes[4]; |
365 | uint32 word; |
366 | } c; |
367 | |
368 | for (int32 x=0;x<length;++x) { |
369 | int32 red=0; |
370 | int32 green=0; |
371 | int32 blue=0; |
372 | int32 alpha=0; |
373 | uint32 *tmp = s-kernel_radius; |
374 | int32 *kernel_tmp = kernel-kernel_radius; |
375 | for (int32 index = -kernel_radius;index<=kernel_radius;++index) { |
376 | c.word = *tmp++; |
377 | if (c.bytes[3] != 0) { |
378 | blue += (c.bytes[0] * *kernel_tmp); |
379 | green += (c.bytes[1] * *kernel_tmp); |
380 | red += (c.bytes[2] * *kernel_tmp); |
381 | } |
382 | alpha += (c.bytes[3] * *kernel_tmp++); |
383 | } |
384 | |
385 | c.bytes[0] = blue >> 15; |
386 | c.bytes[1] = green >> 15; |
387 | c.bytes[2] = red >> 15; |
388 | c.bytes[3] = alpha >> 15; |
389 | |
390 | *t++ = c.word; |
391 | s++; |
392 | } |
393 | } |
394 | |
395 | |
396 | |
397 | |
398 | |
399 | |
400 | |
401 | |
402 | /* |
403 | |
404 | Grayscale AHE |
405 | |
406 | */ |
407 | |
408 | status_t ImageProcessingLibrary::grayscale_ahe(BBitmap *bitmap, int32 regionSize) |
409 | { |
410 | int32 right,bottom; |
411 | right = bitmap->Bounds().right; |
412 | bottom = bitmap->Bounds().bottom; |
413 | |
414 | int32 region_half = regionSize / 2; |
415 | |
416 | uint8 **prev_histograms; |
417 | uint8 **next_histograms; |
418 | |
419 | int32 histogram_count_per_row = right / regionSize + 1 + 2; // extras at the edges |
420 | |
421 | prev_histograms = new uint8*[histogram_count_per_row]; |
422 | next_histograms = new uint8*[histogram_count_per_row]; |
423 | |
424 | for (int32 i=0;i<histogram_count_per_row;i++) { |
425 | prev_histograms[i] = new uint8[256]; |
426 | next_histograms[i] = new uint8[256]; |
427 | } |
428 | |
429 | int32 corner_y = 0; |
430 | int32 corner_x = 0; |
431 | // calculate the initial row of histograms |
432 | for (int32 i=0;i<histogram_count_per_row;i++) { |
433 | if (i == 1) { |
434 | for (int32 j=0;j<256;j++) { |
435 | next_histograms[1][j] = next_histograms[0][j]; |
436 | } |
437 | } |
438 | else if(i == histogram_count_per_row-1) { |
439 | for (int32 j=0;j<256;j++) { |
440 | next_histograms[i][j] = next_histograms[i][j]; |
441 | } |
442 | } |
443 | else { |
444 | calculate_local_mapping_function(bitmap,corner_x,corner_y,regionSize,next_histograms[i]); |
445 | corner_x = corner_x + regionSize; |
446 | } |
447 | } |
448 | |
449 | // make a copy of it |
450 | for (int32 i=0;i<histogram_count_per_row;i++) { |
451 | for (int32 j=0;j<256;j++) { |
452 | prev_histograms[i][j] = next_histograms[i][j]; |
453 | } |
454 | } |
455 | |
456 | |
457 | // loop through the picture |
458 | uint32 *bits = (uint32*)bitmap->Bits(); |
459 | union { |
460 | uint8 bytes[4]; |
461 | uint32 word; |
462 | } c; |
463 | |
464 | for (int32 y=0;y<=bottom;y++) { |
465 | if (y % regionSize == region_half) { |
466 | corner_y += regionSize; |
467 | if (corner_y > bottom) { |
468 | for (int32 i=0;i<histogram_count_per_row;i++) { |
469 | for (int32 j=0;j<256;j++) { |
470 | prev_histograms[i][j] = next_histograms[i][j]; |
471 | } |
472 | } |
473 | } |
474 | else { |
475 | uint8 **spare = prev_histograms; |
476 | prev_histograms = next_histograms; |
477 | |
478 | next_histograms = spare; |
479 | |
480 | corner_x = 0; |
481 | |
482 | // calculate the next row of histograms |
483 | for (int32 i=0;i<histogram_count_per_row;i++) { |
484 | if (i == 1) { |
485 | for (int32 j=0;j<256;j++) { |
486 | next_histograms[1][j] = next_histograms[0][j]; |
487 | } |
488 | } |
489 | else if(i == histogram_count_per_row-1) { |
490 | for (int32 j=0;j<256;j++) { |
491 | next_histograms[i][j] = next_histograms[i][j]; |
492 | } |
493 | } |
494 | else { |
495 | calculate_local_mapping_function(bitmap,corner_x,corner_y,regionSize,next_histograms[i]); |
496 | corner_x = corner_x + regionSize; |
497 | } |
498 | } |
499 | } |
500 | } |
501 | |
502 | int32 current_bin = 1; |
503 | int32 x_dist = region_half; |
504 | int32 y_dist = region_half; // distance to the previous center |
Value stored to 'y_dist' during its initialization is never read | |
505 | uint8 hist_index; |
506 | uint8 map_value; |
507 | |
508 | float left_coeff,right_coeff,top_coeff,bottom_coeff; |
509 | |
510 | for (int32 x=0;x<=right;x++) { |
511 | if (x % regionSize == region_half) |
512 | current_bin++; |
513 | |
514 | if (x % regionSize < region_half) { |
515 | x_dist = x % regionSize + region_half; |
516 | } |
517 | else { |
518 | x_dist = x % regionSize - region_half; |
519 | } |
520 | |
521 | if (y % regionSize < region_half) { |
522 | y_dist = y % regionSize + region_half; |
523 | } |
524 | else { |
525 | y_dist = y % regionSize - region_half; |
526 | } |
527 | |
528 | // the bins are prev...[current_bin], prev...[current_bin-1] and the same for next |
529 | |
530 | c.word = *bits; |
531 | hist_index = c.bytes[0]; |
532 | |
533 | right_coeff = (float)x_dist / (float)regionSize; |
534 | bottom_coeff = (float)y_dist / (float)regionSize; |
535 | left_coeff = 1.0 - right_coeff; |
536 | top_coeff = 1.0 - bottom_coeff; |
537 | |
538 | map_value = left_coeff*(top_coeff*prev_histograms[current_bin-1][hist_index] + |
539 | bottom_coeff*next_histograms[current_bin-1][hist_index]) + |
540 | right_coeff*(top_coeff*prev_histograms[current_bin][hist_index] + |
541 | bottom_coeff*next_histograms[current_bin][hist_index]); |
542 | |
543 | c.bytes[0] = c.bytes[1] = c.bytes[2] = map_value; |
544 | *bits++ = c.word; |
545 | } |
546 | } |
547 | |
548 | // clean up... |
549 | for (int32 i=0;i<histogram_count_per_row;i++) { |
550 | delete[] prev_histograms[i]; |
551 | delete[] next_histograms[i]; |
552 | prev_histograms[i] = NULL__null; |
553 | next_histograms[i] = NULL__null; |
554 | } |
555 | |
556 | delete[] prev_histograms; |
557 | delete[] next_histograms; |
558 | |
559 | return B_OK((int)0); |
560 | } |
561 | |
562 | |
563 | |
564 | |
565 | status_t ImageProcessingLibrary::grayscale_clahe(BBitmap *bitmap, int32 regionSize,int32 clipLimit) |
566 | { |
567 | int32 right,bottom; |
568 | right = bitmap->Bounds().right; |
569 | bottom = bitmap->Bounds().bottom; |
570 | |
571 | int32 region_half = regionSize / 2; |
572 | |
573 | uint8 **prev_histograms; |
574 | uint8 **next_histograms; |
575 | |
576 | int32 histogram_count_per_row = right / regionSize + 1 + 2; // extras at the edges |
577 | |
578 | prev_histograms = new uint8*[histogram_count_per_row]; |
579 | next_histograms = new uint8*[histogram_count_per_row]; |
580 | |
581 | for (int32 i=0;i<histogram_count_per_row;i++) { |
582 | prev_histograms[i] = new uint8[256]; |
583 | next_histograms[i] = new uint8[256]; |
584 | } |
585 | |
586 | int32 corner_y = 0; |
587 | int32 corner_x = 0; |
588 | // calculate the initial row of histograms |
589 | for (int32 i=0;i<histogram_count_per_row;i++) { |
590 | if (i == 1) { |
591 | for (int32 j=0;j<256;j++) { |
592 | next_histograms[1][j] = next_histograms[0][j]; |
593 | } |
594 | } |
595 | else if(i == histogram_count_per_row-1) { |
596 | for (int32 j=0;j<256;j++) { |
597 | next_histograms[i][j] = next_histograms[i][j]; |
598 | } |
599 | } |
600 | else { |
601 | calculate_local_mapping_function_clip(bitmap,corner_x,corner_y,regionSize,clipLimit,next_histograms[i]); |
602 | corner_x = corner_x + regionSize; |
603 | } |
604 | } |
605 | |
606 | // make a copy of it |
607 | for (int32 i=0;i<histogram_count_per_row;i++) { |
608 | for (int32 j=0;j<256;j++) { |
609 | prev_histograms[i][j] = next_histograms[i][j]; |
610 | } |
611 | } |
612 | |
613 | |
614 | // loop through the picture |
615 | uint32 *bits = (uint32*)bitmap->Bits(); |
616 | union { |
617 | uint8 bytes[4]; |
618 | uint32 word; |
619 | } c; |
620 | |
621 | for (int32 y=0;y<=bottom;y++) { |
622 | if (y % regionSize == region_half) { |
623 | corner_y += regionSize; |
624 | if (corner_y > bottom) { |
625 | for (int32 i=0;i<histogram_count_per_row;i++) { |
626 | for (int32 j=0;j<256;j++) { |
627 | prev_histograms[i][j] = next_histograms[i][j]; |
628 | } |
629 | } |
630 | } |
631 | else { |
632 | uint8 **spare = prev_histograms; |
633 | prev_histograms = next_histograms; |
634 | |
635 | next_histograms = spare; |
636 | |
637 | corner_x = 0; |
638 | |
639 | // calculate the next row of histograms |
640 | for (int32 i=0;i<histogram_count_per_row;i++) { |
641 | if (i == 1) { |
642 | for (int32 j=0;j<256;j++) { |
643 | next_histograms[1][j] = next_histograms[0][j]; |
644 | } |
645 | } |
646 | else if(i == histogram_count_per_row-1) { |
647 | for (int32 j=0;j<256;j++) { |
648 | next_histograms[i][j] = next_histograms[i][j]; |
649 | } |
650 | } |
651 | else { |
652 | calculate_local_mapping_function_clip(bitmap,corner_x,corner_y,regionSize,clipLimit,next_histograms[i]); |
653 | corner_x = corner_x + regionSize; |
654 | } |
655 | } |
656 | } |
657 | } |
658 | |
659 | int32 current_bin = 1; |
660 | int32 x_dist = region_half; |
661 | int32 y_dist = region_half; // distance to the previous center |
662 | uint8 hist_index; |
663 | uint8 map_value; |
664 | |
665 | float left_coeff,right_coeff,top_coeff,bottom_coeff; |
666 | |
667 | for (int32 x=0;x<=right;x++) { |
668 | if (x % regionSize == region_half) |
669 | current_bin++; |
670 | |
671 | if (x % regionSize < region_half) { |
672 | x_dist = x % regionSize + region_half; |
673 | } |
674 | else { |
675 | x_dist = x % regionSize - region_half; |
676 | } |
677 | |
678 | if (y % regionSize < region_half) { |
679 | y_dist = y % regionSize + region_half; |
680 | } |
681 | else { |
682 | y_dist = y % regionSize - region_half; |
683 | } |
684 | |
685 | // the bins are prev...[current_bin], prev...[current_bin-1] and the same for next |
686 | |
687 | c.word = *bits; |
688 | hist_index = c.bytes[0]; |
689 | |
690 | right_coeff = (float)x_dist / (float)regionSize; |
691 | bottom_coeff = (float)y_dist / (float)regionSize; |
692 | left_coeff = 1.0 - right_coeff; |
693 | top_coeff = 1.0 - bottom_coeff; |
694 | |
695 | map_value = left_coeff*(top_coeff*prev_histograms[current_bin-1][hist_index] + |
696 | bottom_coeff*next_histograms[current_bin-1][hist_index]) + |
697 | right_coeff*(top_coeff*prev_histograms[current_bin][hist_index] + |
698 | bottom_coeff*next_histograms[current_bin][hist_index]); |
699 | |
700 | c.bytes[0] = c.bytes[1] = c.bytes[2] = map_value; |
701 | *bits++ = c.word; |
702 | } |
703 | } |
704 | |
705 | // clean up... |
706 | for (int32 i=0;i<histogram_count_per_row;i++) { |
707 | delete[] prev_histograms[i]; |
708 | delete[] next_histograms[i]; |
709 | prev_histograms[i] = NULL__null; |
710 | next_histograms[i] = NULL__null; |
711 | } |
712 | |
713 | delete[] prev_histograms; |
714 | delete[] next_histograms; |
715 | |
716 | return B_OK((int)0); |
717 | } |
718 | |
719 | |
720 | |
721 | |
722 | void ImageProcessingLibrary::calculate_local_mapping_function(BBitmap *bitmap,int32 cx, int32 cy,int32 regionSize,uint8 *mapFunction) |
723 | { |
724 | int32 left,right,top,bottom; |
725 | left = cx; |
726 | top = cy; |
727 | right = min_c(left+regionSize-1,bitmap->Bounds().right)((left+regionSize-1)>(bitmap->Bounds().right)?(bitmap-> Bounds().right):(left+regionSize-1)); |
728 | bottom = min_c(top+regionSize-1,bitmap->Bounds().bottom)((top+regionSize-1)>(bitmap->Bounds().bottom)?(bitmap-> Bounds().bottom):(top+regionSize-1)); |
729 | |
730 | |
731 | uint32 *bits = (uint32*)bitmap->Bits(); |
732 | int32 bpr = bitmap->BytesPerRow()/4; |
733 | |
734 | union { |
735 | uint8 bytes[4]; |
736 | uint32 word; |
737 | } c; |
738 | |
739 | // calculate the histogram |
740 | int32 histogram[256]; |
741 | for (int32 i=0;i<256;i++) { |
742 | histogram[i] = 0; |
743 | } |
744 | |
745 | for (int32 y=top;y<=bottom;y++) { |
746 | for (int32 x=left;x<=right;x++) { |
747 | c.word = *(bits + x + y*bpr); |
748 | histogram[c.bytes[0]]++; |
749 | } |
750 | } |
751 | |
752 | // make the histogram cumulative |
753 | for (int32 i=1;i<256;i++) { |
754 | histogram[i] = histogram[i] + histogram[i-1]; |
755 | } |
756 | |
757 | |
758 | // normalize cumulative histogram to create mapping function |
759 | float multiplier = 255.0 / (float)histogram[255]; |
760 | |
761 | for (int32 i=0;i<256;i++) { |
762 | mapFunction[i] = floor(histogram[i]*multiplier); |
763 | } |
764 | } |
765 | |
766 | |
767 | |
768 | void ImageProcessingLibrary::calculate_local_mapping_function_clip(BBitmap *bitmap,int32 cx, int32 cy,int32 regionSize,int32 clipLimit,uint8 *mapFunction) |
769 | { |
770 | int32 left,right,top,bottom; |
771 | left = cx; |
772 | top = cy; |
773 | right = min_c(left+regionSize-1,bitmap->Bounds().right)((left+regionSize-1)>(bitmap->Bounds().right)?(bitmap-> Bounds().right):(left+regionSize-1)); |
774 | bottom = min_c(top+regionSize-1,bitmap->Bounds().bottom)((top+regionSize-1)>(bitmap->Bounds().bottom)?(bitmap-> Bounds().bottom):(top+regionSize-1)); |
775 | |
776 | uint32 *bits = (uint32*)bitmap->Bits(); |
777 | int32 bpr = bitmap->BytesPerRow()/4; |
778 | |
779 | union { |
780 | uint8 bytes[4]; |
781 | uint32 word; |
782 | } c; |
783 | |
784 | // calculate the histogram |
785 | int32 histogram[256]; |
786 | for (int32 i=0;i<256;i++) { |
787 | histogram[i] = 0; |
788 | } |
789 | |
790 | for (int32 y=top;y<=bottom;y++) { |
791 | for (int32 x=left;x<=right;x++) { |
792 | c.word = *(bits + x + y*bpr); |
793 | histogram[c.bytes[0]]++; |
794 | } |
795 | } |
796 | |
797 | |
798 | // clip the histogram |
799 | int32 actual_clip_limit; |
800 | |
801 | top = clipLimit; |
802 | bottom = 0; |
803 | int32 middle; |
804 | int32 S; |
805 | while ((top - bottom) > 1) { |
806 | middle = (top + bottom) / 2; |
807 | S = 0; |
808 | for (int32 i=0;i<256;i++) { |
809 | if (histogram[i] > middle) |
810 | S += histogram[i] - middle; |
811 | } |
812 | if (S > (clipLimit-middle)*256) { |
813 | top = middle; |
814 | } |
815 | else { |
816 | bottom = middle; |
817 | } |
818 | } |
819 | |
820 | actual_clip_limit = bottom + S/256; |
821 | int32 L = clipLimit - actual_clip_limit; |
822 | |
823 | for (int32 i=0;i<256;i++) { |
824 | if (histogram[i] >= actual_clip_limit) |
825 | histogram[i] = clipLimit; |
826 | else |
827 | histogram[i] += L; |
828 | } |
829 | |
830 | |
831 | |
832 | // make the histogram cumulative |
833 | for (int32 i=1;i<256;i++) { |
834 | histogram[i] = histogram[i] + histogram[i-1]; |
835 | } |
836 | |
837 | |
838 | // normalize cumulative histogram to create mapping function |
839 | float multiplier = 255.0 / (float)histogram[255]; |
840 | |
841 | for (int32 i=0;i<256;i++) { |
842 | mapFunction[i] = floor(histogram[i]*multiplier); |
843 | } |
844 | |
845 | } |