X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fmodules%2Fmotion_est%2Ffilter_autotrack_rectangle.c;h=0d526e4547bb3a266a2502edfaa40ba1fac80fa4;hb=16b6d374cf80004b192aae74a55b0452c7ee809d;hp=90efadbb97fcf0c06f6f9112fff7735d1cf85d6d;hpb=4f3d5f48dd9b4a0caddce6b65d9f8d4ad7a4f04a;p=melted diff --git a/src/modules/motion_est/filter_autotrack_rectangle.c b/src/modules/motion_est/filter_autotrack_rectangle.c index 90efadb..0d526e4 100644 --- a/src/modules/motion_est/filter_autotrack_rectangle.c +++ b/src/modules/motion_est/filter_autotrack_rectangle.c @@ -21,6 +21,7 @@ */ #include "filter_motion_est.h" +#include "arrow_code.h" #include @@ -34,121 +35,23 @@ #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) #define ABS(a) ((a) >= 0 ? (a) : (-(a))) -// ffmpeg borrowed -static inline int clip(int a, int amin, int amax) -{ - if (a < amin) - return amin; - else if (a > amax) - return amax; - else - return a; -} - - -/** - * draws an line from (ex, ey) -> (sx, sy). - * Credits: modified from ffmpeg project - * @param ystride stride/linesize of the image - * @param xstride stride/element size of the image - * @param color color of the arrow - */ -static void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, int w, int h, int xstride, int ystride, int color){ - int t, x, y, fr, f; - -// buf[sy*ystride + sx*xstride]= color; - buf[sy*ystride + sx]+= color; - - sx= clip(sx, 0, w-1); - sy= clip(sy, 0, h-1); - ex= clip(ex, 0, w-1); - ey= clip(ey, 0, h-1); - - if(ABS(ex - sx) > ABS(ey - sy)){ - if(sx > ex){ - t=sx; sx=ex; ex=t; - t=sy; sy=ey; ey=t; - } - buf+= sx*xstride + sy*ystride; - ex-= sx; - f= ((ey-sy)<<16)/ex; - for(x= 0; x <= ex; x++){ - y = (x*f)>>16; - fr= (x*f)&0xFFFF; - buf[ y *ystride + x*xstride]= (color*(0x10000-fr))>>16; - buf[(y+1)*ystride + x*xstride]= (color* fr )>>16; - } - }else{ - if(sy > ey){ - t=sx; sx=ex; ex=t; - t=sy; sy=ey; ey=t; - } - buf+= sx*xstride + sy*ystride; - ey-= sy; - if(ey) f= ((ex-sx)<<16)/ey; - else f= 0; - for(y= 0; y <= ey; y++){ - x = (y*f)>>16; - fr= (y*f)&0xFFFF; - buf[y*ystride + x *xstride]= (color*(0x10000-fr))>>16;; - buf[y*ystride + (x+1)*xstride]= (color* fr )>>16;; - } - } -} - -/** - * draws an arrow from (ex, ey) -> (sx, sy). - * Credits: modified from ffmpeg project - * @param stride stride/linesize of the image - * @param color color of the arrow - */ -static __attribute__((used)) void draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, int w, int h, int xstride, int ystride, int color){ - int dx,dy; - -// sx= clip(sx, -100, w+100); -// sy= clip(sy, -100, h+100); -// ex= clip(ex, -100, w+100); -// ey= clip(ey, -100, h+100); - - dx= ex - sx; - dy= ey - sy; - - if(dx*dx + dy*dy > 3*3){ - int rx= dx + dy; - int ry= -dx + dy; - int length= sqrt((rx*rx + ry*ry)<<8); - - //FIXME subpixel accuracy - rx= ROUNDED_DIV(rx*3<<4, length); - ry= ROUNDED_DIV(ry*3<<4, length); - - draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, xstride, ystride, color); - draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, xstride, ystride, color); - } - draw_line(buf, sx, sy, ex, ey, w, h, xstride, ystride, color); -} - void caculate_motion( struct motion_vector_s *vectors, mlt_geometry_item boundry, int macroblock_width, int macroblock_height, int mv_buffer_width, - int method ) + int method, + int width, + int height ) { // translate pixel units (from bounds) to macroblock units // make sure whole macroblock stay within bounds - // I know; it hurts. - int left_mb = boundry->x / macroblock_width; - left_mb += ( (int)boundry->x % macroblock_width == 0 ) ? 0 : 1 ; - int top_mb = boundry->y / macroblock_height; - top_mb += ( (int)boundry->y % macroblock_height == 0 ) ? 0 : 1 ; - - int right_mb = (boundry->x + boundry->w + 1) / macroblock_width; - right_mb -= ( (int)(boundry->x + boundry->w + 1) % macroblock_width == 0 ) ? 0 : 1 ; - int bottom_mb = (boundry->y + boundry->h + 1) / macroblock_height; - bottom_mb -= ( (int)(boundry->y + boundry->h + 1) % macroblock_height == 0 ) ? 0 : 1 ; + int left_mb = ( boundry->x + macroblock_width - 1 ) / macroblock_width; + int top_mb = ( boundry->y + macroblock_height - 1 ) / macroblock_height; + int right_mb = ( boundry->x + boundry->w ) / macroblock_width - 1; + int bottom_mb = ( boundry->y + boundry->h ) / macroblock_height - 1; int i, j, n = 0; @@ -157,38 +60,50 @@ void caculate_motion( struct motion_vector_s *vectors, #define CURRENT ( vectors + j*mv_buffer_width + i ) for( i = left_mb; i <= right_mb; i++ ){ - for( j = top_mb; j <= bottom_mb; j++ ){ - + for( j = top_mb; j <= bottom_mb; j++ ) + { n++; - average_x += CURRENT->dx; average_y += CURRENT->dy; } } - if ( n == 0 ) - return; + if ( n == 0 ) return; average_x /= n; average_y /= n; + n = 0; int average2_x = 0, average2_y = 0; for( i = left_mb; i <= right_mb; i++ ){ for( j = top_mb; j <= bottom_mb; j++ ){ - if( ABS(CURRENT->dx - average_x) < 5 && - ABS(CURRENT->dy - average_y) < 5 ) + if( ABS(CURRENT->dx - average_x) < 3 && + ABS(CURRENT->dy - average_y) < 3 ) { + n++; average2_x += CURRENT->dx; average2_y += CURRENT->dy; } } } - - boundry->x -= average2_x/n; - boundry->y -= average2_y/n; + if ( n == 0 ) return; + + boundry->x -= (double)average2_x / (double)n; + boundry->y -= (double)average2_y / (double)n; + + if ( boundry->x < 0 ) + boundry->x = 0; + if ( boundry->y < 0 ) + boundry->y = 0; + + if ( boundry->x + boundry->w > width ) + boundry->x = width - boundry->w; + + if ( boundry->y + boundry->h > height ) + boundry->y = height - boundry->h; } // Image stack(able) method @@ -214,18 +129,19 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr ); // Get the geometry object - mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL); + mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); // Get the current geometry item struct mlt_geometry_item_s boundry; mlt_geometry_fetch(geometry, &boundry, position); -//fprintf(stderr, "process %d\n", position); // Get the motion vectors struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL ); - + // How did the rectangle move? - if( vectors != NULL ) { + if( vectors != NULL && + boundry.key != 1 ) // Paused? + { int method = mlt_properties_get_int( filter_properties, "method" ); @@ -234,45 +150,44 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" ); int mv_buffer_width = *width / macroblock_width; - caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method ); - - } - - boundry.key = 1; + caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method, *width, *height ); - boundry.f[0] = 1; - boundry.f[1] = 1; - boundry.f[2] = 1; - boundry.f[3] = 1; - boundry.f[4] = 1; -// boundry.frame = position; - - mlt_geometry_insert(geometry, &boundry); + // Make the geometry object a real boy + boundry.key = 1; + boundry.f[0] = 1; + boundry.f[1] = 1; + boundry.f[2] = 1; + boundry.f[3] = 1; + boundry.f[4] = 1; + mlt_geometry_insert(geometry, &boundry); + } + if( mlt_properties_get_int( filter_properties, "debug" ) == 1 ) + { + init_arrows( format, *width, *height ); + draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100); + } - if( mlt_properties_get_int( filter_properties, "debug" ) == 1 ) + if( mlt_properties_get_int( filter_properties, "obscure" ) == 1 ) { - int xstep, ystep; - - // Calculate the size of our steps (the number of bytes that seperate adjacent pixels in X and Y direction) - switch( *format ) { - case mlt_image_yuv422: - xstep = 2; - ystep = xstep * *width; - break; - default: - // I don't know - return -1; - break; - } + mlt_filter obscure = mlt_properties_get_data( filter_properties, "_obscure", NULL ); - draw_line(*image, boundry.x, boundry.y, boundry.x, boundry.y + boundry.h, *width, *height, xstep, ystep, 0xff); - draw_line(*image, boundry.x, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y + boundry.h, *width, *height, xstep, ystep, 0xff); - draw_line(*image, boundry.x + boundry.w, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y, *width, *height, xstep, ystep, 0xff); - draw_line(*image, boundry.x + boundry.w, boundry.y, boundry.x, boundry.y, *width, *height, xstep, ystep, 0xff); + mlt_properties_pass_list( MLT_FILTER_PROPERTIES(obscure), filter_properties, "in, out"); + // Because filter_obscure needs to be rewritten to use mlt_geometry + char geom[100]; + sprintf( geom, "%d,%d:%dx%d", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h ); + mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "start", geom ); + mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "end", geom ); } + + if( mlt_properties_get_int( filter_properties, "collect" ) == 1 ) + { + printf( "%d,%d,%d,%d\n", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h ); + fflush( stdout ); + } + return error; } @@ -289,14 +204,29 @@ static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_ // Get the frame position mlt_position position = mlt_frame_get_position( frame ); + + // Get the geometry object + mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); + if (geometry == NULL) { + mlt_geometry geom = mlt_geometry_init(); + char *arg = mlt_properties_get(filter_properties, "geometry"); + + // Initialize with the supplied geometry + struct mlt_geometry_item_s item; + mlt_geometry_parse_item( geom, &item, arg ); - // gEt the geometry object - mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL); + item.frame = 0; + item.key = 1; + item.mix = 100; + + mlt_geometry_insert( geom, &item ); + mlt_properties_set_data( filter_properties, "filter_geometry", geom, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise ); + geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); + } // Get the current geometry item mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) ); mlt_geometry_fetch(geometry, geometry_item, position); -//fprintf(stderr, "attach %d\n", position); mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL ); @@ -315,9 +245,6 @@ static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { - //mlt_properties_debug(MLT_SERVICE_PROPERTIES(mlt_service_consumer(mlt_filter_service(this))), "consumer!", stderr); - - /* modify the frame with the current geometry */ mlt_frame_push_service( frame, this); mlt_frame_push_get_image( frame, attach_boundry_to_frame ); @@ -339,14 +266,28 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 ) { mlt_filter vismv = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_vismv", NULL ); - if( vismv == NULL ) { - vismv = mlt_factory_filter( "vismv", NULL ); + if( vismv == NULL ) + { + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); + vismv = mlt_factory_filter( profile, "vismv", NULL ); mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL ); } mlt_filter_process( vismv, frame ); } + if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "obscure" ) == 1 ) + { + mlt_filter obscure = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_obscure", NULL ); + if( obscure == NULL ) + { + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); + obscure = mlt_factory_filter( profile, "obscure", NULL ); + mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_obscure", obscure, 0, (mlt_destructor)mlt_filter_close, NULL ); + } + + mlt_filter_process( obscure, frame ); + } return frame; } @@ -355,34 +296,21 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) */ -mlt_filter filter_autotrack_rectangle_init( char *arg ) +mlt_filter filter_autotrack_rectangle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { this->process = filter_process; + // Initialize with the supplied geometry if ther is one + if( arg != NULL ) + mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", arg ); + else + mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", "100,100:100x100" ); - mlt_geometry geometry = mlt_geometry_init(); - - // Initialize with the supplied geometry - if( arg != NULL ) { - - struct mlt_geometry_item_s item; - - mlt_geometry_parse_item( geometry, &item, arg ); - - item.frame = 0; - item.key = 1; - item.mix = 100; - - mlt_geometry_insert( geometry, &item ); - - } - - mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "geometry", geometry, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise ); - - mlt_filter motion_est = mlt_factory_filter("motion_est", NULL); + // create an instance of the motion_est and obscure filter + mlt_filter motion_est = mlt_factory_filter( profile, "motion_est", NULL ); if( motion_est != NULL ) mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est, 0, (mlt_destructor)mlt_filter_close, NULL ); else { @@ -390,8 +318,7 @@ mlt_filter filter_autotrack_rectangle_init( char *arg ) return NULL; } - //mlt_events_init( this ); - //mlt_events_listen(mlt_service_consumer(mlt_filter_service(this) + } return this;