source: trunk/core/motion_detector.c @ 1017

Revision 1017, 16.1 KB checked in by reyalP, 2 years ago (diff)

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

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