This source file includes following definitions.
- clip
- identity
- logarithmic
- histogram_alloc
- histogram_sample_stage
- histogram_process
- gui_osd_draw_single_histo
- gui_osd_draw_blended_histo
- gui_osd_draw_histo
- _module_unloader
- _module_can_unload
1 #include "camera_info.h"
2 #include "conf.h"
3 #include "math.h"
4 #include "modes.h"
5 #include "viewport.h"
6 #include "gui.h"
7 #include "gui_draw.h"
8 #include "gui_osd.h"
9 #include "shooting.h"
10 #include "histogram.h"
11
12
13
14
15 #define HISTO_R 0
16 #define HISTO_G 1
17 #define HISTO_B 2
18 #define HISTO_RGB 3
19 #define HISTO_Y 4
20
21
22 #define HISTO_MODE_LINEAR 0
23 #define HISTO_MODE_LOG 1
24
25
26 #define OSD_HISTO_LAYOUT_A 0
27 #define OSD_HISTO_LAYOUT_Y 1
28 #define OSD_HISTO_LAYOUT_A_Y 2
29 #define OSD_HISTO_LAYOUT_R_G_B 3
30 #define OSD_HISTO_LAYOUT_A_yrgb 4
31 #define OSD_HISTO_LAYOUT_Y_argb 5
32 #define OSD_HISTO_LAYOUT_BLEND 6
33 #define OSD_HISTO_LAYOUT_BLEND_Y 7
34 #ifndef THUMB_FW
35 #define HISTO_DOT_SIZE 3
36 #else
37
38 #define HISTO_DOT_SIZE 5
39 #endif
40 #define HISTO_DOT_PAD (HISTO_DOT_SIZE + 2)
41
42
43
44
45
46
47
48 #define HISTO_TARGET_SAMPLES 20000
49
50 #define HISTO_XSTEP_MIN 4
51
52 #define HISTO_YSTEP_MIN 2
53
54 static unsigned char histogram[5][HISTO_WIDTH];
55 static unsigned short *histogram_proc[5] = { 0,0,0,0,0 };
56 unsigned int histo_max[5], histo_max_center[5];
57 static float histo_max_center_invw[5];
58
59 static long histo_magnification;
60 static long under_exposed;
61 static long over_exposed;
62
63 static long histogram_stage=0;
64
65
66
67
68
69 static int clip(int v)
70 {
71 if (v<0) v=0;
72 else if (v>255) v=255;
73 return v;
74 }
75
76
77 static float identity(float x) { return x; }
78 static float logarithmic(float x) { return log(x); }
79
80 static void histogram_alloc()
81 {
82
83
84
85
86 if (histogram_proc[0] == 0)
87 {
88 histogram_proc[0] = malloc(5 * 256 * sizeof(unsigned short));
89 histogram_proc[1] = histogram_proc[0] + 256;
90 histogram_proc[2] = histogram_proc[1] + 256;
91 histogram_proc[3] = histogram_proc[2] + 256;
92 histogram_proc[4] = histogram_proc[3] + 256;
93 }
94 }
95
96
97
98
99
100
101
102 void histogram_sample_stage(unsigned char *img, int stage, int byte_width, int vis_byte_width, int height, int xstep_bytes, int ystep)
103 {
104
105 unsigned char *p_row = img + stage*ystep*byte_width + xstep_bytes;
106
107 unsigned char *p_max = img + byte_width*(height-ystep);
108
109
110 int row_sample_len = vis_byte_width - 2*xstep_bytes;
111
112
113 int ystep_bytes = ystep*byte_width*3;
114
115 for(;p_row < p_max; p_row += ystep_bytes) {
116
117 unsigned char *p = p_row;
118 unsigned char *p_row_end = p_row + row_sample_len;
119 for(;p < p_row_end; p+= xstep_bytes) {
120 int y, v, u, hi;
121 y = p[1];
122 #ifndef THUMB_FW
123 u = (signed char)p[0];
124 v = (signed char)p[2];
125 #else
126 u = (int)p[0] - 128;
127 v = (int)p[2] - 128;
128 #endif
129
130
131 ++histogram_proc[HISTO_Y][y];
132 hi = clip(((y<<12) + v*5743 + 2048)>>12);
133 ++histogram_proc[HISTO_R][hi];
134 hi = clip(((y<<12) - u*1411 - v*2925 + 2048)>>12);
135 ++histogram_proc[HISTO_G][hi];
136 hi = clip(((y<<12) + u*7258 + 2048)>>12);
137 ++histogram_proc[HISTO_B][hi];
138 }
139 }
140 }
141
142 void histogram_process()
143 {
144 static unsigned char *img;
145
146 static int viewport_byte_width, viewport_height;
147
148 static int viewport_vis_byte_width;
149 static int xstep_bytes, ystep;
150
151 int i, c;
152 float (*histogram_transform)(float);
153 unsigned int histo_fill[5];
154 int histo_main;
155
156 long exposition_thresh = camera_screen.size / 500;
157
158
159 switch (conf.histo_mode)
160 {
161 case HISTO_MODE_LOG:
162 histogram_transform = logarithmic;
163 break;
164 case HISTO_MODE_LINEAR:
165 default:
166 histogram_transform = identity;
167 break;
168 }
169
170
171 if (conf.histo_layout == OSD_HISTO_LAYOUT_Y || conf.histo_layout == OSD_HISTO_LAYOUT_Y_argb)
172 histo_main = HISTO_Y;
173 else
174 histo_main = HISTO_RGB;
175
176 histogram_alloc();
177
178
179
180
181
182
183
184
185 switch (histogram_stage)
186 {
187 case 0: {
188 img = vid_get_viewport_active_buffer();
189 if (!img) return;
190
191 img += vid_get_viewport_image_offset();
192
193 viewport_height = vid_get_viewport_height_proper();
194 viewport_byte_width = vid_get_viewport_byte_width();
195 int viewport_pix_width = vid_get_viewport_width_proper();
196 int total_pixels = viewport_pix_width * viewport_height;
197 int xstep;
198
199 if(total_pixels <= HISTO_XSTEP_MIN*HISTO_YSTEP_MIN*HISTO_TARGET_SAMPLES) {
200 xstep = HISTO_XSTEP_MIN;
201 ystep = HISTO_YSTEP_MIN;
202 } else {
203
204 ystep = total_pixels/(HISTO_XSTEP_MIN*HISTO_TARGET_SAMPLES);
205
206
207 if(ystep >= 5*HISTO_YSTEP_MIN) {
208 xstep = 2*HISTO_XSTEP_MIN;
209 ystep >>= 1;
210 } else {
211 xstep = HISTO_XSTEP_MIN;
212 }
213 }
214
215
216 #ifndef THUMB_FW
217 xstep_bytes = (xstep*3)/2;
218 viewport_vis_byte_width = (viewport_pix_width*3)/2;
219 #else
220 xstep_bytes = xstep*2;
221 viewport_vis_byte_width = viewport_pix_width*2;
222 #endif
223
224 for (c=0; c<5; ++c) {
225 memset(histogram_proc[c],0,256*sizeof(unsigned short));
226 histo_max[c] = histo_max_center[c] = 0;
227 }
228
229 histogram_stage=1;
230 break;
231 }
232
233 case 1:
234 case 2:
235 case 3: {
236 histogram_sample_stage(img, histogram_stage, viewport_byte_width, viewport_vis_byte_width, viewport_height, xstep_bytes, ystep);
237 ++histogram_stage;
238 break;
239 }
240
241 case 4:
242 for (i=0, c=0; i<HISTO_WIDTH; ++i, c+=2) {
243
244
245 #ifndef THUMB_FW
246 histogram_proc[HISTO_Y][i] = histogram_proc[HISTO_Y][c] + histogram_proc[HISTO_Y][c+1];
247 histogram_proc[HISTO_R][i] = histogram_proc[HISTO_R][c] + histogram_proc[HISTO_R][c+1];
248 histogram_proc[HISTO_G][i] = histogram_proc[HISTO_G][c] + histogram_proc[HISTO_G][c+1];
249 histogram_proc[HISTO_B][i] = histogram_proc[HISTO_B][c] + histogram_proc[HISTO_B][c+1];
250 #endif
251
252 histogram_proc[HISTO_RGB][i] = histogram_proc[HISTO_R][i] + histogram_proc[HISTO_G][i] + histogram_proc[HISTO_B][i];
253 }
254
255
256 for (c=0; c<5; ++c) {
257 for (i=0; i<HISTO_WIDTH; ++i) {
258 if (histo_max[c]<histogram_proc[c][i])
259 histo_max[c]=histogram_proc[c][i];
260 if (histo_max_center[c]<histogram_proc[c][i] && i>=conf.histo_ignore_boundary && i<HISTO_WIDTH-conf.histo_ignore_boundary)
261 histo_max_center[c]=histogram_proc[c][i];
262 }
263
264 if (histo_max_center[c] > 0) {
265 histo_max_center_invw[c] = ((float)HISTO_HEIGHT)/histogram_transform((float)histo_max_center[c]);
266 } else if (histo_max[c] > 0) {
267 histo_max_center_invw[c] = ((float)HISTO_HEIGHT)/histogram_transform((float)histo_max[c]);
268 } else {
269 histo_max_center_invw[c] = 0.0f;
270 }
271 }
272
273 if (histo_max[HISTO_RGB] > 0) {
274 under_exposed = (histogram_proc[HISTO_RGB][0]*8
275 +histogram_proc[HISTO_RGB][1]*4
276 +histogram_proc[HISTO_RGB][2]) > exposition_thresh;
277
278 over_exposed = (histogram_proc[HISTO_RGB][HISTO_WIDTH-3]
279 +histogram_proc[HISTO_RGB][HISTO_WIDTH-2]*4
280 +histogram_proc[HISTO_RGB][HISTO_WIDTH-1]*8) > exposition_thresh;
281 } else {
282 over_exposed = 0;
283 under_exposed = 1;
284 }
285
286 histogram_stage=5;
287 break;
288
289 case 5:
290 for (c=0; c<5; ++c) {
291 histo_fill[c]=0;
292 for (i=0; i<HISTO_WIDTH; ++i) {
293 histogram[c][i] = (histogram_transform((float)histogram_proc[c][i]))*histo_max_center_invw[c];
294 if (histogram[c][i] > HISTO_HEIGHT)
295 histogram[c][i] = HISTO_HEIGHT;
296 histo_fill[c]+=histogram[c][i];
297 }
298 }
299
300 histo_magnification = 0;
301 if (conf.histo_auto_ajust) {
302 if (histo_fill[histo_main] < (HISTO_HEIGHT*HISTO_WIDTH)/5) {
303 histo_magnification = (20*HISTO_HEIGHT*HISTO_WIDTH) / histo_fill[histo_main];
304 for (c=0; c<5; ++c) {
305 for (i=0;i<HISTO_WIDTH;i++) {
306 histogram[c][i] = histogram[c][i] * histo_magnification / 100;
307 if (histogram[c][i] > HISTO_HEIGHT)
308 histogram[c][i] = HISTO_HEIGHT;
309 }
310 }
311 }
312 }
313
314 histogram_stage=0;
315 break;
316 }
317
318 }
319
320
321
322
323 static void gui_osd_draw_single_histo(int hist, coord x, coord y, int small)
324 {
325 twoColors hc = user_color(conf.histo_color);
326 twoColors hc2 = user_color(conf.histo_color2);
327
328 register int i, v, threshold;
329 register color cl, cl_over, cl_bg = BG_COLOR(hc);
330 coord w=HISTO_WIDTH, h=HISTO_HEIGHT;
331
332 switch (hist)
333 {
334 case HISTO_R:
335 cl=COLOR_RED;
336 break;
337 case HISTO_G:
338 cl=COLOR_GREEN;
339 break;
340 case HISTO_B:
341 cl=COLOR_BLUE;
342 break;
343 case HISTO_RGB:
344 case HISTO_Y:
345 default:
346 cl=FG_COLOR(hc);
347 break;
348 }
349
350 if (small) {
351 h>>=1; w>>=1;
352 for (i=0; i<w; ++i) {
353 threshold = (histogram[hist][i<<1]+histogram[hist][(i<<1)+1])>>2;
354
355 for (v=1; v<h-1; ++v)
356 draw_pixel(x+1+i, y+h-v, (v<=threshold)?cl:cl_bg);
357 cl_over = (threshold==h && conf.show_overexp)?BG_COLOR(hc2):cl;
358 for (; v<h; ++v)
359 draw_pixel(x+1+i, y+h-v, (v<=threshold)?cl_over:cl_bg);
360 }
361 } else {
362 for (i=0; i<w; ++i) {
363 threshold = histogram[hist][i];
364
365 for (v=1; v<h-3; ++v)
366 draw_pixel(x+1+i, y+h-v, (v<=threshold)?cl:cl_bg);
367 cl_over = (threshold==h && conf.show_overexp)?BG_COLOR(hc2):cl;
368 for (; v<h; ++v)
369 draw_pixel(x+1+i, y+h-v, (v<=threshold)?cl_over:cl_bg);
370 }
371 }
372
373 draw_rectangle(x, y, x+1+w, y+h, hc2, RECT_BORDER1);
374
375 if (conf.histo_show_ev_grid) for (i=1;i<=4;i++) draw_line(x+(1+w)*i/5, y, x+(1+w)*i/5, y+h, FG_COLOR(hc2));
376 }
377
378
379 static void gui_osd_draw_blended_histo(coord x, coord y)
380 {
381 twoColors hc = user_color(conf.histo_color);
382 twoColors hc2 = user_color(conf.histo_color2);
383
384 register unsigned int i, v, red, grn, blu, sel;
385 color cls[] = {
386 BG_COLOR(hc),
387 COLOR_BLUE,
388 COLOR_GREEN,
389 COLOR_CYAN,
390 COLOR_RED,
391 COLOR_MAGENTA,
392 COLOR_YELLOW,
393 COLOR_WHITE
394 };
395
396 for (i=0; i<HISTO_WIDTH; ++i) {
397 red = histogram[HISTO_R][i];
398 grn = histogram[HISTO_G][i];
399 blu = histogram[HISTO_B][i];
400
401 for (v=1; v<HISTO_HEIGHT; ++v) {
402 sel = 0;
403
404 if (v < red) sel = 4;
405 if (v < grn) sel |= 2;
406 if (v < blu) sel |= 1;
407
408 draw_pixel(x+1+i, y+HISTO_HEIGHT-v, cls[sel]);
409 }
410 }
411
412 draw_rectangle(x, y, x+1+HISTO_WIDTH, y+HISTO_HEIGHT, hc2, RECT_BORDER1);
413
414 if (conf.histo_show_ev_grid) for (i=1;i<=4;i++) draw_line(x+(1+HISTO_WIDTH)*i/5, y, x+(1+HISTO_WIDTH)*i/5, y+HISTO_HEIGHT, FG_COLOR(hc2));
415
416 }
417
418
419 void gui_osd_draw_histo(int is_osd_edit)
420 {
421 if (is_osd_edit ||
422 ((camera_info.state.mode_play || !camera_info.state.mode_video) &&
423 (
424 ((conf.show_histo==SHOW_HISTO_HALF) && camera_info.state.is_shutter_half_press) ||
425 ((conf.show_histo==SHOW_HISTO_REC) && camera_info.state.mode_rec && (recreview_hold==0)) ||
426 ((conf.show_histo==SHOW_HISTO_ALWAYS) && (recreview_hold==0))
427 )
428 )
429 )
430 {
431 twoColors hc = user_color(conf.histo_color);
432 twoColors hc2 = user_color(conf.histo_color2);
433
434 switch (conf.histo_layout)
435 {
436 case OSD_HISTO_LAYOUT_Y:
437 gui_osd_draw_single_histo(HISTO_Y, conf.histo_pos.x, conf.histo_pos.y, 0);
438 break;
439 case OSD_HISTO_LAYOUT_A_Y:
440 gui_osd_draw_single_histo(HISTO_RGB, conf.histo_pos.x, conf.histo_pos.y, 0);
441 gui_osd_draw_single_histo(HISTO_Y, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT, 0);
442 break;
443 case OSD_HISTO_LAYOUT_R_G_B:
444 gui_osd_draw_single_histo(HISTO_R, conf.histo_pos.x, conf.histo_pos.y, 0);
445 gui_osd_draw_single_histo(HISTO_G, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT, 0);
446 gui_osd_draw_single_histo(HISTO_B, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT*2, 0);
447 break;
448 case OSD_HISTO_LAYOUT_A_yrgb:
449 gui_osd_draw_single_histo(HISTO_RGB, conf.histo_pos.x, conf.histo_pos.y, 0);
450 gui_osd_draw_single_histo(HISTO_Y, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT, 1);
451 gui_osd_draw_single_histo(HISTO_R, conf.histo_pos.x+HISTO_WIDTH/2+1, conf.histo_pos.y+HISTO_HEIGHT, 1);
452 gui_osd_draw_single_histo(HISTO_G, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT+HISTO_HEIGHT/2, 1);
453 gui_osd_draw_single_histo(HISTO_B, conf.histo_pos.x+HISTO_WIDTH/2+1, conf.histo_pos.y+HISTO_HEIGHT+HISTO_HEIGHT/2, 1);
454 break;
455 case OSD_HISTO_LAYOUT_Y_argb:
456 gui_osd_draw_single_histo(HISTO_Y, conf.histo_pos.x, conf.histo_pos.y, 0);
457 gui_osd_draw_single_histo(HISTO_RGB, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT, 1);
458 gui_osd_draw_single_histo(HISTO_R, conf.histo_pos.x+HISTO_WIDTH/2+1, conf.histo_pos.y+HISTO_HEIGHT, 1);
459 gui_osd_draw_single_histo(HISTO_G, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT+HISTO_HEIGHT/2, 1);
460 gui_osd_draw_single_histo(HISTO_B, conf.histo_pos.x+HISTO_WIDTH/2+1, conf.histo_pos.y+HISTO_HEIGHT+HISTO_HEIGHT/2, 1);
461 break;
462 case OSD_HISTO_LAYOUT_BLEND:
463 gui_osd_draw_blended_histo(conf.histo_pos.x, conf.histo_pos.y);
464 break;
465 case OSD_HISTO_LAYOUT_BLEND_Y:
466 gui_osd_draw_blended_histo(conf.histo_pos.x, conf.histo_pos.y);
467 gui_osd_draw_single_histo(HISTO_Y, conf.histo_pos.x, conf.histo_pos.y+HISTO_HEIGHT, 0);
468 break;
469 case OSD_HISTO_LAYOUT_A:
470 default:
471 gui_osd_draw_single_histo(HISTO_RGB, conf.histo_pos.x, conf.histo_pos.y, 0);
472 break;
473 }
474
475 if (conf.histo_layout != OSD_HISTO_LAYOUT_R_G_B)
476 {
477 if (under_exposed && conf.show_overexp)
478 {
479 draw_ellipse(conf.histo_pos.x+HISTO_DOT_PAD, conf.histo_pos.y+HISTO_DOT_PAD,
480 HISTO_DOT_SIZE, HISTO_DOT_SIZE, BG_COLOR(hc2), DRAW_FILLED);
481 }
482 if (over_exposed && conf.show_overexp)
483 {
484 draw_ellipse(conf.histo_pos.x+HISTO_WIDTH-HISTO_DOT_PAD, conf.histo_pos.y+HISTO_DOT_PAD,
485 HISTO_DOT_SIZE, HISTO_DOT_SIZE, BG_COLOR(hc2), DRAW_FILLED);
486 }
487 }
488 if ((conf.show_overexp ) && camera_info.state.is_shutter_half_press && (under_exposed || over_exposed))
489 draw_string(conf.histo_pos.x+HISTO_WIDTH-FONT_WIDTH*3, conf.histo_pos.y-FONT_HEIGHT, "EXP", hc);
490 if (conf.histo_auto_ajust){
491 if (histo_magnification) {
492 char osd_buf[64];
493 sprintf(osd_buf, " %d.%02dx ", histo_magnification/100, histo_magnification%100);
494 draw_string(conf.histo_pos.x, conf.histo_pos.y-FONT_HEIGHT, osd_buf, hc);
495 } else if (is_osd_edit){
496 draw_string(conf.histo_pos.x, conf.histo_pos.y-FONT_HEIGHT, " 9.99x ", hc);
497 } else {
498 draw_rectangle(conf.histo_pos.x, conf.histo_pos.y-FONT_HEIGHT, conf.histo_pos.x+8*FONT_WIDTH, conf.histo_pos.y-1, MAKE_COLOR(COLOR_TRANSPARENT, COLOR_TRANSPARENT), RECT_BORDER0|DRAW_FILLED);
499 }
500 }
501 }
502 }
503
504
505
506
507
508
509
510
511
512
513
514
515 int _module_unloader()
516 {
517 return 0;
518 }
519
520 int _module_can_unload()
521 {
522 return conf.show_histo == 0;
523 }
524
525
526
527 libhisto_sym _libhisto =
528 {
529 {
530 0, _module_unloader, _module_can_unload, 0, 0
531 },
532
533 histogram_process,
534 gui_osd_draw_histo
535 };
536
537 ModuleInfo _module_info =
538 {
539 MODULEINFO_V1_MAGICNUM,
540 sizeof(ModuleInfo),
541 HISTO_VERSION,
542
543 ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,
544 ANY_PLATFORM_ALLOWED,
545
546 (int32_t)"Histogram Overlay (dll)",
547 MTYPE_EXTENSION,
548
549 &_libhisto.base,
550
551 CONF_VERSION,
552 CAM_SCREEN_VERSION,
553 ANY_VERSION,
554 CAM_INFO_VERSION,
555
556 0,
557 };
558
559