static void get_viewport_size() { viewport_height = vid_get_viewport_height()-camera_screen.edge_hmargin*2; //don't trace bottom lines viewport_width = vid_get_viewport_width(); viewport_byte_width = vid_get_viewport_byte_width(); viewport_yscale = vid_get_viewport_yscale(); viewport_xoffset = vid_get_viewport_display_xoffset(); viewport_yoffset = vid_get_viewport_display_yoffset(); slice_height = viewport_height / EDGE_SLICES; }
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; } }
static int md_detect_motion(void) { int idx, tick, rv; int val, cy, cv, cu; register int col, row, x, y; if(!md_running()) { return 0; } tick = get_tick_count(); rv = 1; #ifdef OPT_MD_DEBUG if(motion_detector.comp_calls_cnt < MD_REC_CALLS_CNT) { motion_detector.comp_calls[motion_detector.comp_calls_cnt]=tick; } motion_detector.comp_calls_cnt++; #endif if(motion_detector.start_time + motion_detector.timeout < tick ) { md_save_calls_history(); motion_detector.running = 0; return 0; } if(motion_detector.last_measure_time + motion_detector.measure_interval > tick) { // wait for the next time return 1; } motion_detector.last_measure_time = tick; unsigned char* img = vid_get_viewport_live_fb(); if(img==NULL) { img = vid_get_viewport_fb(); } #ifdef OPT_MD_DEBUG if(motion_detector.comp_calls_cnt==50 && (motion_detector.parameters & MD_MAKE_RAM_DUMP_FILE) != 0 ) { mx_dump_memory((char*)img); } #endif img += vid_get_viewport_image_offset(); // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD) int vp_h = vid_get_viewport_height(); int vp_w = vid_get_viewport_width(); int vp_bw = vid_get_viewport_byte_width() * vid_get_viewport_yscale(); int x_step = motion_detector.pixels_step * 3; int y_step = motion_detector.pixels_step * vp_bw; for (idx=0, row=0; row < motion_detector.rows; row++) { // Calc img y start and end offsets (use same height for all cells so 'points' is consistent) int y_start = ((row * vp_h) / motion_detector.rows) * vp_bw; int y_end = y_start + ((vp_h / motion_detector.rows) * vp_bw); for (col=0; col < motion_detector.columns; col++, idx++) { int in_clipping_region=0; if (col+1 >= motion_detector.clipping_region_column1 && col+1 <= motion_detector.clipping_region_column2 && row+1 >= motion_detector.clipping_region_row1 && row+1 <= motion_detector.clipping_region_row2) { in_clipping_region=1; } int curr = 0; int diff = 0; if ( (motion_detector.clipping_region_mode==MD_REGION_NONE) || (motion_detector.clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0) || (motion_detector.clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1) ) { // Calc img x start and end offsets (use same width for all cells so 'points' is consistent) int x_start = ((col * vp_w) / motion_detector.columns) * 3; int x_end = x_start + ((vp_w / motion_detector.columns) * 3); int points = 0; for (y=y_start; y<y_end; y+=y_step) { for (x=x_start; x<x_end; x+=x_step) { // ARRAY of UYVYYY values // 6 bytes - 4 pixels if (motion_detector.pixel_measure_mode == MD_MEASURE_MODE_Y) { val = img[y + x + 1]; //Y } else { // Calc offset to UYV component int uvx = x; if (uvx & 1) uvx -= 3; switch(motion_detector.pixel_measure_mode) { case MD_MEASURE_MODE_U: val = (signed char)img[y + uvx]; //U break; case MD_MEASURE_MODE_V: val = (signed char)img[y + uvx + 2]; //V break; case MD_MEASURE_MODE_R: cy = img[y + x + 1]; cv = (signed char)img[y + uvx + 2]; val = clip(((cy<<12) + cv*5743 + 2048)>>12); // R break; case MD_MEASURE_MODE_G: cy = img[y + x + 1]; cu = (signed char)img[y + uvx]; cv = (signed char)img[y + uvx + 2]; val = clip(((cy<<12) - cu*1411 - cv*2925 + 2048)>>12); // G break; case MD_MEASURE_MODE_B: cy = img[y + x + 1]; cu = (signed char)img[y + uvx]; val = clip(((cy<<12) + cu*7258 + 2048)>>12); // B break; default: val = 0; // Stop compiler warning break; } } curr += val; points++; } } motion_detector.points = points ; diff = (curr - motion_detector.prev[idx]) / points; if (diff < 0) diff = -diff; if ((diff > motion_detector.threshold) && (motion_detector.start_time+motion_detector.msecs_before_trigger < tick)) { motion_detector.detected_cells++; } } motion_detector.diff[idx] = diff; motion_detector.prev[idx] = curr; } }