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_measure_y
  10. md_measure_u
  11. md_measure_v
  12. md_measure_r
  13. md_measure_g
  14. md_measure_b
  15. md_detect_motion
  16. md_get_cell_val
  17. md_get_cell_diff
  18. md_draw_grid
  19. _module_unloader
  20. _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 
  47 // Forward references
  48 static int md_detect_motion(void);
  49 
  50 #define MD_XY2IDX(x,y) ((y)*motion_detector.columns+(x))
  51 
  52 enum
  53 {
  54     MD_MEASURE_MODE_U=0,
  55     MD_MEASURE_MODE_Y=1,
  56     MD_MEASURE_MODE_V=2,
  57     MD_MEASURE_MODE_R=3,
  58     MD_MEASURE_MODE_G=4,
  59     MD_MEASURE_MODE_B=5
  60 };
  61 
  62 // Bit values for motion_detector.parameters
  63 enum
  64 {
  65     MD_DO_IMMEDIATE_SHOOT=1,
  66     MD_MAKE_DEBUG_LOG_FILE=2,
  67     MD_MAKE_RAM_DUMP_FILE=4,
  68     MD_NO_SHUTTER_RELEASE_ON_SHOOT=8
  69 };
  70 
  71 enum
  72 {
  73     MD_REGION_NONE=0,
  74     MD_REGION_INCLUDE=1,
  75     MD_REGION_EXCLUDE=2
  76 };
  77 
  78 #define MOTION_DETECTOR_CELLS 1024
  79 
  80 struct motion_detector_s
  81 {
  82     int prev[MOTION_DETECTOR_CELLS];
  83     unsigned char diff[MOTION_DETECTOR_CELLS];
  84 
  85     int columns;
  86     int rows;
  87     int threshold;
  88     int pixel_measure_mode;
  89     int timeout;
  90     int measure_interval;
  91 
  92     int last_measure_time;
  93     int start_time;
  94 
  95     int running;
  96     int detected_cells;
  97 
  98     int draw_grid;
  99     int clipping_region_mode;
 100     int clipping_region_row1;
 101     int clipping_region_column1;
 102     int clipping_region_row2;
 103     int clipping_region_column2;
 104 
 105     int previous_picture_is_ready;
 106 
 107     int return_value;
 108     int parameters;
 109     int pixels_step;
 110     int msecs_before_trigger;
 111 
 112     int points;
 113 
 114     // debug
 115 #ifdef OPT_MD_DEBUG
 116     int comp_calls_cnt;
 117     int comp_calls[MD_REC_CALLS_CNT];
 118 #endif
 119 };
 120 
 121 static struct motion_detector_s motion_detector;
 122 
 123 static void time_counter_capture(time_counter *t)
 124 {
 125     t->last = get_tick_count() - t->tick_count;
 126     if (t->last < t->min)
 127         t->min = t->last;
 128     if (t->last > t->max)
 129         t->max = t->last;
 130     t->sum += t->last;
 131     t->count++;
 132 }
 133 
 134 // Stack process function for running MD logic
 135 static int action_stack_AS_MOTION_DETECTOR()
 136 {
 137     // MD testing with AF LED
 138     if (camera_info.perf.md_af_tuning)
 139     {
 140         if (camera_info.perf.af_led_on == 0)
 141         {
 142             camera_info.perf.af_led_on--;
 143             camera_info.perf.af_led.tick_count = get_tick_count();
 144             camera_set_led(camera_info.cam_af_led,1,200);
 145         }
 146         else if (camera_info.perf.af_led_on > 0)
 147         {
 148             camera_info.perf.af_led_on--;
 149         }
 150     }
 151 
 152     if (md_detect_motion() == 0)
 153     {
 154         if (motion_detector.return_value)
 155         {
 156             camera_info.perf.md_detect_tick = get_tick_count();
 157         }
 158 
 159         // MD testing with AF LED
 160         if (camera_info.perf.md_af_tuning)
 161         {
 162             camera_set_led(camera_info.cam_af_led,0,0);
 163             if (motion_detector.return_value)
 164             {
 165                 time_counter_capture(&camera_info.perf.af_led);
 166             }
 167         }
 168 
 169         // We need to recover the motion detector's
 170         // result and push it onto the thread's stack.
 171         libscriptapi->set_as_ret(motion_detector.return_value);
 172 
 173         action_pop_func(0);
 174         return 1;
 175     }
 176     return 0;
 177 }
 178 
 179 static void md_kbd_sched_immediate_shoot(int no_release)
 180 {
 181     action_pop_func(0);// REMOVE MD ITEM
 182 
 183     // stack operations are reversed!
 184     if (!no_release)  // only release shutter if allowed
 185     {
 186         action_push_release(KEY_SHOOT_FULL);
 187     }
 188     if (camera_info.cam_key_press_delay > 0)
 189         action_push_delay(camera_info.cam_key_press_delay);
 190     action_push_func(action_stack_AS_MOTION_DETECTOR); // it will removed right after exit from this function
 191     kbd_key_press(KEY_SHOOT_FULL); // not a stack operation... pressing right now
 192 
 193     // MD testing with AF LED
 194     if (camera_info.perf.md_af_tuning)
 195     {
 196         camera_info.perf.md_af_on_flag = 1;
 197     }
 198 }
 199 
 200 static int clip(int v)
 201 {
 202     if (v<0) return 0;
 203     if (v>255) return 255;
 204     return v;
 205 }
 206 
 207 // TODO add script interface, currently done when script ends
 208 void md_close_motion_detector()
 209 {
 210 }
 211 
 212 int md_init_motion_detector
 213 (
 214  int columns,
 215  int rows,
 216  int pixel_measure_mode,
 217  int detection_timeout,
 218  int measure_interval,
 219  int threshold,
 220  int draw_grid,
 221  int clipping_region_mode,
 222  int clipping_region_column1,
 223  int clipping_region_row1,
 224  int clipping_region_column2,
 225  int clipping_region_row2,
 226  int parameters,
 227  int pixels_step,
 228  int msecs_before_trigger
 229 )
 230 {
 231 #ifdef OPT_MD_DEBUG
 232     motion_detector.comp_calls_cnt=0;
 233 #endif
 234 
 235     if(     pixel_measure_mode != MD_MEASURE_MODE_Y
 236         &&  pixel_measure_mode != MD_MEASURE_MODE_U
 237         &&  pixel_measure_mode != MD_MEASURE_MODE_V
 238         &&  pixel_measure_mode != MD_MEASURE_MODE_R
 239         &&  pixel_measure_mode != MD_MEASURE_MODE_G
 240         &&  pixel_measure_mode != MD_MEASURE_MODE_B
 241         )
 242     {
 243         pixel_measure_mode = MD_MEASURE_MODE_Y;
 244     }
 245 
 246     // Sanity check on grid size
 247     if (columns < 1) columns = 3;
 248     if (rows < 1) rows = 3;
 249     // If too many grid cells, reduce larger of columns and rows until it fits
 250     while ((columns * rows) > MOTION_DETECTOR_CELLS)
 251     {
 252         if (columns > rows) columns--;
 253         else rows--;
 254     }
 255 
 256     if(msecs_before_trigger<0)
 257     {
 258         msecs_before_trigger=0;
 259     }
 260 
 261     if (pixels_step<1)
 262     {
 263         pixels_step=1;
 264     }
 265 #ifdef THUMB_FW
 266     if (((pixel_measure_mode == MD_MEASURE_MODE_U) || (pixel_measure_mode == MD_MEASURE_MODE_V)) && (pixels_step < 2))
 267     {
 268         pixels_step = 2;    //uv is sampled every 4 bytes in X, prevent double counting
 269     }
 270 #endif
 271 
 272     if(detection_timeout<0)
 273     {
 274         detection_timeout=0;
 275     }
 276 
 277     if(measure_interval<0)
 278     {
 279         measure_interval=0;
 280     }
 281 
 282     if(threshold<0)
 283     {
 284         threshold=0;
 285     }
 286 
 287     motion_detector.msecs_before_trigger = msecs_before_trigger;
 288     motion_detector.parameters = parameters;
 289     motion_detector.pixels_step = pixels_step;
 290     motion_detector.columns = columns;
 291     motion_detector.rows = rows;
 292     motion_detector.return_value = 0;
 293 
 294     motion_detector.pixel_measure_mode = pixel_measure_mode;
 295     motion_detector.timeout = detection_timeout;
 296     motion_detector.measure_interval = measure_interval;
 297     motion_detector.threshold = threshold;
 298     motion_detector.draw_grid = draw_grid;
 299 
 300     if (clipping_region_column1>clipping_region_column2)
 301     {
 302         motion_detector.clipping_region_column2 = clipping_region_column1;
 303         motion_detector.clipping_region_column1 = clipping_region_column2;
 304     }
 305     else
 306     {
 307         motion_detector.clipping_region_column2 = clipping_region_column2;
 308         motion_detector.clipping_region_column1 = clipping_region_column1;
 309     }
 310 
 311     if (clipping_region_row1>clipping_region_row2)
 312     {
 313         motion_detector.clipping_region_row2 = clipping_region_row1;
 314         motion_detector.clipping_region_row1 = clipping_region_row2;
 315     }
 316     else
 317     {
 318         motion_detector.clipping_region_row2 = clipping_region_row2;
 319         motion_detector.clipping_region_row1 = clipping_region_row1;
 320     }
 321 
 322     if (clipping_region_mode!=MD_REGION_NONE && clipping_region_mode!=MD_REGION_INCLUDE && clipping_region_mode!=MD_REGION_EXCLUDE)
 323     {
 324         clipping_region_mode=MD_REGION_NONE;
 325     }
 326     motion_detector.clipping_region_mode = clipping_region_mode;
 327 
 328     motion_detector.detected_cells = 0;
 329     motion_detector.previous_picture_is_ready = 0;
 330     motion_detector.start_time=get_tick_count();
 331 
 332     motion_detector.last_measure_time = motion_detector.start_time - motion_detector.measure_interval;
 333 
 334     motion_detector.running = 1;
 335 
 336     camera_info.perf.af_led_on = 100;
 337     action_push_func(action_stack_AS_MOTION_DETECTOR);
 338     gui_set_need_restore();
 339 
 340     return 1;
 341 }
 342 
 343 #ifdef OPT_MD_DEBUG
 344 
 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 {
 399     char fn[36];
 400     int fd, i;
 401     static int cnt=0;
 402 
 403     started();
 404     mkdir("A/MD");
 405 
 406     do
 407     {
 408         cnt++;
 409         sprintf(fn, "A/MD/%04d.FB", cnt);
 410         fd = open(fn, O_RDONLY, 0777);
 411 
 412         if(fd>=0)
 413         {
 414             close(fd);
 415         }
 416     } while(fd>=0);
 417 
 418     sprintf(fn, "A/MD/%04d.FB", cnt );
 419     fd = open(fn, O_WRONLY|O_CREAT, 0777);
 420     if (fd>=0)
 421     {
 422         write(fd, img, vid_get_viewport_byte_width()*vid_get_viewport_height_proper());
 423         close(fd);
 424     }
 425     vid_bitmap_refresh();
 426     finished();
 427 }
 428 
 429 #else
 430 #define md_save_calls_history()
 431 #define mx_dump_memory(x)
 432 #endif
 433 
 434 
 435 static int md_running()
 436 {
 437     return motion_detector.running;
 438 }
 439 
 440 // Shared variable for the measure functions
 441 static unsigned char* img;
 442 static int x_start, x_end, x_step;
 443 static int y_start, y_end, y_step;
 444 
 445 // Pre Digic6:
 446 //      ARRAY of UYVYYY values
 447 //      6 bytes - 4 pixels
 448 // Digic6:
 449 //      ARRAY of UYVY values
 450 //      4 bytes - 2 pixels
 451 
 452 // Pre Digic6: U & V are signed char values (-128 - 127)
 453 //      R = Y + 1.402 * V + 0.5
 454 //      G = Y - 0.34414 * U - 0.71414 * V + 0.5
 455 //      B = Y + 1.772 * V + 0.5
 456 // Digi6: U & V are unsigned (0 - 255) subtract 128 to get signed value
 457 //      R = Y + 1.402 * (V-128) + 0.5
 458 //      G = Y - 0.34414 * (U-128) - 0.71414 * (V-128) + 0.5
 459 //      B = Y + 1.772 * (V-128) + 0.5
 460 
 461 // Functions for inner loops for each measure mode
 462 
 463 static int md_measure_y()
 464 {
 465     register int x, y;
 466     register int curr = 0;
 467 
 468     for (y=y_start; y<y_end; y+=y_step)
 469     {
 470         for (x=x_start; x<x_end; x+=x_step)
 471         {
 472             curr += img[y + x + 1];  //Y always 2nd byte in each block
 473         }
 474     }
 475 
 476     return curr;
 477 }
 478 
 479 static int md_measure_u()
 480 {
 481     register int x, y, uvx;
 482     register int curr = 0;
 483 
 484     for (y=y_start; y<y_end; y+=y_step)
 485     {
 486         for (x=x_start; x<x_end; x+=x_step)
 487         {
 488             // Calc offset to U & V components in uvx
 489 #ifdef THUMB_FW
 490             uvx = x & 0xFFFFFFFC;           // U is in 1st two bytes of each 4 byte block V is in 2nd two bytes
 491             curr += (int)img[y + uvx] - 128;    //U
 492 #else
 493             uvx = (x&1)?x-3:x;
 494             curr += (signed char)img[y + uvx];  //U
 495 #endif
 496         }
 497     }
 498 
 499     return curr;
 500 }
 501 
 502 static int md_measure_v()
 503 {
 504     register int x, y, uvx;
 505     register int curr = 0;
 506 
 507     for (y=y_start; y<y_end; y+=y_step)
 508     {
 509         for (x=x_start; x<x_end; x+=x_step)
 510         {
 511             // Calc offset to U & V components in uvx
 512 #ifdef THUMB_FW
 513             uvx = x & 0xFFFFFFFC;               // U is in 1st two bytes of each 4 byte block V is in 2nd two bytes
 514             curr += (int)img[y + uvx + 2] - 128;    //V
 515 #else
 516             uvx = (x&1)?x-3:x;
 517             curr += (signed char)img[y + uvx + 2];  //V
 518 #endif
 519         }
 520     }
 521 
 522     return curr;
 523 }
 524 
 525 static int md_measure_r()
 526 {
 527     register int x, y, uvx, cy, cv;
 528     register int curr = 0;
 529 
 530     for (y=y_start; y<y_end; y+=y_step)
 531     {
 532         for (x=x_start; x<x_end; x+=x_step)
 533         {
 534             cy = img[y + x + 1];
 535             // Calc offset to U & V components in uvx
 536 #ifdef THUMB_FW
 537             uvx = x & 0xFFFFFFFC;               // U is in 1st two bytes of each 4 byte block V is in 2nd two bytes
 538             cv = (int)img[y + uvx + 2] - 128;
 539 #else
 540             uvx = (x&1)?x-3:x;
 541             cv = (signed char)img[y + uvx + 2];
 542 #endif
 543             curr += clip(((cy<<12) + cv*5743 + 2048)>>12);      // R
 544         }
 545     }
 546 
 547     return curr;
 548 }
 549 
 550 static int md_measure_g()
 551 {
 552     register int x, y, uvx, cy, cu, cv;
 553     register int curr = 0;
 554 
 555     for (y=y_start; y<y_end; y+=y_step)
 556     {
 557         for (x=x_start; x<x_end; x+=x_step)
 558         {
 559             cy = img[y + x + 1];
 560             // Calc offset to U & V components in uvx
 561 #ifdef THUMB_FW
 562             uvx = x & 0xFFFFFFFC;               // U is in 1st two bytes of each 4 byte block V is in 2nd two bytes
 563             cu = (int)img[y + uvx] - 128;
 564             cv = (int)img[y + uvx + 2] - 128;
 565 #else
 566             uvx = (x&1)?x-3:x;
 567             cu = (signed char)img[y + uvx];
 568             cv = (signed char)img[y + uvx + 2];
 569 #endif
 570             curr += clip(((cy<<12) - cu*1411 - cv*2925 + 2048)>>12);    // G
 571         }
 572     }
 573 
 574     return curr;
 575 }
 576 
 577 static int md_measure_b()
 578 {
 579     register int x, y, uvx, cy, cu;
 580     register int curr = 0;
 581 
 582     for (y=y_start; y<y_end; y+=y_step)
 583     {
 584         for (x=x_start; x<x_end; x+=x_step)
 585         {
 586             cy = img[y + x + 1];
 587             // Calc offset to U & V components in uvx
 588 #ifdef THUMB_FW
 589             uvx = x & 0xFFFFFFFC;               // U is in 1st two bytes of each 4 byte block V is in 2nd two bytes
 590             cu = (int)img[y + uvx] - 128;
 591 #else
 592             uvx = (x&1)?x-3:x;
 593             cu = (signed char)img[y + uvx];
 594 #endif
 595             curr += clip(((cy<<12) + cu*7258 + 2048)>>12);      // B
 596         }
 597     }
 598 
 599     return curr;
 600 }
 601 
 602 static int md_detect_motion(void)
 603 {
 604     int idx, tick, rv;
 605     int val, cy, cv, cu;
 606 
 607     register int col, row, x, y;
 608 
 609     if(!md_running())
 610     {
 611         return 0;
 612     }
 613 
 614     tick = get_tick_count();
 615     rv = 1;
 616 
 617 #ifdef OPT_MD_DEBUG
 618     if(motion_detector.comp_calls_cnt < MD_REC_CALLS_CNT)
 619     {
 620         motion_detector.comp_calls[motion_detector.comp_calls_cnt]=tick;
 621     }
 622     motion_detector.comp_calls_cnt++;
 623 #endif
 624 
 625     if(motion_detector.start_time + motion_detector.timeout < tick )
 626     {
 627         md_save_calls_history();
 628         motion_detector.running = 0;
 629         return 0;
 630     }
 631 
 632     if(motion_detector.last_measure_time + motion_detector.measure_interval > tick)
 633     {
 634         // wait for the next time
 635         return 1;
 636     }
 637 
 638     motion_detector.last_measure_time = tick;
 639 
 640     img = vid_get_viewport_active_buffer();
 641     if (!img) return 0;
 642 
 643 #ifdef OPT_MD_DEBUG
 644     if(motion_detector.comp_calls_cnt==50 && (motion_detector.parameters & MD_MAKE_RAM_DUMP_FILE) != 0 )
 645     {
 646         mx_dump_memory((char*)img);
 647     }
 648 #endif
 649 
 650     motion_detector.detected_cells = 0;
 651 
 652     img += vid_get_viewport_image_offset();     // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
 653 
 654     int vp_bw = vid_get_viewport_byte_width();
 655     int vp_h = vid_get_viewport_height_proper();
 656 
 657 #ifdef THUMB_FW
 658     int vp_w = vid_get_viewport_width_proper();
 659     x_step = motion_detector.pixels_step * 2;
 660     y_step = motion_detector.pixels_step * vp_bw;
 661 #else
 662     int vp_w = vid_get_viewport_width_proper() / 2; // Row width in 3 byte units (half UYVYYY block)
 663     x_step = motion_detector.pixels_step * 3;
 664     y_step = motion_detector.pixels_step * vp_bw * vid_get_viewport_yscale();
 665 #endif
 666 
 667     motion_detector.points = ((vp_w / motion_detector.columns + motion_detector.pixels_step - 1) / motion_detector.pixels_step) * ((vp_h / motion_detector.rows + motion_detector.pixels_step - 1) / motion_detector.pixels_step);
 668 
 669     for (idx=0, row=0; row < motion_detector.rows; row++)
 670     {
 671         // Calc img y start and end offsets (use same height for all cells so 'points' is consistent)
 672         y_start = ((row * vp_h) / motion_detector.rows) * vp_bw;
 673         y_end = y_start + ((vp_h / motion_detector.rows) * vp_bw);
 674 
 675         for (col=0; col < motion_detector.columns; col++, idx++)
 676         {
 677             int in_clipping_region=0;
 678 
 679             if (col+1 >= motion_detector.clipping_region_column1 &&
 680                 col+1 <= motion_detector.clipping_region_column2 &&
 681                 row+1 >= motion_detector.clipping_region_row1 &&
 682                 row+1 <= motion_detector.clipping_region_row2)
 683             {
 684                 in_clipping_region=1;
 685             }
 686 
 687             int curr = 0;
 688             int diff = 0;
 689 
 690             if (
 691                 (motion_detector.clipping_region_mode==MD_REGION_NONE) ||
 692                 (motion_detector.clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0) ||
 693                 (motion_detector.clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1)
 694                )
 695             {
 696                 // Calc img x start and end offsets (use same width for all cells so 'points' is consistent)
 697 #ifdef THUMB_FW
 698                 x_start = ((col * vp_w) / motion_detector.columns) * 2;
 699                 x_end = x_start + ((vp_w / motion_detector.columns) * 2);
 700 #else
 701                 x_start = ((col * vp_w) / motion_detector.columns) * 3;
 702                 x_end = x_start + ((vp_w / motion_detector.columns) * 3);
 703 #endif
 704 
 705                 // Do mode check and call function to do inner loops for mode
 706                 // See comments above on mode calulations
 707                 switch (motion_detector.pixel_measure_mode)
 708                 {
 709                     case MD_MEASURE_MODE_Y:
 710                         curr += md_measure_y();
 711                         break;
 712                     case MD_MEASURE_MODE_U:
 713                         curr += md_measure_u();
 714                         break;
 715                     case MD_MEASURE_MODE_V:
 716                         curr += md_measure_v();
 717                         break;
 718                     case MD_MEASURE_MODE_R:
 719                         curr += md_measure_r();
 720                         break;
 721                     case MD_MEASURE_MODE_G:
 722                         curr += md_measure_g();
 723                         break;
 724                     case MD_MEASURE_MODE_B:
 725                         curr += md_measure_b();
 726                         break;
 727                 }
 728 
 729                 diff = (curr - motion_detector.prev[idx]) / motion_detector.points;
 730                 if (diff < 0) diff = -diff;
 731                 if ((diff > motion_detector.threshold) &&
 732                     (motion_detector.start_time+motion_detector.msecs_before_trigger < tick))
 733                 {
 734                     motion_detector.detected_cells++;
 735                 }
 736             }
 737 
 738             motion_detector.diff[idx] = diff;
 739             motion_detector.prev[idx] = curr;
 740         }
 741     }
 742 
 743     if (motion_detector.previous_picture_is_ready == 0)
 744     {
 745         motion_detector.previous_picture_is_ready = 1;
 746         motion_detector.start_time = get_tick_count();
 747         motion_detector.last_measure_time = motion_detector.start_time - motion_detector.measure_interval;
 748     }
 749     else if ( motion_detector.detected_cells > 0 )
 750     {
 751         if (motion_detector.start_time+motion_detector.msecs_before_trigger < tick)
 752         {
 753             motion_detector.running=0;
 754             motion_detector.return_value = motion_detector.detected_cells;
 755 
 756             if ((motion_detector.parameters&MD_DO_IMMEDIATE_SHOOT) != 0)
 757             {
 758                 //make shoot
 759                 md_kbd_sched_immediate_shoot(motion_detector.parameters&MD_NO_SHUTTER_RELEASE_ON_SHOOT);
 760             }
 761             rv = 0;
 762         }
 763     }
 764 
 765     return rv;
 766 }
 767 
 768 int md_get_cell_val(int column, int row)
 769 {
 770     if ((column<1 || column > motion_detector.columns) ||
 771         (row<1 || row > motion_detector.rows))
 772     {
 773         return 0;
 774     }
 775 
 776     return motion_detector.prev[ MD_XY2IDX(column-1,row-1) ]/motion_detector.points ;
 777 }
 778 
 779 int md_get_cell_diff(int column, int row)
 780 {
 781     if ((column<1 || column > motion_detector.columns) ||
 782         (row<1 || row > motion_detector.rows))
 783     {
 784         return 0;
 785     }
 786 
 787     return motion_detector.diff[ MD_XY2IDX(column-1,row-1) ];
 788 }
 789 
 790 void md_draw_grid()
 791 {
 792     int col, row;
 793     int i;
 794     char mdbuff[8];
 795 
 796     if (!md_running() || motion_detector.draw_grid==0 || camera_info.state.state_kbd_script_run==0)
 797     {
 798         return;
 799     }
 800 
 801     int xoffset = vid_get_viewport_display_xoffset();   // used when image size != viewport size
 802     int yoffset = vid_get_viewport_display_yoffset();   // used when image size != viewport size
 803 
 804     // display area size
 805     int x_size = camera_screen.width-xoffset * 2;
 806     int y_size = camera_screen.height-yoffset * 2;
 807 
 808     // initial display offsets
 809     int y_start, y_end = yoffset;
 810     int x_start, x_end;
 811 
 812     for (i=0, row=0; row < motion_detector.rows && camera_info.state.state_kbd_script_run; row++)
 813     {
 814         // Calc display start and end offsets
 815         y_start = y_end;    // reuse last end value as new start value
 816         y_end = yoffset + ((row + 1) * y_size) / motion_detector.rows;
 817 
 818         x_end = xoffset;
 819 
 820         for (col=0; col < motion_detector.columns; col++, i++)
 821         {
 822             // Calc display x start and end offsets
 823             x_start = x_end;    // reuse last end value as new start value
 824             x_end = xoffset + ((col + 1) * x_size) / motion_detector.columns;
 825 
 826             int in_clipping_region = 0;
 827             if ( col+1>=motion_detector.clipping_region_column1
 828                 && col+1<=motion_detector.clipping_region_column2
 829                 && row+1>=motion_detector.clipping_region_row1
 830                 && row+1<=motion_detector.clipping_region_row2
 831                 )
 832             {
 833                 in_clipping_region = 1;
 834             }
 835 
 836             if ((motion_detector.clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0) ||
 837                 (motion_detector.clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1) ||
 838                 (motion_detector.clipping_region_mode==MD_REGION_NONE))
 839             {
 840                 int diff = motion_detector.diff[i];
 841 
 842                 twoColors c = MAKE_COLOR(COLOR_TRANSPARENT, COLOR_GREEN);
 843                 if (diff > motion_detector.threshold)
 844                 {
 845                     c = MAKE_COLOR(COLOR_TRANSPARENT, COLOR_RED);
 846                 }
 847 
 848                 if (motion_detector.draw_grid & 2)
 849                 {
 850                     sprintf(mdbuff,"%-3d", diff);
 851                     draw_string(x_start+4, y_start+2, mdbuff, c);
 852                 }
 853 
 854                 if (motion_detector.draw_grid & 1)
 855                 {
 856                     draw_rectangle(x_start+2, y_start+2, x_end-2, y_end-2, c, RECT_BORDER1);
 857                 }
 858             }
 859         }
 860     }
 861 }
 862 
 863 
 864 // =========  MODULE INIT =================
 865 
 866 /***************** BEGIN OF AUXILARY PART *********************
 867 ATTENTION: DO NOT REMOVE OR CHANGE SIGNATURES IN THIS SECTION
 868 **************************************************************/
 869 
 870 //---------------------------------------------------------
 871 // PURPOSE: Finalize module operations (close allocs, etc)
 872 // RETURN VALUE: 0-ok, 1-fail
 873 //---------------------------------------------------------
 874 int _module_unloader()
 875 {
 876     md_close_motion_detector();
 877     return 0;
 878 }
 879 
 880 int _module_can_unload()
 881 {
 882     return camera_info.state.state_kbd_script_run == SCRIPT_STATE_INACTIVE;
 883 }
 884 
 885 /******************** Module Information structure ******************/
 886 
 887 libmotiondetect_sym _libmotiondetect =
 888 {
 889     {
 890          0, _module_unloader, _module_can_unload, 0, 0
 891     },
 892 
 893     md_close_motion_detector,
 894     md_init_motion_detector,
 895     md_get_cell_diff,
 896     md_draw_grid,
 897     md_get_cell_val,
 898 };
 899 
 900 ModuleInfo _module_info =
 901 {
 902     MODULEINFO_V1_MAGICNUM,
 903     sizeof(ModuleInfo),
 904     MOTION_DETECTOR_VERSION,    // Module version
 905 
 906     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,           // Requirements of CHDK version
 907     ANY_PLATFORM_ALLOWED,       // Specify platform dependency
 908 
 909     -LANG_MODULE_MOTION_DETECT, // Module name
 910     MTYPE_EXTENSION,
 911 
 912     &_libmotiondetect.base,
 913 
 914     ANY_VERSION,                // CONF version
 915     CAM_SCREEN_VERSION,         // CAM SCREEN version
 916     ANY_VERSION,                // CAM SENSOR version
 917     CAM_INFO_VERSION,           // CAM INFO version
 918 };
 919 
 920 /*************** END OF AUXILARY PART *******************/

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