📄 gradient.c
字号:
/***************************************************************************** * gradient.c : Gradient and edge detection video effects plugin for vlc ***************************************************************************** * Copyright (C) 2000-2008 the VideoLAN team * $Id: f1c57cdeefe761bdfa96ba2b255b5f1bf54c1f56 $ * * Authors: Samuel Hocevar <sam@zoy.org> * Antoine Cellerier <dionoea -at- videolan -dot- org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <math.h> /* sin(), cos() */#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_sout.h>#include <vlc_vout.h>#include "vlc_filter.h"#include "filter_picture.h"enum { GRADIENT, EDGE, HOUGH };/***************************************************************************** * Local prototypes *****************************************************************************/static int Create ( vlc_object_t * );static void Destroy ( vlc_object_t * );static picture_t *Filter( filter_t *, picture_t * );static int GradientCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static void FilterGradient( filter_t *, picture_t *, picture_t * );static void FilterEdge ( filter_t *, picture_t *, picture_t * );static void FilterHough ( filter_t *, picture_t *, picture_t * );/***************************************************************************** * Module descriptor *****************************************************************************/#define MODE_TEXT N_("Distort mode")#define MODE_LONGTEXT N_("Distort mode, one of \"gradient\", \"edge\" and \"hough\".")#define GRADIENT_TEXT N_("Gradient image type")#define GRADIENT_LONGTEXT N_("Gradient image type (0 or 1). 0 will " \ "turn the image to white while 1 will keep colors." )#define CARTOON_TEXT N_("Apply cartoon effect")#define CARTOON_LONGTEXT N_("Apply cartoon effect. It is only used by " \ "\"gradient\" and \"edge\".")static const char *const mode_list[] = { "gradient", "edge", "hough" };static const char *const mode_list_text[] = { N_("Gradient"), N_("Edge"), N_("Hough") };#define FILTER_PREFIX "gradient-"vlc_module_begin(); set_description( N_("Gradient video filter") ); set_shortname( N_( "Gradient" )); set_capability( "video filter2", 0 ); set_category( CAT_VIDEO ); set_subcategory( SUBCAT_VIDEO_VFILTER ); add_string( FILTER_PREFIX "mode", "gradient", NULL, MODE_TEXT, MODE_LONGTEXT, false ); change_string_list( mode_list, mode_list_text, 0 ); add_integer_with_range( FILTER_PREFIX "type", 0, 0, 1, NULL, GRADIENT_TEXT, GRADIENT_LONGTEXT, false ); add_bool( FILTER_PREFIX "cartoon", 1, NULL, CARTOON_TEXT, CARTOON_LONGTEXT, false ); add_shortcut( "gradient" ); set_callbacks( Create, Destroy );vlc_module_end();static const char *const ppsz_filter_options[] = { "mode", "type", "cartoon", NULL};/***************************************************************************** * vout_sys_t: Distort video output method descriptor ***************************************************************************** * This structure is part of the video output thread descriptor. * It describes the Distort specific properties of an output thread. *****************************************************************************/struct filter_sys_t{ int i_mode; /* For the gradient mode */ int i_gradient_type; bool b_cartoon; uint32_t *p_buf32; uint32_t *p_buf32_bis; uint8_t *p_buf8; /* For hough mode */ int *p_pre_hough;};/***************************************************************************** * Create: allocates Distort video thread output method ***************************************************************************** * This function allocates and initializes a Distort vout method. *****************************************************************************/static int Create( vlc_object_t *p_this ){ filter_t *p_filter = (filter_t *)p_this; char *psz_method; switch( p_filter->fmt_in.video.i_chroma ) { CASE_PLANAR_YUV break; default: msg_Err( p_filter, "Unsupported input chroma (%4s)", (char*)&(p_filter->fmt_in.video.i_chroma) ); return VLC_EGENERIC; } /* Allocate structure */ p_filter->p_sys = malloc( sizeof( filter_sys_t ) ); if( p_filter->p_sys == NULL ) return VLC_ENOMEM; p_filter->pf_video_filter = Filter; p_filter->p_sys->p_pre_hough = NULL; config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options, p_filter->p_cfg ); if( !(psz_method = var_CreateGetNonEmptyStringCommand( p_filter, FILTER_PREFIX "mode" )) ) { msg_Err( p_filter, "configuration variable " FILTER_PREFIX "mode empty" ); p_filter->p_sys->i_mode = GRADIENT; } else { if( !strcmp( psz_method, "gradient" ) ) { p_filter->p_sys->i_mode = GRADIENT; } else if( !strcmp( psz_method, "edge" ) ) { p_filter->p_sys->i_mode = EDGE; } else if( !strcmp( psz_method, "hough" ) ) { p_filter->p_sys->i_mode = HOUGH; } else { msg_Err( p_filter, "no valid gradient mode provided (%s)", psz_method ); p_filter->p_sys->i_mode = GRADIENT; } } free( psz_method ); p_filter->p_sys->i_gradient_type = var_CreateGetIntegerCommand( p_filter, FILTER_PREFIX "type" ); p_filter->p_sys->b_cartoon = var_CreateGetBoolCommand( p_filter, FILTER_PREFIX "cartoon" ); var_AddCallback( p_filter, FILTER_PREFIX "mode", GradientCallback, p_filter->p_sys ); var_AddCallback( p_filter, FILTER_PREFIX "type", GradientCallback, p_filter->p_sys ); var_AddCallback( p_filter, FILTER_PREFIX "cartoon", GradientCallback, p_filter->p_sys ); p_filter->p_sys->p_buf32 = NULL; p_filter->p_sys->p_buf32_bis = NULL; p_filter->p_sys->p_buf8 = NULL; return VLC_SUCCESS;}/***************************************************************************** * Destroy: destroy Distort video thread output method ***************************************************************************** * Terminate an output method created by DistortCreateOutputMethod *****************************************************************************/static void Destroy( vlc_object_t *p_this ){ filter_t *p_filter = (filter_t *)p_this; free( p_filter->p_sys->p_buf32 ); free( p_filter->p_sys->p_buf32_bis ); free( p_filter->p_sys->p_buf8 ); free( p_filter->p_sys->p_pre_hough ); free( p_filter->p_sys );}/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Distort image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ){ picture_t *p_outpic; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } switch( p_filter->p_sys->i_mode ) { case EDGE: FilterEdge( p_filter, p_pic, p_outpic ); break; case GRADIENT: FilterGradient( p_filter, p_pic, p_outpic ); break; case HOUGH: FilterHough( p_filter, p_pic, p_outpic ); break; default: break; } return CopyInfoAndRelease( p_outpic, p_pic );}/***************************************************************************** * Gaussian Convolution ***************************************************************************** * Gaussian convolution ( sigma == 1.4 ) * * | 2 4 5 4 2 | | 2 4 4 4 2 | * | 4 9 12 9 4 | | 4 8 12 8 4 | * | 5 12 15 12 5 | ~ | 4 12 16 12 4 | * | 4 9 12 9 4 | | 4 8 12 8 4 | * | 2 4 5 4 2 | | 2 4 4 4 2 | *****************************************************************************/static void GaussianConvolution( picture_t *p_inpic, uint32_t *p_smooth ){ const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels; const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch; const int i_src_visible = p_inpic->p[Y_PLANE].i_visible_pitch; const int i_num_lines = p_inpic->p[Y_PLANE].i_visible_lines; int x,y; for( y = 2; y < i_num_lines - 2; y++ ) { for( x = 2; x < i_src_visible - 2; x++ ) { p_smooth[y*i_src_visible+x] = (uint32_t)( /* 2 rows up */ ( p_inpix[(y-2)*i_src_pitch+x-2] ) + ((p_inpix[(y-2)*i_src_pitch+x-1] + p_inpix[(y-2)*i_src_pitch+x] + p_inpix[(y-2)*i_src_pitch+x+1])<<1 ) + ( p_inpix[(y-2)*i_src_pitch+x+2] ) /* 1 row up */ + ((p_inpix[(y-1)*i_src_pitch+x-2] + ( p_inpix[(y-1)*i_src_pitch+x-1]<<1 ) + ( p_inpix[(y-1)*i_src_pitch+x]*3 ) + ( p_inpix[(y-1)*i_src_pitch+x+1]<<1 ) + p_inpix[(y-1)*i_src_pitch+x+2] /* */ + p_inpix[y*i_src_pitch+x-2] + ( p_inpix[y*i_src_pitch+x-1]*3 ) + ( p_inpix[y*i_src_pitch+x]<<2 ) + ( p_inpix[y*i_src_pitch+x+1]*3 ) + p_inpix[y*i_src_pitch+x+2] /* 1 row down */ + p_inpix[(y+1)*i_src_pitch+x-2] + ( p_inpix[(y+1)*i_src_pitch+x-1]<<1 ) + ( p_inpix[(y+1)*i_src_pitch+x]*3 ) + ( p_inpix[(y+1)*i_src_pitch+x+1]<<1 ) + p_inpix[(y+1)*i_src_pitch+x+2] )<<1 ) /* 2 rows down */ + ( p_inpix[(y+2)*i_src_pitch+x-2] ) + ((p_inpix[(y+2)*i_src_pitch+x-1] + p_inpix[(y+2)*i_src_pitch+x] + p_inpix[(y+2)*i_src_pitch+x+1])<<1 ) + ( p_inpix[(y+2)*i_src_pitch+x+2] ) ) >> 6 /* 115 */; } }}/***************************************************************************** * FilterGradient: Sobel *****************************************************************************/static void FilterGradient( filter_t *p_filter, picture_t *p_inpic, picture_t *p_outpic ){ int x, y; const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch; const int i_src_visible = p_inpic->p[Y_PLANE].i_visible_pitch; const int i_dst_pitch = p_outpic->p[Y_PLANE].i_pitch; const int i_num_lines = p_inpic->p[Y_PLANE].i_visible_lines; const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels; uint8_t *p_outpix = p_outpic->p[Y_PLANE].p_pixels; uint32_t *p_smooth; if( !p_filter->p_sys->p_buf32 ) p_filter->p_sys->p_buf32 = (uint32_t *)malloc( i_num_lines * i_src_visible * sizeof(uint32_t)); p_smooth = p_filter->p_sys->p_buf32; if( !p_smooth ) return; if( p_filter->p_sys->b_cartoon ) { vlc_memcpy( p_outpic->p[U_PLANE].p_pixels, p_inpic->p[U_PLANE].p_pixels, p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch ); vlc_memcpy( p_outpic->p[V_PLANE].p_pixels, p_inpic->p[V_PLANE].p_pixels, p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch ); } else { vlc_memset( p_outpic->p[U_PLANE].p_pixels, 0x80, p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch ); vlc_memset( p_outpic->p[V_PLANE].p_pixels, 0x80, p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch ); } GaussianConvolution( p_inpic, p_smooth ); /* Sobel gradient | -1 0 1 | | 1 2 1 | | -2 0 2 | and | 0 0 0 | | -1 0 1 | | -1 -2 -1 | */#define FOR \ for( y = 1; y < i_num_lines - 1; y++ ) \ { \ for( x = 1; x < i_src_visible - 1; x++ ) \ { \ const uint32_t a = \ ( \ abs( \ ( p_smooth[(y-1)*i_src_visible+x-1] \ - p_smooth[(y+1)*i_src_visible+x-1] ) \ + ( ( p_smooth[(y-1)*i_src_visible+x] \ - p_smooth[(y+1)*i_src_visible+x] ) <<1 ) \ + ( p_smooth[(y-1)*i_src_visible+x+1] \ - p_smooth[(y+1)*i_src_visible+x+1] ) \ ) \ + \ abs( \ ( p_smooth[(y-1)*i_src_visible+x-1] \ - p_smooth[(y-1)*i_src_visible+x+1] ) \ + ( ( p_smooth[y*i_src_visible+x-1] \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -