source: trunk/core/motion_detector.c @ 1087

Revision 1087, 16.3 KB checked in by reyalP, 2 years ago (diff)

md cleanup and optimization from philmoz in http://chdk.setepontos.com/index.php?topic=650.msg62654#msg62654

  • 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 vp_w, vp_h, idx, tmp2, tick, in_clipping_region, x_step, y_step, x_end, y_end;
355        int val;
356    int cy,cv,cu;
357
358        register int col, row, x, y;
359
360        if(!md_running()){
361                return 0;
362        }
363
364        tick=get_tick_count();
365#ifdef OPT_MD_DEBUG
366        if(motion_detector->comp_calls_cnt < MD_REC_CALLS_CNT) {
367                motion_detector->comp_calls[motion_detector->comp_calls_cnt]=tick;
368        }
369        motion_detector->comp_calls_cnt++;
370#endif
371
372        if(motion_detector->start_time + motion_detector->timeout < tick ) {
373                md_save_calls_history();
374                motion_detector->running = 0;
375                return 0;
376        }
377
378        if(motion_detector->last_measure_time + motion_detector->measure_interval > tick){
379                // wait for the next time
380                return 1;
381        }
382
383        motion_detector->last_measure_time=tick;
384
385// swap pointers so we don't need to copy last data array into Previous one
386        tmp=motion_detector->curr;
387        motion_detector->curr=motion_detector->prev;
388        motion_detector->prev=tmp;
389
390//      memset(motion_detector->points,0, sizeof(motion_detector->points));
391// WARNING. maybe not optimized
392        //for(i=0 ; i<motion_detector->rows*motion_detector->columns ; i++ ){
393        //      motion_detector->points[i]=0;
394        //      motion_detector->curr[i]=0;
395        //}
396
397
398        // >> fill "curr" array
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 += vid_get_viewport_image_offset();         // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
426
427        x_step=vid_get_viewport_width()/motion_detector->columns;
428        y_step=vp_h/motion_detector->rows;
429
430        for (idx=0, row=0; row < motion_detector->rows; row++)
431        {
432                for (col=0; col < motion_detector->columns; col++, idx++)
433                {
434                        motion_detector->points[idx] = 0;
435                        motion_detector->curr[idx] = 0;
436
437                        in_clipping_region=0;
438
439                        if (col+1 >= motion_detector->clipping_region_column1 &&
440                                col+1 <= motion_detector->clipping_region_column2 &&
441                                row+1 >= motion_detector->clipping_region_row1 &&
442                                row+1 <= motion_detector->clipping_region_row2)
443                        {
444                                in_clipping_region=1;
445                        }
446
447                        if (
448                                (motion_detector->clipping_region_mode==MD_REGION_NONE) ||
449                                (motion_detector->clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0) ||
450                                (motion_detector->clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1)
451                           )
452                        {
453                                x_end=(col+1)*x_step;
454                                y_end=(row+1)*y_step*vp_w;
455                                for(y=row*y_step*vp_w; y<y_end; y+=motion_detector->pixels_step*vp_w){
456                                        for(x=col*x_step; x<x_end; x+=motion_detector->pixels_step){
457
458                                                // ARRAY of UYVYYY values
459                                                // 6 bytes - 4 pixels
460
461                                                switch(motion_detector->pixel_measure_mode){
462                                                default:
463                                                case MD_MEASURE_MODE_Y:
464                                                        val = img[(y+x)*3 + 1];                         //Y
465                                                        break;
466                                                case MD_MEASURE_MODE_U:
467                                                        val = img[(y+(x&0xFFFFFFFE))*3];                //U
468                                                        break;
469                                                case MD_MEASURE_MODE_V:
470                                                        val = img[(y+(x&0xFFFFFFFE))*3 + 2];    //V
471                                                        break;
472
473                                                case MD_MEASURE_MODE_R:
474                                                        cy=img[(y+x)*3 + 1];
475                                                        cv=img[(y+(x&0xFFFFFFFE))*3 + 2];
476                                                        val = clip(((cy<<12)           + cv*5743 + 2048)>>12); // R
477                                                        break;
478
479                                                case MD_MEASURE_MODE_G:
480                                                        cy=img[(y+x)*3 + 1];
481                                                        cu=img[(y+(x&0xFFFFFFFE))*3];
482                                                        cv=img[(y+(x&0xFFFFFFFE))*3 + 2];
483                                                        val = clip(((cy<<12) - cu*1411 - cv*2925 + 2048)>>12); // G
484                                                        break;
485
486                                                case MD_MEASURE_MODE_B:
487                                                        cy=img[(y+x)*3 + 1];
488                                                        cu=img[(y+(x&0xFFFFFFFE))*3];
489                                                        val = clip(((cy<<12) + cu*7258           + 2048)>>12); // B
490                                                        break;
491                                                }
492
493                                                motion_detector->curr[ idx ] += val;
494                                                motion_detector->points[ idx ]++;
495                                        }
496                                }
497                        }
498                }
499        }
500        // << fill "curr" array
501
502
503        if(motion_detector->previous_picture_is_ready==0){
504                motion_detector->previous_picture_is_ready=1;
505                motion_detector->start_time=get_tick_count();
506                motion_detector->last_measure_time=motion_detector->start_time-motion_detector->measure_interval;
507                return 1;
508        }
509
510
511        // >> compare arrays here
512        for (idx=0; idx < motion_detector->rows*motion_detector->columns; idx++)
513        {
514                tmp2=0;
515                if(motion_detector->points[idx]>0){
516                        motion_detector->prev[idx] = (motion_detector->curr[idx]-motion_detector->prev[idx])/motion_detector->points[idx];
517                        tmp2 = ( motion_detector->prev[idx] < 0 ) ? -motion_detector->prev[idx] : motion_detector->prev[idx] ;
518                }
519
520                if( tmp2 > motion_detector->threshold ){
521                        if (motion_detector->start_time+motion_detector->msecs_before_trigger < tick){
522                                motion_detector->detected_cells++;
523                        }
524                }
525        }
526        // << compare arrays here
527
528
529        if( motion_detector->detected_cells > 0 ){
530//              sprintf(buf,"-cells: %d", motion_detector->detected_cells);
531//              script_console_add_line(buf);
532
533                if (motion_detector->start_time+motion_detector->msecs_before_trigger < tick){
534                        motion_detector->running=0;
535            motion_detector->return_value = motion_detector->detected_cells;
536           
537//                      md_save_calls_history();
538                        if( ( motion_detector->parameters&MD_DO_IMMEDIATE_SHOOT ) !=0){
539                                //make shoot
540                                //kbd_sched_shoot();
541                                md_kbd_sched_immediate_shoot(motion_detector->parameters&MD_NO_SHUTTER_RELEASE_ON_SHOOT);
542                        }
543                        return 0;
544                }
545        }
546
547
548        return 1;
549}
550
551
552int md_get_cell_diff(int column, int row){
553
554        if(!motion_detector){
555                return 0;
556        }
557        if (column<1 || column > motion_detector->columns){
558                return 0;
559        }
560
561        if (row<1 || row > motion_detector->rows ){
562                return 0;
563        }
564       
565
566        return motion_detector->prev[ MD_XY2IDX(column-1,row-1) ];
567}
568
569
570
571int md_running(){
572        return motion_detector?motion_detector->running:0;
573}
574
575
576void md_draw_grid(){
577        int x_step, y_step, col, row;
578        int xoffset, yoffset;
579        int do_draw_rect, i, tmp2, in_clipping_region, color, col_start, col_stop, row_start, row_stop;
580
581        if(!md_running() || motion_detector->draw_grid==0){
582                return ;
583        }
584
585        xoffset = ASPECT_VIEWPORT_XCORRECTION(vid_get_viewport_xoffset());      // used when image size != viewport size
586        yoffset = vid_get_viewport_yoffset();   // used when image size != viewport size
587
588        x_step=(screen_width-xoffset*2)/motion_detector->columns;
589        y_step=(screen_height-yoffset*2)/motion_detector->rows;
590#if 0
591        row_start=1;
592        row_stop=motion_detector->rows;
593        if(motion_detector->clipping_region_mode==2){
594                row_start=motion_detector->clipping_region_row1;
595                row_stop=motion_detector->clipping_region_row2+1;
596                col_start=motion_detector->clipping_region_column1;
597                col_stop=motion_detector->clipping_region_column2+1;
598        }
599        if(motion_detector->clipping_region_mode==0 || motion_detector->clipping_region_mode==2){
600                for(col=col_start;col<col_stop;col++){
601                        draw_line(col*x_step,0,col*x_step,screen_height, COLOR_GREEN);
602                }
603                for(row=row_start;row<row_stop;row++){
604                        draw_line(0,row*y_step,screen_width,row*y_step, COLOR_GREEN);
605                }
606        } else if(motion_detector->clipping_region_mode==1){
607                for(col=1;col<motion_detector->columns;col++){
608                        if(col<){
609                                draw_line(col*x_step,0,col*x_step,screen_height, COLOR_GREEN);
610                        }
611                }
612        }
613#endif
614
615        for ( col=0, row=0; row < motion_detector->rows; ){
616                i=MD_XY2IDX(col,row);
617                tmp2 = ( motion_detector->prev[i] < 0 ) ? -motion_detector->prev[i] : motion_detector->prev[i] ;
618
619                        in_clipping_region=0;
620                        if ( col+1>=motion_detector->clipping_region_column1
621                                && col+1<=motion_detector->clipping_region_column2
622                                && row+1>=motion_detector->clipping_region_row1
623                                && row+1<=motion_detector->clipping_region_row2
624                                ){
625                                        in_clipping_region=1;
626                        }
627
628                        do_draw_rect=0;
629
630                        if(motion_detector->clipping_region_mode==MD_REGION_EXCLUDE && in_clipping_region==0){
631                                do_draw_rect=1;
632                        }
633
634                        if(motion_detector->clipping_region_mode==MD_REGION_INCLUDE && in_clipping_region==1){
635                                do_draw_rect=1;
636                        }
637
638                        if(motion_detector->clipping_region_mode==MD_REGION_NONE){
639                                do_draw_rect=1;
640                        }
641
642                        if(do_draw_rect==1){
643                                color=COLOR_GREEN;
644                                if( tmp2 > motion_detector->threshold){
645                                        color=COLOR_RED;
646                                }
647                                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);
648                        }
649
650                        col++;
651                        if( col >= motion_detector->columns ){
652                                row++;
653                                col=0;
654                        }
655        }
656
657}
658
659int md_get_result()
660{
661    return motion_detector->return_value;
662}
Note: See TracBrowser for help on using the repository browser.