gradient.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:29k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * gradient.c : Gradient and edge detection video effects plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2008 the VideoLAN team
  5.  * $Id: 948cb4a04d318256b720203ed6ea0e8b54698f02 $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Antoine Cellerier <dionoea -at- videolan -dot- org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <math.h>                                            /* sin(), cos() */
  31. #include <vlc_common.h>
  32. #include <vlc_plugin.h>
  33. #include <vlc_sout.h>
  34. #include <vlc_vout.h>
  35. #include "vlc_filter.h"
  36. #include "filter_picture.h"
  37. enum { GRADIENT, EDGE, HOUGH };
  38. /*****************************************************************************
  39.  * Local prototypes
  40.  *****************************************************************************/
  41. static int  Create    ( vlc_object_t * );
  42. static void Destroy   ( vlc_object_t * );
  43. static picture_t *Filter( filter_t *, picture_t * );
  44. static int GradientCallback( vlc_object_t *, char const *,
  45.                              vlc_value_t, vlc_value_t,
  46.                              void * );
  47. static void FilterGradient( filter_t *, picture_t *, picture_t * );
  48. static void FilterEdge    ( filter_t *, picture_t *, picture_t * );
  49. static void FilterHough   ( filter_t *, picture_t *, picture_t * );
  50. /*****************************************************************************
  51.  * Module descriptor
  52.  *****************************************************************************/
  53. #define MODE_TEXT N_("Distort mode")
  54. #define MODE_LONGTEXT N_("Distort mode, one of "gradient", "edge" and "hough".")
  55. #define GRADIENT_TEXT N_("Gradient image type")
  56. #define GRADIENT_LONGTEXT N_("Gradient image type (0 or 1). 0 will " 
  57.         "turn the image to white while 1 will keep colors." )
  58. #define CARTOON_TEXT N_("Apply cartoon effect")
  59. #define CARTOON_LONGTEXT N_("Apply cartoon effect. It is only used by " 
  60.     ""gradient" and "edge".")
  61. static const char *const mode_list[] = { "gradient", "edge", "hough" };
  62. static const char *const mode_list_text[] = { N_("Gradient"), N_("Edge"), N_("Hough") };
  63. #define FILTER_PREFIX "gradient-"
  64. vlc_module_begin ()
  65.     set_description( N_("Gradient video filter") )
  66.     set_shortname( N_( "Gradient" ))
  67.     set_capability( "video filter2", 0 )
  68.     set_category( CAT_VIDEO )
  69.     set_subcategory( SUBCAT_VIDEO_VFILTER )
  70.     add_string( FILTER_PREFIX "mode", "gradient", NULL,
  71.                 MODE_TEXT, MODE_LONGTEXT, false )
  72.         change_string_list( mode_list, mode_list_text, 0 )
  73.     add_integer_with_range( FILTER_PREFIX "type", 0, 0, 1, NULL,
  74.                 GRADIENT_TEXT, GRADIENT_LONGTEXT, false )
  75.     add_bool( FILTER_PREFIX "cartoon", 1, NULL,
  76.                 CARTOON_TEXT, CARTOON_LONGTEXT, false )
  77.     add_shortcut( "gradient" )
  78.     set_callbacks( Create, Destroy )
  79. vlc_module_end ()
  80. static const char *const ppsz_filter_options[] = {
  81.     "mode", "type", "cartoon", NULL
  82. };
  83. /*****************************************************************************
  84.  * filter_sys_t: Distort video output method descriptor
  85.  *****************************************************************************
  86.  * This structure is part of the video output thread descriptor.
  87.  * It describes the Distort specific properties of an output thread.
  88.  *****************************************************************************/
  89. struct filter_sys_t
  90. {
  91.     vlc_mutex_t lock;
  92.     int i_mode;
  93.     /* For the gradient mode */
  94.     int i_gradient_type;
  95.     bool b_cartoon;
  96.     uint32_t *p_buf32;
  97.     uint32_t *p_buf32_bis;
  98.     uint8_t *p_buf8;
  99.     /* For hough mode */
  100.     int *p_pre_hough;
  101. };
  102. /*****************************************************************************
  103.  * Create: allocates Distort video thread output method
  104.  *****************************************************************************
  105.  * This function allocates and initializes a Distort vout method.
  106.  *****************************************************************************/
  107. static int Create( vlc_object_t *p_this )
  108. {
  109.     filter_t *p_filter = (filter_t *)p_this;
  110.     char *psz_method;
  111.     switch( p_filter->fmt_in.video.i_chroma )
  112.     {
  113.         CASE_PLANAR_YUV
  114.             break;
  115.         default:
  116.              msg_Err( p_filter, "Unsupported input chroma (%4s)",
  117.                       (char*)&(p_filter->fmt_in.video.i_chroma) );
  118.             return VLC_EGENERIC;
  119.     }
  120.     /* Allocate structure */
  121.     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
  122.     if( p_filter->p_sys == NULL )
  123.         return VLC_ENOMEM;
  124.     p_filter->pf_video_filter = Filter;
  125.     p_filter->p_sys->p_pre_hough = NULL;
  126.     config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options,
  127.                    p_filter->p_cfg );
  128.     if( !(psz_method =
  129.         var_CreateGetNonEmptyStringCommand( p_filter, FILTER_PREFIX "mode" )) )
  130.     {
  131.         msg_Err( p_filter, "configuration variable "
  132.                  FILTER_PREFIX "mode empty" );
  133.         p_filter->p_sys->i_mode = GRADIENT;
  134.     }
  135.     else
  136.     {
  137.         if( !strcmp( psz_method, "gradient" ) )
  138.         {
  139.             p_filter->p_sys->i_mode = GRADIENT;
  140.         }
  141.         else if( !strcmp( psz_method, "edge" ) )
  142.         {
  143.             p_filter->p_sys->i_mode = EDGE;
  144.         }
  145.         else if( !strcmp( psz_method, "hough" ) )
  146.         {
  147.             p_filter->p_sys->i_mode = HOUGH;
  148.         }
  149.         else
  150.         {
  151.             msg_Err( p_filter, "no valid gradient mode provided (%s)", psz_method );
  152.             p_filter->p_sys->i_mode = GRADIENT;
  153.         }
  154.     }
  155.     free( psz_method );
  156.     p_filter->p_sys->i_gradient_type =
  157.         var_CreateGetIntegerCommand( p_filter, FILTER_PREFIX "type" );
  158.     p_filter->p_sys->b_cartoon =
  159.         var_CreateGetBoolCommand( p_filter, FILTER_PREFIX "cartoon" );
  160.     vlc_mutex_init( &p_filter->p_sys->lock );
  161.     var_AddCallback( p_filter, FILTER_PREFIX "mode",
  162.                      GradientCallback, p_filter->p_sys );
  163.     var_AddCallback( p_filter, FILTER_PREFIX "type",
  164.                      GradientCallback, p_filter->p_sys );
  165.     var_AddCallback( p_filter, FILTER_PREFIX "cartoon",
  166.                      GradientCallback, p_filter->p_sys );
  167.     p_filter->p_sys->p_buf32 = NULL;
  168.     p_filter->p_sys->p_buf32_bis = NULL;
  169.     p_filter->p_sys->p_buf8 = NULL;
  170.     return VLC_SUCCESS;
  171. }
  172. /*****************************************************************************
  173.  * Destroy: destroy Distort video thread output method
  174.  *****************************************************************************
  175.  * Terminate an output method created by DistortCreateOutputMethod
  176.  *****************************************************************************/
  177. static void Destroy( vlc_object_t *p_this )
  178. {
  179.     filter_t *p_filter = (filter_t *)p_this;
  180.     filter_sys_t *p_sys = p_filter->p_sys;
  181.     var_DelCallback( p_filter, FILTER_PREFIX "mode",
  182.                      GradientCallback, p_sys );
  183.     var_DelCallback( p_filter, FILTER_PREFIX "type",
  184.                      GradientCallback, p_sys );
  185.     var_DelCallback( p_filter, FILTER_PREFIX "cartoon",
  186.                      GradientCallback, p_sys );
  187.     vlc_mutex_destroy( &p_sys->lock );
  188.     free( p_sys->p_buf32 );
  189.     free( p_sys->p_buf32_bis );
  190.     free( p_sys->p_buf8 );
  191.     free( p_sys->p_pre_hough );
  192.     free( p_sys );
  193. }
  194. /*****************************************************************************
  195.  * Render: displays previously rendered output
  196.  *****************************************************************************
  197.  * This function send the currently rendered image to Distort image, waits
  198.  * until it is displayed and switch the two rendering buffers, preparing next
  199.  * frame.
  200.  *****************************************************************************/
  201. static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
  202. {
  203.     picture_t *p_outpic;
  204.     if( !p_pic ) return NULL;
  205.     p_outpic = filter_NewPicture( p_filter );
  206.     if( !p_outpic )
  207.     {
  208.         picture_Release( p_pic );
  209.         return NULL;
  210.     }
  211.     vlc_mutex_lock( &p_filter->p_sys->lock );
  212.     switch( p_filter->p_sys->i_mode )
  213.     {
  214.         case EDGE:
  215.             FilterEdge( p_filter, p_pic, p_outpic );
  216.             break;
  217.         case GRADIENT:
  218.             FilterGradient( p_filter, p_pic, p_outpic );
  219.             break;
  220.         case HOUGH:
  221.             FilterHough( p_filter, p_pic, p_outpic );
  222.             break;
  223.         default:
  224.             break;
  225.     }
  226.     vlc_mutex_unlock( &p_filter->p_sys->lock );
  227.     return CopyInfoAndRelease( p_outpic, p_pic );
  228. }
  229. /*****************************************************************************
  230.  * Gaussian Convolution
  231.  *****************************************************************************
  232.  *    Gaussian convolution ( sigma == 1.4 )
  233.  *
  234.  *    |  2  4  5  4  2  |   |  2  4  4  4  2 |
  235.  *    |  4  9 12  9  4  |   |  4  8 12  8  4 |
  236.  *    |  5 12 15 12  5  | ~ |  4 12 16 12  4 |
  237.  *    |  4  9 12  9  4  |   |  4  8 12  8  4 |
  238.  *    |  2  4  5  4  2  |   |  2  4  4  4  2 |
  239.  *****************************************************************************/
  240. static void GaussianConvolution( picture_t *p_inpic, uint32_t *p_smooth )
  241. {
  242.     const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
  243.     const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch;
  244.     const int i_src_visible = p_inpic->p[Y_PLANE].i_visible_pitch;
  245.     const int i_num_lines = p_inpic->p[Y_PLANE].i_visible_lines;
  246.     int x,y;
  247.     for( y = 2; y < i_num_lines - 2; y++ )
  248.     {
  249.         for( x = 2; x < i_src_visible - 2; x++ )
  250.         {
  251.             p_smooth[y*i_src_visible+x] = (uint32_t)(
  252.               /* 2 rows up */
  253.                 ( p_inpix[(y-2)*i_src_pitch+x-2] )
  254.               + ((p_inpix[(y-2)*i_src_pitch+x-1]
  255.               +   p_inpix[(y-2)*i_src_pitch+x]
  256.               +   p_inpix[(y-2)*i_src_pitch+x+1])<<1 )
  257.               + ( p_inpix[(y-2)*i_src_pitch+x+2] )
  258.               /* 1 row up */
  259.               + ((p_inpix[(y-1)*i_src_pitch+x-2]
  260.               + ( p_inpix[(y-1)*i_src_pitch+x-1]<<1 )
  261.               + ( p_inpix[(y-1)*i_src_pitch+x]*3 )
  262.               + ( p_inpix[(y-1)*i_src_pitch+x+1]<<1 )
  263.               +   p_inpix[(y-1)*i_src_pitch+x+2]
  264.               /* */
  265.               +   p_inpix[y*i_src_pitch+x-2]
  266.               + ( p_inpix[y*i_src_pitch+x-1]*3 )
  267.               + ( p_inpix[y*i_src_pitch+x]<<2 )
  268.               + ( p_inpix[y*i_src_pitch+x+1]*3 )
  269.               +   p_inpix[y*i_src_pitch+x+2]
  270.               /* 1 row down */
  271.               +   p_inpix[(y+1)*i_src_pitch+x-2]
  272.               + ( p_inpix[(y+1)*i_src_pitch+x-1]<<1 )
  273.               + ( p_inpix[(y+1)*i_src_pitch+x]*3 )
  274.               + ( p_inpix[(y+1)*i_src_pitch+x+1]<<1 )
  275.               +   p_inpix[(y+1)*i_src_pitch+x+2] )<<1 )
  276.               /* 2 rows down */
  277.               + ( p_inpix[(y+2)*i_src_pitch+x-2] )
  278.               + ((p_inpix[(y+2)*i_src_pitch+x-1]
  279.               +   p_inpix[(y+2)*i_src_pitch+x]
  280.               +   p_inpix[(y+2)*i_src_pitch+x+1])<<1 )
  281.               + ( p_inpix[(y+2)*i_src_pitch+x+2] )
  282.               ) >> 6 /* 115 */;
  283.         }
  284.     }
  285. }
  286. /*****************************************************************************
  287.  * FilterGradient: Sobel
  288.  *****************************************************************************/
  289. static void FilterGradient( filter_t *p_filter, picture_t *p_inpic,
  290.                                                 picture_t *p_outpic )
  291. {
  292.     int x, y;
  293.     const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch;
  294.     const int i_src_visible = p_inpic->p[Y_PLANE].i_visible_pitch;
  295.     const int i_dst_pitch = p_outpic->p[Y_PLANE].i_pitch;
  296.     const int i_num_lines = p_inpic->p[Y_PLANE].i_visible_lines;
  297.     const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
  298.     uint8_t *p_outpix = p_outpic->p[Y_PLANE].p_pixels;
  299.     uint32_t *p_smooth;
  300.     if( !p_filter->p_sys->p_buf32 )
  301.         p_filter->p_sys->p_buf32 =
  302.         (uint32_t *)malloc( i_num_lines * i_src_visible * sizeof(uint32_t));
  303.     p_smooth = p_filter->p_sys->p_buf32;
  304.     if( !p_smooth ) return;
  305.     if( p_filter->p_sys->b_cartoon )
  306.     {
  307.         vlc_memcpy( p_outpic->p[U_PLANE].p_pixels,
  308.             p_inpic->p[U_PLANE].p_pixels,
  309.             p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
  310.         vlc_memcpy( p_outpic->p[V_PLANE].p_pixels,
  311.             p_inpic->p[V_PLANE].p_pixels,
  312.             p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
  313.     }
  314.     else
  315.     {
  316.         vlc_memset( p_outpic->p[U_PLANE].p_pixels, 0x80,
  317.             p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
  318.         vlc_memset( p_outpic->p[V_PLANE].p_pixels, 0x80,
  319.             p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
  320.     }
  321.     GaussianConvolution( p_inpic, p_smooth );
  322.     /* Sobel gradient
  323.      | -1 0 1 |     |  1  2  1 |
  324.      | -2 0 2 | and |  0  0  0 |
  325.      | -1 0 1 |     | -1 -2 -1 | */
  326. #define FOR                                                     
  327.     for( y = 1; y < i_num_lines - 1; y++ )                      
  328.     {                                                           
  329.         for( x = 1; x < i_src_visible - 1; x++ )                
  330.         {                                                       
  331.             const uint32_t a =                                  
  332.             (                                                   
  333.               abs(                                              
  334.                  ( p_smooth[(y-1)*i_src_visible+x-1]            
  335.                    - p_smooth[(y+1)*i_src_visible+x-1] )        
  336.                + ( ( p_smooth[(y-1)*i_src_visible+x]            
  337.                     - p_smooth[(y+1)*i_src_visible+x] ) <<1 )   
  338.                + ( p_smooth[(y-1)*i_src_visible+x+1]            
  339.                    - p_smooth[(y+1)*i_src_visible+x+1] )        
  340.               )                                                 
  341.             +                                                   
  342.               abs(                                              
  343.                  ( p_smooth[(y-1)*i_src_visible+x-1]            
  344.                    - p_smooth[(y-1)*i_src_visible+x+1] )        
  345.                + ( ( p_smooth[y*i_src_visible+x-1]              
  346.                     - p_smooth[y*i_src_visible+x+1] ) <<1 )     
  347.                + ( p_smooth[(y+1)*i_src_visible+x-1]            
  348.                    - p_smooth[(y+1)*i_src_visible+x+1] )        
  349.               )                                                 
  350.             );
  351.     if( p_filter->p_sys->i_gradient_type )
  352.     {
  353.         if( p_filter->p_sys->b_cartoon )
  354.         {
  355.             FOR
  356.             if( a > 60 )
  357.             {
  358.                 p_outpix[y*i_dst_pitch+x] = 0x00;
  359.             }
  360.             else
  361.             {
  362.                 if( p_smooth[y*i_src_visible+x] > 0xa0 )
  363.                     p_outpix[y*i_dst_pitch+x] =
  364.                         0xff - ((0xff - p_inpix[y*i_src_pitch+x] )>>2);
  365.                 else if( p_smooth[y*i_src_visible+x] > 0x70 )
  366.                     p_outpix[y*i_dst_pitch+x] =
  367.                         0xa0 - ((0xa0 - p_inpix[y*i_src_pitch+x] )>>2);
  368.                 else if( p_smooth[y*i_src_visible+x] > 0x28 )
  369.                     p_outpix[y*i_dst_pitch+x] =
  370.                         0x70 - ((0x70 - p_inpix[y*i_src_pitch+x] )>>2);
  371.                 else
  372.                     p_outpix[y*i_dst_pitch+x] =
  373.                         0x28 - ((0x28 - p_inpix[y*i_src_pitch+x] )>>2);
  374.             }
  375.             }}
  376.         }
  377.         else
  378.         {
  379.             FOR
  380.             p_outpix[y*i_dst_pitch+x] = clip_uint8_vlc( a );
  381.             }}
  382.         }
  383.     }
  384.     else
  385.     {
  386.         FOR
  387.         if( a>>8 )
  388.             p_outpix[y*i_dst_pitch+x] = 0;
  389.         else
  390.             p_outpix[y*i_dst_pitch+x] = 0xff-(uint8_t)a;
  391.         }}
  392.     }
  393. #undef FOR
  394. }
  395. /*****************************************************************************
  396.  * FilterEdge: Canny edge detection algorithm
  397.  *****************************************************************************
  398.  * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
  399.  * (well ... my implementation isn't really the canny algorithm ... but some
  400.  * ideas are the same)
  401.  *****************************************************************************/
  402. /* angle : | */
  403. #define THETA_Y 0
  404. /* angle : - */
  405. #define THETA_X 1
  406. /* angle : / */
  407. #define THETA_P 2
  408. /* angle :  */
  409. #define THETA_M 3
  410. static void FilterEdge( filter_t *p_filter, picture_t *p_inpic,
  411.                                             picture_t *p_outpic )
  412. {
  413.     int x, y;
  414.     const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch;
  415.     const int i_src_visible = p_inpic->p[Y_PLANE].i_visible_pitch;
  416.     const int i_dst_pitch = p_outpic->p[Y_PLANE].i_pitch;
  417.     const int i_num_lines = p_inpic->p[Y_PLANE].i_visible_lines;
  418.     const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
  419.     uint8_t *p_outpix = p_outpic->p[Y_PLANE].p_pixels;
  420.     uint32_t *p_smooth;
  421.     uint32_t *p_grad;
  422.     uint8_t *p_theta;
  423.     if( !p_filter->p_sys->p_buf32 )
  424.         p_filter->p_sys->p_buf32 =
  425.         (uint32_t *)malloc( i_num_lines * i_src_visible * sizeof(uint32_t));
  426.     p_smooth = p_filter->p_sys->p_buf32;
  427.     if( !p_filter->p_sys->p_buf32_bis )
  428.         p_filter->p_sys->p_buf32_bis =
  429.         (uint32_t *)malloc( i_num_lines * i_src_visible * sizeof(uint32_t));
  430.     p_grad = p_filter->p_sys->p_buf32_bis;
  431.     if( !p_filter->p_sys->p_buf8 )
  432.         p_filter->p_sys->p_buf8 =
  433.         (uint8_t *)malloc( i_num_lines * i_src_visible * sizeof(uint8_t));
  434.     p_theta = p_filter->p_sys->p_buf8;
  435.     if( !p_smooth || !p_grad || !p_theta ) return;
  436.     if( p_filter->p_sys->b_cartoon )
  437.     {
  438.         vlc_memcpy( p_outpic->p[U_PLANE].p_pixels,
  439.             p_inpic->p[U_PLANE].p_pixels,
  440.             p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
  441.         vlc_memcpy( p_outpic->p[V_PLANE].p_pixels,
  442.             p_inpic->p[V_PLANE].p_pixels,
  443.             p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
  444.     }
  445.     else
  446.     {
  447.         vlc_memset( p_outpic->p[Y_PLANE].p_pixels, 0xff,
  448.               p_outpic->p[Y_PLANE].i_lines * p_outpic->p[Y_PLANE].i_pitch );
  449.         vlc_memset( p_outpic->p[U_PLANE].p_pixels, 0x80,
  450.             p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
  451.         vlc_memset( p_outpic->p[V_PLANE].p_pixels, 0x80,
  452.             p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
  453.     }
  454.     GaussianConvolution( p_inpic, p_smooth );
  455.     /* Sobel gradient
  456.      | -1 0 1 |     |  1  2  1 |
  457.      | -2 0 2 | and |  0  0  0 |
  458.      | -1 0 1 |     | -1 -2 -1 | */
  459.     for( y = 1; y < i_num_lines - 1; y++ )
  460.     {
  461.         for( x = 1; x < i_src_visible - 1; x++ )
  462.         {
  463.             const int gradx =
  464.                  ( p_smooth[(y-1)*i_src_visible+x-1]
  465.                    - p_smooth[(y+1)*i_src_visible+x-1] )
  466.                + ( ( p_smooth[(y-1)*i_src_visible+x]
  467.                     - p_smooth[(y+1)*i_src_visible+x] ) <<1 )
  468.                + ( p_smooth[(y-1)*i_src_visible+x+1]
  469.                    - p_smooth[(y+1)*i_src_visible+x+1] );
  470.             const int grady =
  471.                  ( p_smooth[(y-1)*i_src_visible+x-1]
  472.                    - p_smooth[(y-1)*i_src_visible+x+1] )
  473.                + ( ( p_smooth[y*i_src_visible+x-1]
  474.                     - p_smooth[y*i_src_visible+x+1] ) <<1 )
  475.                + ( p_smooth[(y+1)*i_src_visible+x-1]
  476.                    - p_smooth[(y+1)*i_src_visible+x+1] );
  477.             p_grad[y*i_src_visible+x] = (uint32_t)(abs( gradx ) + abs( grady ));
  478.             /* tan( 22.5 ) = 0,414213562 .. * 128 = 53
  479.              * tan( 26,565051177 ) = 0.5
  480.              * tan( 45 + 22.5 ) = 2,414213562 .. * 128 = 309
  481.              * tan( 63,434948823 ) 2 */
  482.             if( (grady<<1) > gradx )
  483.                 p_theta[y*i_src_visible+x] = THETA_P;
  484.             else if( (grady<<1) < -gradx )
  485.                 p_theta[y*i_src_visible+x] = THETA_M;
  486.             else if( !gradx || abs(grady) > abs(gradx)<<1 )
  487.                 p_theta[y*i_src_visible+x] = THETA_Y;
  488.             else
  489.                 p_theta[y*i_src_visible+x] = THETA_X;
  490.         }
  491.     }
  492.     /* edge computing */
  493.     for( y = 1; y < i_num_lines - 1; y++ )
  494.     {
  495.         for( x = 1; x < i_src_visible - 1; x++ )
  496.         {
  497.             if( p_grad[y*i_src_visible+x] > 40 )
  498.             {
  499.                 switch( p_theta[y*i_src_visible+x] )
  500.                 {
  501.                     case THETA_Y:
  502.                         if(    p_grad[y*i_src_visible+x] > p_grad[(y-1)*i_src_visible+x]
  503.                             && p_grad[y*i_src_visible+x] > p_grad[(y+1)*i_src_visible+x] )
  504.                         {
  505.                             p_outpix[y*i_dst_pitch+x] = 0;
  506.                             break;
  507.                         } else goto colorize;
  508.                     case THETA_P:
  509.                         if(    p_grad[y*i_src_visible+x] > p_grad[(y-1)*i_src_visible+x-1]
  510.                             && p_grad[y*i_src_visible+x] > p_grad[(y+1)*i_src_visible+x+1] )
  511.                         {
  512.                             p_outpix[y*i_dst_pitch+x] = 0;
  513.                             break;
  514.                         } else goto colorize;
  515.                     case THETA_M:
  516.                         if(    p_grad[y*i_src_visible+x] > p_grad[(y-1)*i_src_visible+x+1]
  517.                             && p_grad[y*i_src_visible+x] > p_grad[(y+1)*i_src_visible+x-1] )
  518.                         {
  519.                             p_outpix[y*i_dst_pitch+x] = 0;
  520.                             break;
  521.                         } else goto colorize;
  522.                     case THETA_X:
  523.                         if(    p_grad[y*i_src_visible+x] > p_grad[y*i_src_visible+x-1]
  524.                             && p_grad[y*i_src_visible+x] > p_grad[y*i_src_visible+x+1] )
  525.                         {
  526.                             p_outpix[y*i_dst_pitch+x] = 0;
  527.                             break;
  528.                         } else goto colorize;
  529.                 }
  530.             }
  531.             else
  532.             {
  533.                 colorize:
  534.                 if( p_filter->p_sys->b_cartoon )
  535.                 {
  536.                     if( p_smooth[y*i_src_visible+x] > 0xa0 )
  537.                         p_outpix[y*i_dst_pitch+x] = (uint8_t)
  538.                             0xff - ((0xff - p_inpix[y*i_src_pitch+x] )>>2);
  539.                     else if( p_smooth[y*i_src_visible+x] > 0x70 )
  540.                         p_outpix[y*i_dst_pitch+x] =(uint8_t)
  541.                             0xa0 - ((0xa0 - p_inpix[y*i_src_pitch+x] )>>2);
  542.                     else if( p_smooth[y*i_src_visible+x] > 0x28 )
  543.                         p_outpix[y*i_dst_pitch+x] =(uint8_t)
  544.                             0x70 - ((0x70 - p_inpix[y*i_src_pitch+x] )>>2);
  545.                     else
  546.                         p_outpix[y*i_dst_pitch+x] =(uint8_t)
  547.                             0x28 - ((0x28 - p_inpix[y*i_src_pitch+x] )>>2);
  548.                 }
  549.             }
  550.         }
  551.     }
  552. }
  553. /*****************************************************************************
  554.  * FilterHough
  555.  *****************************************************************************/
  556. #define p_pre_hough p_filter->p_sys->p_pre_hough
  557. static void FilterHough( filter_t *p_filter, picture_t *p_inpic,
  558.                                              picture_t *p_outpic )
  559. {
  560.     int x, y, i;
  561.     int i_src_visible = p_inpic->p[Y_PLANE].i_visible_pitch;
  562.     int i_dst_pitch = p_outpic->p[Y_PLANE].i_pitch;
  563.     int i_num_lines = p_inpic->p[Y_PLANE].i_visible_lines;
  564.     uint8_t *p_outpix = p_outpic->p[Y_PLANE].p_pixels;
  565.     int i_diag = sqrt( i_num_lines * i_num_lines +
  566.                         i_src_visible * i_src_visible);
  567.     int i_max, i_phi_max, i_rho, i_rho_max;
  568.     int i_nb_steps = 90;
  569.     double d_step = M_PI / i_nb_steps;
  570.     double d_sin;
  571.     double d_cos;
  572.     uint32_t *p_smooth;
  573.     int *p_hough = malloc( i_diag * i_nb_steps * sizeof(int) );
  574.     if( ! p_hough ) return;
  575.     p_smooth = (uint32_t *)malloc( i_num_lines*i_src_visible*sizeof(uint32_t));
  576.     if( !p_smooth )
  577.     {
  578.         free( p_hough );
  579.         return;
  580.     }
  581.     if( ! p_pre_hough )
  582.     {
  583.         msg_Dbg(p_filter, "Starting precalculation");
  584.         p_pre_hough = malloc( i_num_lines*i_src_visible*i_nb_steps*sizeof(int));
  585.         if( ! p_pre_hough )
  586.         {
  587.             free( p_smooth );
  588.             free( p_hough );
  589.             return;
  590.         }
  591.         for( i = 0 ; i < i_nb_steps ; i++)
  592.         {
  593.             d_sin = sin(d_step * i);
  594.             d_cos = cos(d_step * i);
  595.             for( y = 0 ; y < i_num_lines ; y++ )
  596.                 for( x = 0 ; x < i_src_visible ; x++ )
  597.                 {
  598.                     p_pre_hough[(i*i_num_lines+y)*i_src_visible + x] =
  599.                         ceil(x*d_sin + y*d_cos);
  600.                 }
  601.         }
  602.         msg_Dbg(p_filter, "Precalculation done");
  603.     }
  604.     vlc_memset( p_hough, 0, i_diag * i_nb_steps * sizeof(int) );
  605.     vlc_memcpy(
  606.         p_outpic->p[Y_PLANE].p_pixels, p_inpic->p[Y_PLANE].p_pixels,
  607.         p_outpic->p[Y_PLANE].i_lines * p_outpic->p[Y_PLANE].i_pitch );
  608.     vlc_memcpy(
  609.         p_outpic->p[U_PLANE].p_pixels, p_inpic->p[U_PLANE].p_pixels,
  610.         p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
  611.     vlc_memcpy(
  612.         p_outpic->p[V_PLANE].p_pixels, p_inpic->p[V_PLANE].p_pixels,
  613.         p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
  614.     GaussianConvolution( p_inpic, p_smooth );
  615.     /* Sobel gradient
  616.      | -1 0 1 |     |  1  2  1 |
  617.      | -2 0 2 | and |  0  0  0 |
  618.      | -1 0 1 |     | -1 -2 -1 | */
  619.     i_max = 0;
  620.     i_rho_max = 0;
  621.     i_phi_max = 0;
  622.     for( y = 4; y < i_num_lines - 4; y++ )
  623.     {
  624.         for( x = 4; x < i_src_visible - 4; x++ )
  625.         {
  626.             uint32_t a =
  627.             (
  628.               abs(
  629.                 ( ( p_smooth[(y-1)*i_src_visible+x]
  630.                     - p_smooth[(y+1)*i_src_visible+x] ) <<1 )
  631.                + ( p_smooth[(y-1)*i_src_visible+x-1]
  632.                    - p_smooth[(y+1)*i_src_visible+x-1] )
  633.                + ( p_smooth[(y-1)*i_src_visible+x+1]
  634.                    - p_smooth[(y+1)*i_src_visible+x+1] )
  635.               )
  636.             +
  637.               abs(
  638.                 ( ( p_smooth[y*i_src_visible+x-1]
  639.                     - p_smooth[y*i_src_visible+x+1] ) <<1 )
  640.                + ( p_smooth[(y-1)*i_src_visible+x-1]
  641.                    - p_smooth[(y-1)*i_src_visible+x+1] )
  642.                + ( p_smooth[(y+1)*i_src_visible+x-1]
  643.                    - p_smooth[(y+1)*i_src_visible+x+1] )
  644.               )
  645.             );
  646.             if( a>>8 )
  647.             {
  648.                 for( i = 0 ; i < i_nb_steps ; i ++ )
  649.                 {
  650.                     i_rho = p_pre_hough[(i*i_num_lines+y)*i_src_visible + x];
  651.                     if( p_hough[i_rho + i_diag/2 + i * i_diag]++ > i_max )
  652.                     {
  653.                         i_max = p_hough[i_rho + i_diag/2 + i * i_diag];
  654.                         i_rho_max = i_rho;
  655.                         i_phi_max = i;
  656.                     }
  657.                 }
  658.             }
  659.         }
  660.     }
  661.     d_sin = sin(i_phi_max*d_step);
  662.     d_cos = cos(i_phi_max*d_step);
  663.     if( d_cos != 0 )
  664.     {
  665.         for( x = 0 ; x < i_src_visible ; x++ )
  666.         {
  667.             y = (i_rho_max - x * d_sin) / d_cos;
  668.             if( y >= 0 && y < i_num_lines )
  669.                 p_outpix[y*i_dst_pitch+x] = 255;
  670.         }
  671.     }
  672.     free( p_hough );
  673.     free( p_smooth );
  674. }
  675. #undef p_pre_hough
  676. static int GradientCallback( vlc_object_t *p_this, char const *psz_var,
  677.                              vlc_value_t oldval, vlc_value_t newval,
  678.                              void *p_data )
  679. {
  680.     VLC_UNUSED(oldval);
  681.     filter_sys_t *p_sys = (filter_sys_t *)p_data;
  682.     vlc_mutex_lock( &p_sys->lock );
  683.     if( !strcmp( psz_var, FILTER_PREFIX "mode" ) )
  684.     {
  685.         if( !strcmp( newval.psz_string, "gradient" ) )
  686.         {
  687.             p_sys->i_mode = GRADIENT;
  688.         }
  689.         else if( !strcmp( newval.psz_string, "edge" ) )
  690.         {
  691.             p_sys->i_mode = EDGE;
  692.         }
  693.         else if( !strcmp( newval.psz_string, "hough" ) )
  694.         {
  695.             p_sys->i_mode = HOUGH;
  696.         }
  697.         else
  698.         {
  699.             msg_Err( p_this, "no valid gradient mode provided (%s)", newval.psz_string );
  700.             p_sys->i_mode = GRADIENT;
  701.         }
  702.     }
  703.     else if( !strcmp( psz_var, FILTER_PREFIX "type" ) )
  704.     {
  705.         p_sys->i_gradient_type = newval.i_int;
  706.     }
  707.     else if( !strcmp( psz_var, FILTER_PREFIX "cartoon" ) )
  708.     {
  709.         p_sys->b_cartoon = newval.b_bool;
  710.     }
  711.     vlc_mutex_unlock( &p_sys->lock );
  712.     return VLC_SUCCESS;
  713. }