/** * Initialize the relational histogram for the distance and angle parameters */ void REM::initializeHistogram() { hist = histogram_alloc(binDimension, binDimension); histogram_set_ranges_uniform(hist, minDist, maxDist, minAngle, maxAngle); }
void histogram_process() { static unsigned char *img; static int viewport_size, viewport_width, viewport_row_offset; register int x, i, hi; int y, v, u, c; float (*histogram_transform)(float); unsigned int histo_fill[5]; int histo_main; long exposition_thresh = camera_screen.size / 500; // Select transform function switch (conf.histo_mode) { case HISTO_MODE_LOG: histogram_transform = logarithmic; break; case HISTO_MODE_LINEAR: default: histogram_transform = identity; break; } // Select which calculated histogram channel determines magnification / scaling if (conf.histo_layout == OSD_HISTO_LAYOUT_Y || conf.histo_layout == OSD_HISTO_LAYOUT_Y_argb) histo_main = HISTO_Y; else histo_main = HISTO_RGB; histogram_alloc(); // This function is called in the main spytask loop roughly every 20msec // To avoid hogging all the CPU it performs it's work in stages controlled by histogram-stage // Stage Function // 0 Initialize global variables used in next stages // 1,2,3 Count number of values for a third of the viewport image at each stage // 4 Calculate max values, over and under exposure setting // 5 Calculate the histogram display values switch (histogram_stage) { case 0: img=vid_get_viewport_active_buffer(); if (!img) return; img += vid_get_viewport_image_offset(); // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD) viewport_size = vid_get_viewport_height() * vid_get_viewport_byte_width() * vid_get_viewport_yscale(); viewport_width = vid_get_viewport_width(); viewport_row_offset = vid_get_viewport_row_offset(); for (c=0; c<5; ++c) { memset(histogram_proc[c],0,256*sizeof(unsigned short)); histo_max[c] = histo_max_center[c] = 0; } histogram_stage=1; break; case 1: case 2: case 3: x = 0; // count how many blocks we have done on the current row (to skip unused buffer space at end of each row) for (i=(histogram_stage-1)*6; i<viewport_size; i+=HISTO_STEP_SIZE*6) { y = img[i+1]; u = *(signed char*)(&img[i]); //if (u&0x00000080) u|=0xFFFFFF00; // Compiler should handle the unsigned -> signed conversion v = *(signed char*)(&img[i+2]); //if (v&0x00000080) v|=0xFFFFFF00; // Compiler should handle the unsigned -> signed conversion ++histogram_proc[HISTO_Y][y]; // Y hi = clip(((y<<12) + v*5743 + 2048)>>12); // R ++histogram_proc[HISTO_R][hi]; hi = clip(((y<<12) - u*1411 - v*2925 + 2048)>>12); // G ++histogram_proc[HISTO_G][hi]; hi = clip(((y<<12) + u*7258 + 2048)>>12); // B ++histogram_proc[HISTO_B][hi]; // Handle case where viewport memory buffer is wider than the actual buffer. x += HISTO_STEP_SIZE * 2; // viewport width is measured in blocks of three bytes each even though the data is stored in six byte chunks ! if (x == viewport_width) { i += viewport_row_offset; x = 0; } } ++histogram_stage; break; case 4: for (i=0, c=0; i<HISTO_WIDTH; ++i, c+=2) { // G // Merge each pair of values into a single value (for width = 128) // Warning: this is optimised for HISTO_WIDTH = 128, don't change the width unless you re-write this code as well. histogram_proc[HISTO_Y][i] = histogram_proc[HISTO_Y][c] + histogram_proc[HISTO_Y][c+1]; histogram_proc[HISTO_R][i] = histogram_proc[HISTO_R][c] + histogram_proc[HISTO_R][c+1]; histogram_proc[HISTO_G][i] = histogram_proc[HISTO_G][c] + histogram_proc[HISTO_G][c+1]; histogram_proc[HISTO_B][i] = histogram_proc[HISTO_B][c] + histogram_proc[HISTO_B][c+1]; // Calc combined RGB totals histogram_proc[HISTO_RGB][i] = histogram_proc[HISTO_R][i] + histogram_proc[HISTO_G][i] + histogram_proc[HISTO_B][i]; } // calculate maximums for (c=0; c<5; ++c) { for (i=0; i<HISTO_WIDTH; ++i) { if (histo_max[c]<histogram_proc[c][i]) histo_max[c]=histogram_proc[c][i]; if (histo_max_center[c]<histogram_proc[c][i] && i>=conf.histo_ignore_boundary && i<HISTO_WIDTH-conf.histo_ignore_boundary) histo_max_center[c]=histogram_proc[c][i]; } if (histo_max_center[c] > 0) { histo_max_center_invw[c] = ((float)HISTO_HEIGHT)/histogram_transform((float)histo_max_center[c]); } else if (histo_max[c] > 0) { histo_max_center_invw[c] = ((float)HISTO_HEIGHT)/histogram_transform((float)histo_max[c]); } else { histo_max_center_invw[c] = 0.0f; } } if (histo_max[HISTO_RGB] > 0) { // over- / under- expos under_exposed = (histogram_proc[HISTO_RGB][0]*8 +histogram_proc[HISTO_RGB][1]*4 +histogram_proc[HISTO_RGB][2]) > exposition_thresh; over_exposed = (histogram_proc[HISTO_RGB][HISTO_WIDTH-3] +histogram_proc[HISTO_RGB][HISTO_WIDTH-2]*4 +histogram_proc[HISTO_RGB][HISTO_WIDTH-1]*8) > exposition_thresh; } else { over_exposed = 0; under_exposed = 1; } histogram_stage=5; break; case 5: for (c=0; c<5; ++c) { histo_fill[c]=0; for (i=0; i<HISTO_WIDTH; ++i) { histogram[c][i] = (histogram_transform((float)histogram_proc[c][i]))*histo_max_center_invw[c]; if (histogram[c][i] > HISTO_HEIGHT) histogram[c][i] = HISTO_HEIGHT; histo_fill[c]+=histogram[c][i]; } } histo_magnification = 0; if (conf.histo_auto_ajust) { if (histo_fill[histo_main] < (HISTO_HEIGHT*HISTO_WIDTH)/5) { // try to ajust if average level is less than 20% histo_magnification = (20*HISTO_HEIGHT*HISTO_WIDTH) / histo_fill[histo_main]; for (c=0; c<5; ++c) { for (i=0;i<HISTO_WIDTH;i++) { histogram[c][i] = histogram[c][i] * histo_magnification / 100; if (histogram[c][i] > HISTO_HEIGHT) histogram[c][i] = HISTO_HEIGHT; } } } } histogram_stage=0; break; } }