root/modules/motion_detector.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. time_counter_capture
  2. action_stack_AS_MOTION_DETECTOR
  3. md_kbd_sched_immediate_shoot
  4. clip
  5. md_close_motion_detector
  6. md_save_calls_history
  7. mx_dump_memory
  8. md_running
  9. md_detect_motion
  10. md_detect_motion
  11. md_get_cell_val
  12. md_get_cell_diff
  13. md_draw_grid
  14. _module_unloader
  15. _module_can_unload

   1 /*
   2 
   3 Motion detection module
   4 
   5 Author: mx3 (Max Sagaydachny) . win1251 ( Максим Сагайдачный )
   6 Email: win.drivers@gmail.com
   7 Skype: max_dtc
   8 ICQ#: 125-985-663
   9 Country: Ukraine
  10 Sity: Kharkiv
  11 
  12 20070912 mx3: first version
  13 
  14 20070918 mx3: speed optimization,
  15 
  16 20101201 CHDKLover: speed optimization
  17 
  18 20160710 62ndidiot: prelim digic 6 mods for test
  19                     need vid_get_viewport_byte_width() properly defined in lib.c to
  20                     override the non-digic 6 one in generic/wrappers.c
  21                     so correct width for 640x480 lcd in digic6 is 1280 bytes not 1080...
  22 20170207 62ndidiot: fix RGB calculation for Digic6
  23 
  24 */
  25 
  26 #ifdef OPT_MD_DEBUG
  27 #define MD_REC_CALLS_CNT 2048
  28 #define MD_INFO_BUF_SIZE 4096
  29 #endif
  30 
  31 #include "camera_info.h"
  32 #include "action_stack.h"
  33 #include "console.h"
  34 #include "keyboard.h"
  35 #include "clock.h"
  36 #include "viewport.h"
  37 #include "debug_led.h"
  38 #include "gui.h"
  39 #include "gui_draw.h"
  40 #include "script_api.h"
  41 #include "script.h"
  42 
  43 #include "motion_detector.h"
  44 #include "module_def.h"
  45 #include "gui_lang.h"
  46 // going to replace this with something more elegant
  47 #ifndef THUMB_FW
  48    int xs=6; //bytes per 4 pixel grouping
  49    int np=4;
  50 #else
  51    int xs=4; //yuv422
  52    int np=2;
  53 #endif
  54 // Forward references
  55 static int md_detect_motion(void);
  56 
  57 #define MD_XY2IDX(x,y) ((y)*motion_detector.columns+(x))
  58 
  59 enum
  60 {
  61     MD_MEASURE_MODE_U=0,
  62     MD_MEASURE_MODE_Y=1,
  63     MD_MEASURE_MODE_V=2,
  64     MD_MEASURE_MODE_R=3,
  65     MD_MEASURE_MODE_G=4,
  66     MD_MEASURE_MODE_B=5
  67 };
  68 
  69 // Bit values for motion_detector.parameters
  70 enum
  71 {
  72     MD_DO_IMMEDIATE_SHOOT=1,
  73     MD_MAKE_DEBUG_LOG_FILE=2,
  74     MD_MAKE_RAM_DUMP_FILE=4,
  75     MD_NO_SHUTTER_RELEASE_ON_SHOOT=8
  76 };
  77 
  78 enum
  79 {
  80     MD_REGION_NONE=0,
  81     MD_REGION_INCLUDE=1,
  82     MD_REGION_EXCLUDE=2
  83 };
  84 
  85 #define MOTION_DETECTOR_CELLS 1024
  86 
  87 struct motion_detector_s
  88 {
  89     int prev[MOTION_DETECTOR_CELLS];
  90     unsigned char diff[MOTION_DETECTOR_CELLS];
  91 
  92     int columns;
  93     int rows;
  94     int threshold;
  95     int pixel_measure_mode;
  96     int timeout;
  97     int measure_interval;
  98 
  99     int last_measure_time;
 100     int start_time;
 101 
 102     int running;
 103     int detected_cells;
 104 
 105     int draw_grid;
 106     int clipping_region_mode;
 107     int clipping_region_row1;
 108     int clipping_region_column1;
 109     int clipping_region_row2;
 110     int clipping_region_column2;
 111 
 112     int previous_picture_is_ready;
 113 
 114     int return_value;
 115     int parameters;
 116     int pixels_step;
 117     int msecs_before_trigger;
 118 
 119     int points ;
 120 
 121     // debug
 122 #ifdef OPT_MD_DEBUG
 123     int comp_calls_cnt;
 124     int comp_calls[MD_REC_CALLS_CNT];
 125 #endif
 126 };
 127 
 128 static struct motion_detector_s motion_detector;
 129 
 130 static void time_counter_capture(time_counter *t)
 131 {
 132     t->last = get_tick_count() - t->tick_count;
 133     if (t->last < t->min)
 134         t->min = t->last;
 135     if (t->last > t->max)
 136         t->max = t->last;
 137     t->sum += t->last;
 138     t->count++;
 139 }
 140 
 141 // Stack process function for running MD logic
 142 static int action_stack_AS_MOTION_DETECTOR()
 143 {
 144     // MD testing with AF LED
 145     if (camera_info.perf.md_af_tuning)
 146     {
 147         if (camera_info.perf.af_led_on == 0)
 148         {
 149             camera_info.perf.af_led_on--;
 150             camera_info.perf.af_led.tick_count = get_tick_count();
 151             camera_set_led(camera_info.cam_af_led,1,200);
 152         }
 153         else if (camera_info.perf.af_led_on > 0)
 154         {
 155             camera_info.perf.af_led_on--;
 156         }
 157     }
 158 
 159     if (md_detect_motion() == 0)
 160     {
 161         if (motion_detector.return_value)
 162         {
 163             camera_info.perf.md_detect_tick = get_tick_count();
 164         }
 165 
 166         // MD testing with AF LED
 167         if (camera_info.perf.md_af_tuning)
 168         {
 169             camera_set_led(camera_info.cam_af_led,0,0);
 170             if (motion_detector.return_value)
 171             {
 172                 time_counter_capture(&camera_info.perf.af_led);
 173             }
 174         }
 175 
 176         // We need to recover the motion detector's
 177         // result and push it onto the thread's stack.
 178         libscriptapi->set_as_ret(motion_detector.return_value);
 179 
 180         action_pop_func(0);
 181         return 1;
 182     }
 183     return 0;
 184 }
 185 
 186 static void md_kbd_sched_immediate_shoot(int no_release)
 187 {
 188     action_pop_func(0);// REMOVE MD ITEM
 189 
 190     // stack operations are reversed!
 191     if (!no_release)  // only release shutter if allowed
 192     {
 193         action_push_release(KEY_SHOOT_FULL);
 194     }
 195     if (camera_info.cam_key_press_delay > 0)
 196         action_push_delay(camera_info.cam_key_press_delay);
 197     action_push_func(action_stack_AS_MOTION_DETECTOR); // it will removed right after exit from this function
 198     kbd_key_press(KEY_SHOOT_FULL); // not a stack operation... pressing right now
 199 
 200     // MD testing with AF LED
 201     if (camera_info.perf.md_af_tuning)
 202     {
 203         camera_info.perf.md_af_on_flag = 1;
 204     }
 205 }
 206 
 207 static int clip(int v)
 208 {
 209     if (v<0) v=0;
 210     else if (v>255) v=255;
 211     return v;
 212 }
 213 
 214 // TODO add script interface, currently done when script ends
 215 void md_close_motion_detector()
 216 {
 217 }
 218 
 219 int md_init_motion_detector
 220 (
 221  int columns,
 222  int rows,
 223  int pixel_measure_mode,
 224  int detection_timeout,
 225  int measure_interval,
 226  int threshold,
 227  int draw_grid,
 228  int clipping_region_mode,
 229  int clipping_region_column1,
 230  int clipping_region_row1,
 231  int clipping_region_column2,
 232  int clipping_region_row2,
 233  int parameters,
 234  int pixels_step,
 235  int msecs_before_trigger
 236 )
 237 {
 238 #ifdef OPT_MD_DEBUG
 239     motion_detector.comp_calls_cnt=0;
 240 #endif
 241 
 242     if(     pixel_measure_mode != MD_MEASURE_MODE_Y
 243         &&  pixel_measure_mode != MD_MEASURE_MODE_U
 244         &&  pixel_measure_mode != MD_MEASURE_MODE_V
 245         &&  pixel_measure_mode != MD_MEASURE_MODE_R
 246         &&  pixel_measure_mode != MD_MEASURE_MODE_G
 247         &&  pixel_measure_mode != MD_MEASURE_MODE_B
 248         )
 249     {
 250         pixel_measure_mode = MD_MEASURE_MODE_Y;
 251     }
 252 
 253     // Sanity check on grid size
 254     if (columns < 1) columns = 3;
 255     if (rows < 1) rows = 3;
 256     // If too many grid cells, reduce larger of columns and rows until it fits
 257     while ((columns * rows) > MOTION_DETECTOR_CELLS)
 258     {
 259         if (columns > rows) columns--;
 260         else rows--;
 261     }
 262 
 263     if(msecs_before_trigger<0)
 264     {
 265         msecs_before_trigger=0;
 266     }
 267 
 268     if (pixels_step<1)
 269     {
 270         pixels_step=1;
 271     }
 272 
 273     if(detection_timeout<0)
 274     {
 275         detection_timeout=0;
 276     }
 277 
 278     if(measure_interval<0)
 279     {
 280         measure_interval=0;
 281     }
 282 
 283     if(threshold<0)
 284     {
 285         threshold=0;
 286     }
 287 
 288     motion_detector.msecs_before_trigger = msecs_before_trigger;
 289     motion_detector.parameters = parameters;
 290     motion_detector.pixels_step = pixels_step;
 291     motion_detector.columns = columns;
 292     motion_detector.rows = rows;
 293     motion_detector.return_value = 0;
 294 
 295     motion_detector.pixel_measure_mode = pixel_measure_mode;
 296     motion_detector.timeout = detection_timeout;
 297     motion_detector.measure_interval = measure_interval;
 298     motion_detector.threshold = threshold;
 299     motion_detector.draw_grid = draw_grid;
 300 
 301     if (clipping_region_column1>clipping_region_column2)
 302     {
 303         motion_detector.clipping_region_column2 = clipping_region_column1;
 304         motion_detector.clipping_region_column1 = clipping_region_column2;
 305     }
 306     else
 307     {
 308         motion_detector.clipping_region_column2 = clipping_region_column2;
 309         motion_detector.clipping_region_column1 = clipping_region_column1;
 310     }
 311 
 312     if (clipping_region_row1>clipping_region_row2)
 313     {
 314         motion_detector.clipping_region_row2 = clipping_region_row1;
 315         motion_detector.clipping_region_row1 = clipping_region_row2;
 316     }
 317     else
 318     {
 319         motion_detector.clipping_region_row2 = clipping_region_row2;
 320         motion_detector.clipping_region_row1 = clipping_region_row1;
 321     }
 322 
 323     if (clipping_region_mode!=MD_REGION_NONE && clipping_region_mode!=MD_REGION_INCLUDE && clipping_region_mode!=MD_REGION_EXCLUDE)
 324     {
 325         clipping_region_mode=MD_REGION_NONE;
 326     }
 327     motion_detector.clipping_region_mode = clipping_region_mode;
 328 
 329     motion_detector.detected_cells = 0;
 330     motion_detector.previous_picture_is_ready = 0;
 331     motion_detector.start_time=get_tick_count();
 332 
 333     motion_detector.last_measure_time = motion_detector.start_time - motion_detector.measure_interval;
 334 
 335     motion_detector.running = 1;
 336 
 337     camera_info.perf.af_led_on = 100;
 338     action_push_func(action_stack_AS_MOTION_DETECTOR);
 339     gui_set_need_restore();
 340 
 341     return 1;
 342 }
 343 
 344 #ifdef OPT_MD_DEBUG
 345 static void md_save_calls_history(){
 346     char buf[200], fn[30];
 347     char big[MD_INFO_BUF_SIZE];
 348     int big_ln;
 349     int calls,i, ln, fd;
 350     static struct utimbuf t;
 351     static struct tm *ttm;
 352 
 353 
 354     if( (motion_detector.parameters & MD_MAKE_DEBUG_LOG_FILE) == 0 ){
 355         return;
 356     }
 357 
 358 
 359     strcpy(fn,"A/MD_INFO.TXT");//,BUILD_NUMBER,motion_detector.pixels_step);
 360     fd = open(fn, O_WRONLY|O_CREAT, 0777);
 361     if( fd>=0) {
 362         console_add_line("Writing info file...");
 363         lseek(fd,0,SEEK_END);
 364             ttm = get_localtime();
 365         big_ln=sprintf(big,
 366                                 "\r\n--- %04u-%02u-%02u  %02u:%02u:%02u\r\n"
 367                                 "CHDK Ver: %s [ #%s ]\r\nBuild Date: %s %s\r\nCamera:  %s [ %s ]\r\n"
 368                                 "[%dx%d], threshold: %d, interval: %d, pixels step: %d\r\n"
 369                                 "region: [%d,%d-%d,%d], region type: %d\r\n"
 370                                 "wait interval: %d, parameters: %d, calls: %d, detected cells: %d\r\n",
 371                                 1900+ttm->tm_year, ttm->tm_mon+1, ttm->tm_mday, ttm->tm_hour, ttm->tm_min, ttm->tm_sec,
 372                                 camera_info.chdk_ver, camera_info.build_number, camera_info.build_date, camera_info.build_time, camera_info.platform, camera_info.platformsub,
 373                                 motion_detector.columns, motion_detector.rows, motion_detector.threshold, motion_detector.measure_interval, motion_detector.pixels_step,
 374                                 motion_detector.clipping_region_column1, motion_detector.clipping_region_row1, motion_detector.clipping_region_column2, motion_detector.clipping_region_row2, motion_detector.clipping_region_mode,
 375                                 motion_detector.msecs_before_trigger, motion_detector.parameters, motion_detector.comp_calls_cnt,
 376                                 motion_detector.detected_cells
 377                 );
 378 
 379         calls = ( motion_detector.comp_calls_cnt < MD_REC_CALLS_CNT) ?motion_detector.comp_calls_cnt: MD_REC_CALLS_CNT;
 380 
 381         for(i=0;i<calls;i++){
 382             ln=sprintf(buf,"[%d] - %d\r\n",i,motion_detector.comp_calls[i]);
 383             if(big_ln+ln>MD_INFO_BUF_SIZE){
 384           write(fd,big,big_ln);
 385                 big_ln=0;
 386             }
 387             memcpy(big+big_ln,buf,ln+1);
 388             big_ln+=ln;
 389         }
 390     write(fd,big,big_ln);
 391         close(fd);
 392       t.actime = t.modtime = time(NULL);
 393     utime(fn, &t);
 394     }
 395 }
 396 
 397 static void mx_dump_memory(void *img){
 398     char fn[36];
 399     int fd, i;
 400     static int cnt=0;
 401 
 402     started();
 403     mkdir("A/MD");
 404 
 405         do {
 406             cnt++;
 407             sprintf(fn, "A/MD/%04d.FB", cnt);
 408             fd = open(fn, O_RDONLY, 0777);
 409 
 410             if(fd>=0){
 411                 close(fd);
 412             }
 413         } while(fd>=0);
 414 
 415 
 416                 sprintf(fn, "A/MD/%04d.FB", cnt );
 417                 fd = open(fn, O_WRONLY|O_CREAT, 0777);
 418                 if (fd>=0) {
 419             write(fd, img, camera_screen.width*vid_get_viewport_height()*xs/np);
 420             close(fd);
 421                 }
 422   vid_bitmap_refresh();
 423   finished();
 424 
 425 }
 426 #else
 427 #define md_save_calls_history()
 428 #define mx_dump_memory(x)
 429 #endif
 430 
 431 
 432 static int md_running()
 433 {
 434         return motion_detector.running;
 435 }
 436 
 437 
 438 #ifndef THUMB_FW
 439 // pre-digic 6 implementation
 440 // much duplication, be sure to update else case if logic is changed!
 441 static int md_detect_motion(void)
 442 {
 443     int idx, tick, rv;
 444     int val, cy, cv, cu;
 445 
 446     register int col, row, x, y;
 447 
 448     if(!md_running())
 449     {
 450         return 0;
 451     }
 452 
 453     tick = get_tick_count();
 454     rv = 1;
 455 
 456 #ifdef OPT_MD_DEBUG
 457     if(motion_detector.comp_calls_cnt < MD_REC_CALLS_CNT)
 458     {
 459         motion_detector.comp_calls[motion_detector.comp_calls_cnt]=tick;
 460     }
 461     motion_detector.comp_calls_cnt++;
 462 #endif
 463 
 464     if(motion_detector.start_time + motion_detector.timeout < tick )
 465     {
 466         md_save_calls_history();
 467         motion_detector.running = 0;
 468         return 0;
 469     }
 470 
 471     if(motion_detector.last_measure_time + motion_detector.measure_interval > tick)
 472     {
 473         // wait for the next time
 474         return 1;
 475     }
 476 
 477     motion_detector.last_measure_time = tick;
 478 
 479     unsigned char* img = vid_get_viewport_active_buffer();
 480     if (!img) return 0;
 481 
 482 #ifdef OPT_MD_DEBUG
 483     if(motion_detector.comp_calls_cnt==50 && (motion_detector.parameters & MD_MAKE_RAM_DUMP_FILE) != 0 )
 484     {
 485         mx_dump_memory((char*)img);
 486     }
 487 #endif
 488 
 489     motion_detector.detected_cells = 0;
 490 
 491     img += vid_get_viewport_image_offset();             // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
 492 
 493         int vp_h = vid_get_viewport_height();
 494     int vp_w = vid_get_viewport_width();
 495         int vp_bw = vid_get_viewport_byte_width() * vid_get_viewport_yscale();
 496 
 497         int x_step = motion_detector.pixels_step * 3;
 498         int y_step = motion_detector.pixels_step * vp_bw;
 499 
 500     for (idx=0, row=0; row < motion_detector.rows; row++)
 501     {
 502         // Calc img y start and end offsets (use same height for all cells so 'points' is consistent)
 503         int y_start = ((row * vp_h) / motion_detector.rows) * vp_bw;
 504         int y_end = y_start + ((vp_h / motion_detector.rows) * vp_bw);
 505 
 506         for (col=0; col < motion_detector.columns; col++, idx++)
 507         {
 508             int in_clipping_region=0;
 509 
 510             if (col+1 >= motion_detector.clipping_region_column1 &&
 511                 col+1 <= motion_detector.clipping_region_column2 &&
 512                 row+1 >= motion_detector.clipping_region_row1 &&
 513                 row+1 <= motion_detector.clipping_region_row2)
 514             {
 515                 in_clipping_region=1;
 516             }
 517 
 518             int curr = 0;
 519             int diff = 0;
 520 
 521             if (
 522                 (motion_detector.clipping_region_mode==MD_REGION_NONE) ||
 523                 (motion_detector.clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0) ||
 524                 (motion_detector.clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1)
 525                )
 526             {
 527                 // Calc img x start and end offsets (use same width for all cells so 'points' is consistent)
 528                 int x_start = ((col * vp_w) / motion_detector.columns) * 3;
 529                 int x_end = x_start + ((vp_w / motion_detector.columns) * 3);
 530 
 531                 int points = 0;
 532 
 533                 for (y=y_start; y<y_end; y+=y_step)
 534                 {
 535                     for (x=x_start; x<x_end; x+=x_step)
 536                     {
 537                         // ARRAY of UYVYYY values
 538                         // 6 bytes - 4 pixels
 539 
 540                         if (motion_detector.pixel_measure_mode == MD_MEASURE_MODE_Y)
 541                         {
 542                             val = img[y + x + 1];                                                       //Y
 543                         }
 544                         else
 545                         {
 546                             // Calc offset to UYV component
 547                             int uvx = x;
 548                             if (uvx & 1) uvx -= 3;
 549 
 550                             switch(motion_detector.pixel_measure_mode)
 551                             {
 552                             case MD_MEASURE_MODE_U:
 553                                 val = (signed char)img[y + uvx];                                //U
 554                                 break;
 555 
 556                             case MD_MEASURE_MODE_V:
 557                                 val = (signed char)img[y + uvx + 2];                    //V
 558                                 break;
 559 
 560                             case MD_MEASURE_MODE_R:
 561                                 cy = img[y + x + 1];
 562                                 cv = (signed char)img[y + uvx + 2];
 563                                 val = clip(((cy<<12)           + cv*5743 + 2048)>>12); // R
 564                                 break;
 565 
 566                             case MD_MEASURE_MODE_G:
 567                                 cy = img[y + x + 1];
 568                                 cu = (signed char)img[y + uvx];
 569                                 cv = (signed char)img[y + uvx + 2];
 570                                 val = clip(((cy<<12) - cu*1411 - cv*2925 + 2048)>>12); // G
 571                                 break;
 572 
 573                             case MD_MEASURE_MODE_B:
 574                                 cy = img[y + x + 1];
 575                                 cu = (signed char)img[y + uvx];
 576                                 val = clip(((cy<<12) + cu*7258           + 2048)>>12); // B
 577                                 break;
 578 
 579                             default:
 580                                 val = 0;    // Stop compiler warning
 581                                 break;
 582                             }
 583                         }
 584 
 585                         curr += val;
 586                         points++;
 587                     }
 588                 }
 589                 motion_detector.points = points ;
 590                 diff = (curr - motion_detector.prev[idx]) / points;
 591                 if (diff < 0) diff = -diff;
 592                 if ((diff > motion_detector.threshold) &&
 593                     (motion_detector.start_time+motion_detector.msecs_before_trigger < tick))
 594                 {
 595                     motion_detector.detected_cells++;
 596                 }
 597             }
 598 
 599             motion_detector.diff[idx] = diff;
 600             motion_detector.prev[idx] = curr;
 601         }
 602     }
 603 
 604     if (motion_detector.previous_picture_is_ready == 0)
 605     {
 606         motion_detector.previous_picture_is_ready = 1;
 607         motion_detector.start_time = get_tick_count();
 608         motion_detector.last_measure_time = motion_detector.start_time - motion_detector.measure_interval;
 609     }
 610     else if ( motion_detector.detected_cells > 0 )
 611     {
 612         if (motion_detector.start_time+motion_detector.msecs_before_trigger < tick)
 613         {
 614             motion_detector.running=0;
 615             motion_detector.return_value = motion_detector.detected_cells;
 616 
 617             if ((motion_detector.parameters&MD_DO_IMMEDIATE_SHOOT) != 0)
 618             {
 619                 //make shoot
 620                 md_kbd_sched_immediate_shoot(motion_detector.parameters&MD_NO_SHUTTER_RELEASE_ON_SHOOT);
 621             }
 622             rv = 0;
 623         }
 624     }
 625 
 626     return rv;
 627 }
 628 
 629 #else // ndef THUMB_FW
 630 // DIGIC 6
 631 static int md_detect_motion(void)
 632 {
 633     int idx, tick, rv;
 634     int val, cy, cv, cu;
 635 
 636     register int col, row, x, y;
 637 
 638     if(!md_running())
 639     {
 640         return 0;
 641     }
 642 
 643     tick = get_tick_count();
 644     rv = 1;
 645 
 646 #ifdef OPT_MD_DEBUG
 647     if(motion_detector.comp_calls_cnt < MD_REC_CALLS_CNT)
 648     {
 649         motion_detector.comp_calls[motion_detector.comp_calls_cnt]=tick;
 650     }
 651     motion_detector.comp_calls_cnt++;
 652 #endif
 653 
 654     if(motion_detector.start_time + motion_detector.timeout < tick )
 655     {
 656         md_save_calls_history();
 657         motion_detector.running = 0;
 658         return 0;
 659     }
 660 
 661     if(motion_detector.last_measure_time + motion_detector.measure_interval > tick)
 662     {
 663         // wait for the next time
 664         return 1;
 665     }
 666 
 667     motion_detector.last_measure_time = tick;
 668 
 669     unsigned char* img = vid_get_viewport_active_buffer();
 670     if (!img) return 0;
 671 
 672 #ifdef OPT_MD_DEBUG
 673     if(motion_detector.comp_calls_cnt==50 && (motion_detector.parameters & MD_MAKE_RAM_DUMP_FILE) != 0 )
 674     {
 675         mx_dump_memory((char*)img);
 676     }
 677 #endif
 678 
 679     motion_detector.detected_cells = 0;
 680 
 681     img += vid_get_viewport_image_offset();             // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
 682 
 683     int vp_h = vid_get_viewport_height();
 684     int vp_w = vid_get_viewport_width();
 685 
 686     int vp_bw = vid_get_viewport_byte_width();
 687     int x_step = motion_detector.pixels_step * 2; // so actually pixels-step = 1 will
 688                                //give a step of 2 bytes, no pixels will be skipped
 689     if (( (motion_detector.pixel_measure_mode == MD_MEASURE_MODE_U) ||
 690          (motion_detector.pixel_measure_mode == MD_MEASURE_MODE_V) ) && (x_step < 4) ){
 691        x_step =  4; //uv is sampled every 4 bytes in X, prevent double counting
 692     }
 693 
 694         int y_step = motion_detector.pixels_step * vp_bw;
 695 
 696     for (idx=0, row=0; row < motion_detector.rows; row++)
 697     {
 698         // Calc img y start and end offsets (use same height for all cells so 'points' is consistent)
 699         int y_start = ((row * vp_h) / motion_detector.rows) * vp_bw;
 700         int y_end = y_start + ((vp_h / motion_detector.rows) * vp_bw);
 701 
 702         for (col=0; col < motion_detector.columns; col++, idx++)
 703         {
 704             int in_clipping_region=0;
 705 
 706             if (col+1 >= motion_detector.clipping_region_column1 &&
 707                 col+1 <= motion_detector.clipping_region_column2 &&
 708                 row+1 >= motion_detector.clipping_region_row1 &&
 709                 row+1 <= motion_detector.clipping_region_row2)
 710             {
 711                 in_clipping_region=1;
 712             }
 713 
 714             int curr = 0;
 715             int diff = 0;
 716 
 717             if (
 718                 (motion_detector.clipping_region_mode==MD_REGION_NONE) ||
 719                 (motion_detector.clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0) ||
 720                 (motion_detector.clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1)
 721                )
 722             {
 723                 // Calc img x start and end offsets (use same width for all cells so 'points' is consistent)
 724 //                int x_start = ((col * vp_bw) / motion_detector.columns); //first byte of col
 725                 int x_start = ((col * vp_w * 2) / motion_detector.columns); //first byte of col
 726 //                int x_end = x_start + ((vp_bw / motion_detector.columns)); //last byte
 727                 int x_end = x_start + ((vp_w * 2 / motion_detector.columns)); //last byte
 728 // ensure x_start  is a multiple of xs (so either UY, or VY in uyvy scheme)
 729 // this isn't done in the old code, so I think selecting a number of columns like say 7
 730 // can result in bad alignment
 731 // eg xstart = 111, xstart % xs = 1 (for xs = 2)
 732                 x_start  +=    x_start % xs;
 733                 int points = 0;
 734 
 735                 for (y=y_start; y<y_end; y+=y_step)
 736                 {
 737                     for (x=x_start; x<x_end; x+=x_step)
 738                     {
 739                        if (x_start + xs >= x_end) { break;}
 740                         // ARRAY of UYVYYY values or UYVY
 741                         // 6 bytes - 4 pixels       4 bytes - 2 pixels
 742 
 743                         if (motion_detector.pixel_measure_mode == MD_MEASURE_MODE_Y)
 744                         {
 745                             val = img[y + x + 1];  //Y (first Y only of group)
 746                         }
 747                         else
 748                         {
 749                             // Calc offset to UYV component
 750                             int uvx = x;
 751 // check move backwards to find u value if necessary
 752 // eg x=111 x%4 = 3 uvx=108
 753 // actually this will always be zero or 2
 754 //e.g. component U   Y   V   Y
 755 //     byte #   108 109 110 111
 756                            uvx -= x % 4;
 757                            unsigned int ibuf = *(unsigned int*)(&img[(y+uvx)&0xfffffffc]);
 758                            cu =(signed char)((ibuf&0xff)-128);
 759                            cv =(signed char)(((ibuf>>16)&0xff)-128);
 760                            cy = (unsigned char)((ibuf>>8)&0xff);
 761 
 762                             switch(motion_detector.pixel_measure_mode)
 763                             {
 764                             case MD_MEASURE_MODE_U:
 765                                 val = cu; //U
 766                                 break;
 767 
 768                             case MD_MEASURE_MODE_V:
 769                                 val = cv; //V
 770                                 break;
 771 
 772                             case MD_MEASURE_MODE_R:
 773 
 774                                 val = clip(((cy<<12)           + cv*5743 + 2048)>>12); // R
 775                                 break;
 776 
 777                             case MD_MEASURE_MODE_G:
 778 
 779                                 val = clip(((cy<<12) - cu*1411 - cv*2925 + 2048)>>12); // G
 780                                 break;
 781 
 782                             case MD_MEASURE_MODE_B:
 783 
 784                                 val = clip(((cy<<12) + cu*7258           + 2048)>>12); // B
 785                                 break;
 786 
 787                             default:
 788                                 val = 0;    // Stop compiler warning
 789                                 break;
 790                             }
 791                         }
 792 
 793                         curr += val;
 794                         points++;
 795                     }
 796                 }
 797                 motion_detector.points = points ;
 798                 diff = (curr - motion_detector.prev[idx]) / points;
 799                 if (diff < 0) diff = -diff;
 800                 if ((diff > motion_detector.threshold) &&
 801                     (motion_detector.start_time+motion_detector.msecs_before_trigger < tick))
 802                 {
 803                     motion_detector.detected_cells++;
 804                 }
 805             }
 806 
 807             motion_detector.diff[idx] = diff;
 808             motion_detector.prev[idx] = curr;
 809         }
 810     }
 811 
 812     if (motion_detector.previous_picture_is_ready == 0)
 813     {
 814         motion_detector.previous_picture_is_ready = 1;
 815         motion_detector.start_time = get_tick_count();
 816         motion_detector.last_measure_time = motion_detector.start_time - motion_detector.measure_interval;
 817     }
 818     else if ( motion_detector.detected_cells > 0 )
 819     {
 820         if (motion_detector.start_time+motion_detector.msecs_before_trigger < tick)
 821         {
 822             motion_detector.running=0;
 823             motion_detector.return_value = motion_detector.detected_cells;
 824 
 825             if ((motion_detector.parameters&MD_DO_IMMEDIATE_SHOOT) != 0)
 826             {
 827                 //make shoot
 828                 md_kbd_sched_immediate_shoot(motion_detector.parameters&MD_NO_SHUTTER_RELEASE_ON_SHOOT);
 829             }
 830             rv = 0;
 831         }
 832     }
 833 
 834     return rv;
 835 }
 836 #endif
 837 
 838 int md_get_cell_val(int column, int row)
 839 {
 840     if ((column<1 || column > motion_detector.columns) ||
 841         (row<1 || row > motion_detector.rows))
 842     {
 843         return 0;
 844     }
 845 
 846     return motion_detector.prev[ MD_XY2IDX(column-1,row-1) ]/motion_detector.points ;
 847 }
 848 
 849 int md_get_cell_diff(int column, int row)
 850 {
 851     if ((column<1 || column > motion_detector.columns) ||
 852         (row<1 || row > motion_detector.rows))
 853     {
 854         return 0;
 855     }
 856 
 857     return motion_detector.diff[ MD_XY2IDX(column-1,row-1) ];
 858 }
 859 
 860 void md_draw_grid()
 861 {
 862     int col, row;
 863     int i;
 864     char mdbuff[8];
 865 
 866     if (!md_running() || motion_detector.draw_grid==0 || camera_info.state.state_kbd_script_run==0)
 867     {
 868         return;
 869         }
 870 
 871         int xoffset = vid_get_viewport_display_xoffset();       // used when image size != viewport size
 872         int yoffset = vid_get_viewport_display_yoffset();       // used when image size != viewport size
 873 
 874     // display area size
 875         int x_size = camera_screen.width-xoffset * 2;
 876         int y_size = camera_screen.height-yoffset * 2;
 877 
 878     // initial display offsets
 879     int y_start, y_end = yoffset;
 880     int x_start, x_end;
 881 
 882     for (i=0, row=0; row < motion_detector.rows && camera_info.state.state_kbd_script_run; row++)
 883     {
 884         // Calc display start and end offsets
 885         y_start = y_end;    // reuse last end value as new start value
 886         y_end = yoffset + ((row + 1) * y_size) / motion_detector.rows;
 887 
 888         x_end = xoffset;
 889 
 890         for (col=0; col < motion_detector.columns; col++, i++)
 891         {
 892             // Calc display x start and end offsets
 893             x_start = x_end;    // reuse last end value as new start value
 894             x_end = xoffset + ((col + 1) * x_size) / motion_detector.columns;
 895 
 896             int in_clipping_region = 0;
 897             if ( col+1>=motion_detector.clipping_region_column1
 898                 && col+1<=motion_detector.clipping_region_column2
 899                 && row+1>=motion_detector.clipping_region_row1
 900                 && row+1<=motion_detector.clipping_region_row2
 901                 )
 902             {
 903                 in_clipping_region = 1;
 904             }
 905 
 906             if ((motion_detector.clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0) ||
 907                 (motion_detector.clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1) ||
 908                 (motion_detector.clipping_region_mode==MD_REGION_NONE))
 909             {
 910                 int diff = motion_detector.diff[i];
 911 
 912                 twoColors c = MAKE_COLOR(COLOR_TRANSPARENT, COLOR_GREEN);
 913                 if (diff > motion_detector.threshold)
 914                 {
 915                     c = MAKE_COLOR(COLOR_TRANSPARENT, COLOR_RED);
 916                 }
 917 
 918                 if (motion_detector.draw_grid & 2)
 919                 {
 920                     sprintf(mdbuff,"%-3d", diff);
 921                     draw_string(x_start+4, y_start+2, mdbuff, c);
 922                 }
 923 
 924                 if (motion_detector.draw_grid & 1)
 925                 {
 926                     draw_rectangle(x_start+2, y_start+2, x_end-2, y_end-2, c, RECT_BORDER1);
 927                 }
 928             }
 929         }
 930     }
 931 }
 932 
 933 
 934 // =========  MODULE INIT =================
 935 
 936 /***************** BEGIN OF AUXILARY PART *********************
 937 ATTENTION: DO NOT REMOVE OR CHANGE SIGNATURES IN THIS SECTION
 938 **************************************************************/
 939 
 940 //---------------------------------------------------------
 941 // PURPOSE: Finalize module operations (close allocs, etc)
 942 // RETURN VALUE: 0-ok, 1-fail
 943 //---------------------------------------------------------
 944 int _module_unloader()
 945 {
 946     md_close_motion_detector();
 947     return 0;
 948 }
 949 
 950 int _module_can_unload()
 951 {
 952     return camera_info.state.state_kbd_script_run == SCRIPT_STATE_INACTIVE;
 953 }
 954 
 955 /******************** Module Information structure ******************/
 956 
 957 libmotiondetect_sym _libmotiondetect =
 958 {
 959     {
 960          0, _module_unloader, _module_can_unload, 0, 0
 961     },
 962 
 963     md_close_motion_detector,
 964     md_init_motion_detector,
 965     md_get_cell_diff,
 966     md_draw_grid,
 967     md_get_cell_val,
 968 };
 969 
 970 ModuleInfo _module_info =
 971 {
 972     MODULEINFO_V1_MAGICNUM,
 973     sizeof(ModuleInfo),
 974     MOTION_DETECTOR_VERSION,    // Module version
 975 
 976     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,                       // Requirements of CHDK version
 977     ANY_PLATFORM_ALLOWED,               // Specify platform dependency
 978 
 979     -LANG_MODULE_MOTION_DETECT, // Module name
 980     MTYPE_EXTENSION,
 981 
 982     &_libmotiondetect.base,
 983 
 984     ANY_VERSION,                // CONF version
 985     CAM_SCREEN_VERSION,         // CAM SCREEN version
 986     ANY_VERSION,                // CAM SENSOR version
 987     CAM_INFO_VERSION,           // CAM INFO version
 988 };
 989 
 990 /*************** END OF AUXILARY PART *******************/

/* [<][>][^][v][top][bottom][index][help] */