source: trunk/core/motion_detector.c @ 1024

Revision 1024, 16.5 KB checked in by reyalP, 2 years ago (diff)

g12 and sx30 updates from philmoz in http://chdk.setepontos.com/index.php?topic=650.msg59326#msg59326

  • Cleaned up the image offset code.
  • minor bug fixes and corrected address for exmem_alloc
  • moved SCREEN_COLOR define into gui_draw.h so it can be easily overridden (found in five places and default value was white on the SX30 and G12).
  • added some defines configured in makefile.inc so that gui_debug_draw_values can be used to show memory properly (was hard wired to VX addresses).
  • Property svn:eol-style set to native
Line 
1
2/*
3
4Motion detection module
5
6
7Author: mx3 (Max Sagaydachny) . win1251 ( Ìàêñèì Ñàãàéäà÷íûé )
8Email: win.drivers@gmail.com
9Skype: max_dtc
10ICQ#: 125-985-663
11Country: Ukraine
12Sity: Kharkiv
13
14
1520070912 mx3: first version
16
1720070918 mx3: speed optimization,
18
19
20
21*/
22
23
24void dump_memory();
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 "motion_detector.h"
32#include "action_stack.h"
33#include "console.h"
34#include "keyboard.h"
35
36#include "gui.h"
37#include "gui_draw.h"
38
39
40#define MD_XY2IDX(x,y) ((y)*motion_detector->columns+x)
41
42enum {
43
44        MD_MEASURE_MODE_U=0,
45        MD_MEASURE_MODE_Y=1,
46        MD_MEASURE_MODE_V=2,
47        MD_MEASURE_MODE_R=3,
48        MD_MEASURE_MODE_G=4,
49        MD_MEASURE_MODE_B=5
50};
51
52enum {
53    MD_DO_IMMEDIATE_SHOOT=1,
54    MD_MAKE_DEBUG_LOG_FILE=2,
55    MD_MAKE_RAM_DUMP_FILE=4,
56    MD_NO_SHUTTER_RELEASE_ON_SHOOT=8
57};
58
59enum {
60        MD_REGION_NONE=0,
61        MD_REGION_INCLUDE=1,
62        MD_REGION_EXCLUDE=2
63};
64
65
66
67
68
69//#define MD_XY2IDX(x,y) ((y)*motion_detector->columns+x)
70
71
72struct motion_detector_s {
73        int *curr; // points to buff1 or buff2
74        int *prev; // points to buff2 or buff1
75        int buff1[MOTION_DETECTOR_CELLS];
76        int buff2[MOTION_DETECTOR_CELLS];
77        int points[MOTION_DETECTOR_CELLS];
78
79        int columns;
80        int rows;
81        int threshold;
82        int pixel_measure_mode;
83        int timeout;
84        int measure_interval;
85
86        int last_measure_time;
87        int start_time;
88
89        int running;
90        int detected_cells;
91
92        int draw_grid;
93        int clipping_region_mode;
94        int clipping_region_row1;
95        int clipping_region_column1;
96        int clipping_region_row2;
97        int clipping_region_column2;
98
99        int previous_picture_is_ready;
100
101        int return_value;
102        int parameters;
103        int pixels_step;
104        int msecs_before_trigger;
105
106// debug
107#ifdef OPT_MD_DEBUG
108        int comp_calls_cnt;
109        int comp_calls[MD_REC_CALLS_CNT];
110#endif
111};
112
113static struct motion_detector_s *motion_detector=NULL;
114
115static void md_kbd_sched_immediate_shoot(int no_release)
116{
117    action_pop();// REMOVE MD ITEM
118 
119    // stack operations are reversed!
120    if (!no_release)  // only release shutter if allowed
121    {
122      action_push_release(KEY_SHOOT_FULL);
123      action_push_delay(20);
124    }
125    action_push(AS_MOTION_DETECTOR); // it will removed right after exit from this function
126    kbd_key_press(KEY_SHOOT_FULL); // not a stack operation... pressing right now
127}
128
129static int clip(int v) {
130    if (v<0) v=0;
131    if (v>255) v=255;
132    return v;
133}
134
135
136// TODO add script interface, currently done when script ends
137void md_close_motion_detector()
138{
139        free(motion_detector);
140        motion_detector=NULL;
141}
142
143
144int md_init_motion_detector(
145 int columns,
146 int rows,
147 int pixel_measure_mode,
148 int detection_timeout,
149 int measure_interval,
150 int threshold,
151 int draw_grid,
152 int clipping_region_mode,
153 int clipping_region_column1,
154 int clipping_region_row1,
155 int clipping_region_column2,
156 int clipping_region_row2,
157 int parameters,
158 int pixels_step,
159 int msecs_before_trigger
160){
161
162        if(!motion_detector) {
163                motion_detector=malloc(sizeof(struct motion_detector_s));
164                if(!motion_detector)
165                        return 0; // TODO make sure callers handle this
166        }
167#ifdef OPT_MD_DEBUG
168        motion_detector->comp_calls_cnt=0;
169#endif
170        motion_detector->previous_picture_is_ready=0;
171        motion_detector->curr=motion_detector->buff1;
172        motion_detector->prev=motion_detector->buff2;
173
174        if(             pixel_measure_mode != MD_MEASURE_MODE_Y
175                &&      pixel_measure_mode != MD_MEASURE_MODE_U
176                &&      pixel_measure_mode != MD_MEASURE_MODE_V
177                &&      pixel_measure_mode != MD_MEASURE_MODE_R
178                &&      pixel_measure_mode != MD_MEASURE_MODE_G
179                &&      pixel_measure_mode != MD_MEASURE_MODE_B
180                ){
181                pixel_measure_mode = MD_MEASURE_MODE_Y;
182        }
183
184
185        if( columns<1 || rows<1 || columns * rows > MOTION_DETECTOR_CELLS ){
186                columns=3;
187                rows=3;
188        }
189
190        if(msecs_before_trigger<0){
191                msecs_before_trigger=0;
192        }
193
194        if (pixels_step<1){
195                pixels_step=1;
196        }
197
198        if(detection_timeout<0){
199                detection_timeout=0;
200        }
201
202        if(measure_interval<0) {
203                measure_interval=0;
204        }
205
206        if(threshold<0) {
207                threshold=0;
208        }
209
210
211        motion_detector->msecs_before_trigger=msecs_before_trigger;
212        motion_detector->parameters = parameters;
213        motion_detector->pixels_step=pixels_step;
214        motion_detector->columns=columns;
215        motion_detector->rows=rows;
216        motion_detector->return_value=0;
217       
218
219        motion_detector->pixel_measure_mode=pixel_measure_mode;
220        motion_detector->timeout=detection_timeout;
221        motion_detector->measure_interval=measure_interval;
222        motion_detector->threshold=threshold;
223        motion_detector->draw_grid=draw_grid;
224
225
226        if (clipping_region_column1>clipping_region_column2){
227                motion_detector->clipping_region_column2=clipping_region_column1;
228                motion_detector->clipping_region_column1=clipping_region_column2;
229        } else {
230                motion_detector->clipping_region_column2=clipping_region_column2;
231                motion_detector->clipping_region_column1=clipping_region_column1;
232        }
233
234        if (clipping_region_row1>clipping_region_row2){
235                motion_detector->clipping_region_row2=clipping_region_row1;
236                motion_detector->clipping_region_row1=clipping_region_row2;
237        } else {
238                motion_detector->clipping_region_row2=clipping_region_row2;
239                motion_detector->clipping_region_row1=clipping_region_row1;
240        }
241
242        if (clipping_region_mode!=MD_REGION_NONE && clipping_region_mode!=MD_REGION_INCLUDE && clipping_region_mode!=MD_REGION_EXCLUDE){
243                clipping_region_mode=MD_REGION_NONE;
244        }
245        motion_detector->clipping_region_mode=clipping_region_mode;
246
247        motion_detector->detected_cells=0;
248        motion_detector->previous_picture_is_ready=0;
249        motion_detector->start_time=get_tick_count();
250
251        motion_detector->last_measure_time = motion_detector->start_time - motion_detector->measure_interval;
252
253        motion_detector->running=1;
254
255        action_push(AS_MOTION_DETECTOR);
256        draw_clear();
257
258        return 1;
259}
260
261#ifdef OPT_MD_DEBUG
262void md_save_calls_history(){
263        char buf[200], fn[30];
264        char big[MD_INFO_BUF_SIZE];
265        int big_ln;
266        int calls,i, ln, fd;
267  static struct utimbuf t;
268    unsigned long t2;
269    static struct tm *ttm;
270
271
272        if( (motion_detector->parameters & MD_MAKE_DEBUG_LOG_FILE) == 0 ){
273                return;
274        }
275       
276
277        strcpy(fn,"A/MD_INFO.TXT");//,BUILD_NUMBER,motion_detector->pixels_step);
278        fd = open(fn, O_WRONLY|O_CREAT, 0777);
279        if( fd>=0) {
280                console_add_line("Writing info file...");
281                lseek(fd,0,SEEK_END);
282    t2 = time(NULL);
283    ttm = localtime(&t2);
284    big_ln=sprintf(big,
285                                "\r\n--- %04u-%02u-%02u  %02u:%02u:%02u\r\n"
286                                "CHDK Ver: %s [ #%s ]\r\nBuild Date: %s %s\r\nCamera:  %s [ %s ]\r\n"
287                                "[%dx%d], threshold: %d, interval: %d, pixels step: %d\r\n"
288                                "region: [%d,%d-%d,%d], region type: %d\r\n"
289                                "wait interval: %d, parameters: %d, calls: %d, detected cells: %d\r\n",
290                                1900+ttm->tm_year, ttm->tm_mon+1, ttm->tm_mday, ttm->tm_hour, ttm->tm_min, ttm->tm_sec,
291                                HDK_VERSION, BUILD_NUMBER, __DATE__, __TIME__, PLATFORM, PLATFORMSUB,
292                                motion_detector->columns, motion_detector->rows, motion_detector->threshold, motion_detector->measure_interval, motion_detector->pixels_step,
293                                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,
294                                motion_detector->msecs_before_trigger, motion_detector->parameters, motion_detector->comp_calls_cnt,
295                                motion_detector->detected_cells
296                );
297
298                calls = ( motion_detector->comp_calls_cnt < MD_REC_CALLS_CNT) ?motion_detector->comp_calls_cnt: MD_REC_CALLS_CNT;
299
300                for(i=0;i<calls;i++){
301                        ln=sprintf(buf,"[%d] - %d\r\n",i,motion_detector->comp_calls[i]);
302                        if(big_ln+ln>MD_INFO_BUF_SIZE){
303              write(fd,big,big_ln);
304                                big_ln=0;
305                        }
306                        memcpy(big+big_ln,buf,ln+1);
307                        big_ln+=ln;
308                }
309    write(fd,big,big_ln);
310                close(fd);
311          t.actime = t.modtime = time(NULL);
312    utime(fn, &t);
313        }
314}
315
316static void mx_dump_memory(void *img){
317        char fn[36];
318        int fd, i;
319        static int cnt=0;
320
321    started();
322    mkdir("A/MD");
323
324                do {
325                        cnt++;
326                        sprintf(fn, "A/MD/%04d.FB", cnt);
327                        fd = open(fn, O_RDONLY, 0777);
328
329                        if(fd>=0){
330                                close(fd);
331                        }
332                } while(fd>=0);
333
334
335                sprintf(fn, "A/MD/%04d.FB", cnt );
336                fd = open(fn, O_WRONLY|O_CREAT, 0777);
337                if (fd) {
338            write(fd, img, screen_width*vid_get_viewport_height()*3);
339            close(fd);
340                }
341  vid_bitmap_refresh();
342  finished();
343
344}
345#else
346#define md_save_calls_history()
347#define mx_dump_memory(x)
348#endif
349
350
351int md_detect_motion(void){
352        int *tmp;
353        unsigned char * img;
354        int viewport_size;
355        int img_offset;         // used as offset into img buffer when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
356        int vp_w, vp_h, pix_N, idx, tmp2, tick, vp_w_mul_y, in_clipping_region, x_step, y_step, do_calc;
357        int val;
358
359        register int i, col, row, x, y;
360
361//      static char buf[128];
362        double vp_hr, vp_wr;
363
364
365
366        if(!md_running()){
367                return 0;
368        }
369
370        tick=get_tick_count();
371#ifdef OPT_MD_DEBUG
372        if(motion_detector->comp_calls_cnt < MD_REC_CALLS_CNT) {
373                motion_detector->comp_calls[motion_detector->comp_calls_cnt]=tick;
374        }
375        motion_detector->comp_calls_cnt++;
376#endif
377
378        if(motion_detector->start_time + motion_detector->timeout < tick ) {
379                md_save_calls_history();
380                motion_detector->running = 0;
381                return 0;
382        }
383
384        if(motion_detector->last_measure_time + motion_detector->measure_interval > tick){
385                // wait for the next time
386                return 1;
387        }
388
389        motion_detector->last_measure_time=tick;
390
391// swap pointers so we don't need to copy last data array into Previous one
392        tmp=motion_detector->curr;
393        motion_detector->curr=motion_detector->prev;
394        motion_detector->prev=tmp;
395
396//      memset(motion_detector->points,0, sizeof(motion_detector->points));
397// WARNING. maybe not optimized
398        for(i=0 ; i<motion_detector->rows*motion_detector->columns ; i++ ){
399                motion_detector->points[i]=0;
400                motion_detector->curr[i]=0;
401        }
402
403
404        // >> fill "curr" array
405 
406
407//  if (strcmp(PLATFORM,"a610")==0 || strcmp(PLATFORM,"a710")==0) {
408         img = vid_get_viewport_live_fb();
409                if(img==NULL){
410                        img = vid_get_viewport_fb();
411        }
412/* the following is commented because of a bugreport: http://chdk.kernreaktor.org/mantis/view.php?id=70
413#if defined (CAMERA_s5is)
414long bufoff = *((long *) 0x218C);
415if(bufoff == 0) {
416    bufoff = 2;
417} else {
418    bufoff--;
419}
420img += bufoff * 0x7E900;
421#endif
422*/
423
424#ifdef OPT_MD_DEBUG
425        if(motion_detector->comp_calls_cnt==50 && (motion_detector->parameters & MD_MAKE_RAM_DUMP_FILE) != 0 ){
426                mx_dump_memory((char*)img);
427        }
428#endif
429
430        vp_h=vid_get_viewport_height();
431        vp_w=vid_get_viewport_buffer_width();
432        img_offset = vid_get_viewport_image_offset();           // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
433
434        x_step=vid_get_viewport_width()/motion_detector->columns;
435        y_step=vp_h/motion_detector->rows;
436
437        for(row=0, col=0; row < motion_detector->rows ; ){
438                do_calc=0;
439                in_clipping_region=0;
440
441                if (
442                                 col+1 >= motion_detector->clipping_region_column1
443                        && col+1 <= motion_detector->clipping_region_column2
444                        && row+1 >= motion_detector->clipping_region_row1
445                        && row+1 <= motion_detector->clipping_region_row2
446                        ){
447                                in_clipping_region=1;
448                }
449
450                if(motion_detector->clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0){
451                        do_calc=1;
452                }
453
454                if(motion_detector->clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1){
455                        do_calc=1;
456                }
457
458                if(motion_detector->clipping_region_mode==MD_REGION_NONE){
459                        do_calc=1;
460                }
461
462                if(do_calc==1){
463                  idx=MD_XY2IDX(col,row);
464                        for(x=col*x_step;x<(col+1)*x_step;x+=motion_detector->pixels_step){
465                                for(y=row*y_step;y<(row+1)*y_step;y+=motion_detector->pixels_step){
466                                        int cy,cv,cu;
467
468                                        cy=img[img_offset + (y*vp_w+x)*3 + 1];
469
470// ARRAY of UYVYYY values
471// 6 bytes - 4 pixels
472
473                                        if((x%2)==0){
474                                                cu=img[img_offset + (y*vp_w+x)*3];
475                                                cv=img[img_offset + (y*vp_w+x)*3 + 2];
476                                        } else {
477                                                cu=img[img_offset + (y*vp_w+x-1)*3];
478                                                cv=img[img_offset + (y*vp_w+x-1)*3 + 2];
479                                        }
480
481                                        switch(motion_detector->pixel_measure_mode){
482                                                MD_MEASURE_MODE_Y:
483                                                        val=cy;
484                                                        break;
485                                                MD_MEASURE_MODE_U:
486                                                        val=cu;
487                                                        break;
488                                                MD_MEASURE_MODE_V:
489                                                                val = cv;
490                                                        break;
491
492                                                MD_MEASURE_MODE_R:
493                val = clip(((cy<<12)           + cv*5743 + 2048)/4096); // R
494                                                        break;
495
496                                                MD_MEASURE_MODE_G:
497                val = clip(((cy<<12) - cu*1411 - cv*2925 + 2048)/4096); // G
498                                                        break;
499
500                                                MD_MEASURE_MODE_B:
501                val = clip(((cy<<12) + cu*7258           + 2048)/4096); // B
502                                                        break;
503
504                                                default:
505                                                                val=cy;
506                                                        break;
507                                        }
508                                        motion_detector->curr[ idx ]+=val;
509                                        motion_detector->points[ idx ]++;
510                                }
511                        }
512                }
513
514                col++;
515                if(col>=motion_detector->columns){
516                        col=0;
517                        row++;
518                }
519        }
520        // << fill "curr" array
521
522
523        if(motion_detector->previous_picture_is_ready==0){
524                motion_detector->previous_picture_is_ready=1;
525                motion_detector->start_time=get_tick_count();
526                motion_detector->last_measure_time=motion_detector->start_time-motion_detector->measure_interval;
527                return 1;
528        }
529
530
531        // >> compare arrays here
532
533                for ( col=0, row=0; row < motion_detector->rows; ){
534                  idx=MD_XY2IDX(col,row);
535                        tmp2=0;
536                        if(motion_detector->points[idx]>0){
537                                motion_detector->prev[idx] = (motion_detector->curr[idx]-motion_detector->prev[idx])/motion_detector->points[idx];
538                                tmp2 = ( motion_detector->prev[idx] < 0 ) ? -motion_detector->prev[idx] : motion_detector->prev[idx] ;
539                        }
540       
541                        if( tmp2 > motion_detector->threshold ){
542                                if (motion_detector->start_time+motion_detector->msecs_before_trigger < tick){
543                                        motion_detector->detected_cells++;
544                                }
545                        }
546
547                        col++;
548                        if(col>=motion_detector->columns){
549                                col=0;
550                                row++;
551                        }
552                }
553               
554        // << compare arrays here
555
556
557        if( motion_detector->detected_cells > 0 ){
558//              sprintf(buf,"-cells: %d", motion_detector->detected_cells);
559//              script_console_add_line(buf);
560
561                if (motion_detector->start_time+motion_detector->msecs_before_trigger < tick){
562                        motion_detector->running=0;
563            motion_detector->return_value = motion_detector->detected_cells;
564           
565//                      md_save_calls_history();
566                        if( ( motion_detector->parameters&MD_DO_IMMEDIATE_SHOOT ) !=0){
567                                //make shoot
568                                //kbd_sched_shoot();
569                                md_kbd_sched_immediate_shoot(motion_detector->parameters&MD_NO_SHUTTER_RELEASE_ON_SHOOT);
570                        }
571                        return 0;
572                }
573        }
574
575
576        return 1;
577}
578
579
580int md_get_cell_diff(int column, int row){
581
582        if(!motion_detector){
583                return 0;
584        }
585        if (column<1 || column > motion_detector->columns){
586                return 0;
587        }
588
589        if (row<1 || row > motion_detector->rows ){
590                return 0;
591        }
592       
593
594        return motion_detector->prev[ MD_XY2IDX(column-1,row-1) ];
595}
596
597
598
599int md_running(){
600        return motion_detector?motion_detector->running:0;
601}
602
603
604void md_draw_grid(){
605        int x_step, y_step, col, row;
606        int xoffset, yoffset;
607        int do_draw_rect, i, tmp2, in_clipping_region, color, col_start, col_stop, row_start, row_stop;
608
609        if(!md_running() || motion_detector->draw_grid==0){
610                return ;
611        }
612
613        xoffset = ASPECT_VIEWPORT_XCORRECTION(vid_get_viewport_xoffset());      // used when image size != viewport size
614        yoffset = vid_get_viewport_yoffset();   // used when image size != viewport size
615
616        x_step=(screen_width-xoffset*2)/motion_detector->columns;
617        y_step=(screen_height-yoffset*2)/motion_detector->rows;
618#if 0
619        row_start=1;
620        row_stop=motion_detector->rows;
621        if(motion_detector->clipping_region_mode==2){
622                row_start=motion_detector->clipping_region_row1;
623                row_stop=motion_detector->clipping_region_row2+1;
624                col_start=motion_detector->clipping_region_column1;
625                col_stop=motion_detector->clipping_region_column2+1;
626        }
627        if(motion_detector->clipping_region_mode==0 || motion_detector->clipping_region_mode==2){
628                for(col=col_start;col<col_stop;col++){
629                        draw_line(col*x_step,0,col*x_step,screen_height, COLOR_GREEN);
630                }
631                for(row=row_start;row<row_stop;row++){
632                        draw_line(0,row*y_step,screen_width,row*y_step, COLOR_GREEN);
633                }
634        } else if(motion_detector->clipping_region_mode==1){
635                for(col=1;col<motion_detector->columns;col++){
636                        if(col<){
637                                draw_line(col*x_step,0,col*x_step,screen_height, COLOR_GREEN);
638                        }
639                }
640        }
641#endif
642
643        for ( col=0, row=0; row < motion_detector->rows; ){
644                i=MD_XY2IDX(col,row);
645                tmp2 = ( motion_detector->prev[i] < 0 ) ? -motion_detector->prev[i] : motion_detector->prev[i] ;
646
647                        in_clipping_region=0;
648                        if ( col+1>=motion_detector->clipping_region_column1
649                                && col+1<=motion_detector->clipping_region_column2
650                                && row+1>=motion_detector->clipping_region_row1
651                                && row+1<=motion_detector->clipping_region_row2
652                                ){
653                                        in_clipping_region=1;
654                        }
655
656                        do_draw_rect=0;
657
658                        if(motion_detector->clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0){
659                                do_draw_rect=1;
660                        }
661
662                        if(motion_detector->clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1){
663                                do_draw_rect=1;
664                        }
665
666                        if(motion_detector->clipping_region_mode==MD_REGION_NONE){
667                                do_draw_rect=1;
668                        }
669
670                        if(do_draw_rect==1){
671                                color=COLOR_GREEN;
672                                if( tmp2 > motion_detector->threshold){
673                                        color=COLOR_RED;
674                                }
675                                draw_rect(xoffset+x_step*col+2,yoffset+y_step*row+2, xoffset+x_step*(col+1)-2, yoffset+y_step*(row+1)-2,color);
676                        }
677
678                        col++;
679                        if( col >= motion_detector->columns ){
680                                row++;
681                                col=0;
682                        }
683        }
684
685}
686
687int md_get_result()
688{
689    return motion_detector->return_value;
690}
Note: See TracBrowser for help on using the repository browser.