1 /*****************************************************************************
2 * gradient.c : Gradient and edge detection video effects plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2008 VLC authors and VideoLAN
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Antoine Cellerier <dionoea -at- videolan -dot- org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
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 Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <math.h> /* sin(), cos() */
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
38 #include <vlc_filter.h>
39 #include <vlc_picture.h>
40 #include "filter_picture.h"
42 enum { GRADIENT
, EDGE
, HOUGH
};
44 /*****************************************************************************
46 *****************************************************************************/
47 static int Create ( vlc_object_t
* );
48 static void Destroy ( vlc_object_t
* );
50 static picture_t
*Filter( filter_t
*, picture_t
* );
51 static int GradientCallback( vlc_object_t
*, char const *,
52 vlc_value_t
, vlc_value_t
,
55 static void FilterGradient( filter_t
*, picture_t
*, picture_t
* );
56 static void FilterEdge ( filter_t
*, picture_t
*, picture_t
* );
57 static void FilterHough ( filter_t
*, picture_t
*, picture_t
* );
59 /*****************************************************************************
61 *****************************************************************************/
62 #define MODE_TEXT N_("Distort mode")
63 #define MODE_LONGTEXT N_("Distort mode, one of \"gradient\", \"edge\" and \"hough\".")
65 #define GRADIENT_TEXT N_("Gradient image type")
66 #define GRADIENT_LONGTEXT N_("Gradient image type (0 or 1). 0 will " \
67 "turn the image to white while 1 will keep colors." )
69 #define CARTOON_TEXT N_("Apply cartoon effect")
70 #define CARTOON_LONGTEXT N_("Apply cartoon effect. It is only used by " \
71 "\"gradient\" and \"edge\".")
73 #define GRADIENT_HELP N_("Apply color gradient or edge detection effects")
75 static const char *const mode_list
[] = { "gradient", "edge", "hough" };
76 static const char *const mode_list_text
[] = { N_("Gradient"), N_("Edge"), N_("Hough") };
78 #define FILTER_PREFIX "gradient-"
81 set_description( N_("Gradient video filter") )
82 set_shortname( N_( "Gradient" ))
83 set_help(GRADIENT_HELP
)
84 set_capability( "video filter", 0 )
85 set_category( CAT_VIDEO
)
86 set_subcategory( SUBCAT_VIDEO_VFILTER
)
88 add_string( FILTER_PREFIX
"mode", "gradient",
89 MODE_TEXT
, MODE_LONGTEXT
, false )
90 change_string_list( mode_list
, mode_list_text
)
92 add_integer_with_range( FILTER_PREFIX
"type", 0, 0, 1,
93 GRADIENT_TEXT
, GRADIENT_LONGTEXT
, false )
94 add_bool( FILTER_PREFIX
"cartoon", true,
95 CARTOON_TEXT
, CARTOON_LONGTEXT
, false )
97 add_shortcut( "gradient" )
98 set_callbacks( Create
, Destroy
)
101 static const char *const ppsz_filter_options
[] = {
102 "mode", "type", "cartoon", NULL
105 /*****************************************************************************
106 * filter_sys_t: Distort video output method descriptor
107 *****************************************************************************
108 * This structure is part of the video output thread descriptor.
109 * It describes the Distort specific properties of an output thread.
110 *****************************************************************************/
116 /* For the gradient mode */
121 uint32_t *p_buf32_bis
;
128 /*****************************************************************************
129 * Create: allocates Distort video thread output method
130 *****************************************************************************
131 * This function allocates and initializes a Distort vout method.
132 *****************************************************************************/
133 static int Create( vlc_object_t
*p_this
)
135 filter_t
*p_filter
= (filter_t
*)p_this
;
138 switch( p_filter
->fmt_in
.video
.i_chroma
)
144 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
145 (char*)&(p_filter
->fmt_in
.video
.i_chroma
) );
149 /* Allocate structure */
150 p_filter
->p_sys
= malloc( sizeof( filter_sys_t
) );
151 if( p_filter
->p_sys
== NULL
)
154 p_filter
->pf_video_filter
= Filter
;
156 p_filter
->p_sys
->p_pre_hough
= NULL
;
158 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
162 var_CreateGetNonEmptyStringCommand( p_filter
, FILTER_PREFIX
"mode" )) )
164 msg_Err( p_filter
, "configuration variable "
165 FILTER_PREFIX
"mode empty" );
166 p_filter
->p_sys
->i_mode
= GRADIENT
;
170 if( !strcmp( psz_method
, "gradient" ) )
172 p_filter
->p_sys
->i_mode
= GRADIENT
;
174 else if( !strcmp( psz_method
, "edge" ) )
176 p_filter
->p_sys
->i_mode
= EDGE
;
178 else if( !strcmp( psz_method
, "hough" ) )
180 p_filter
->p_sys
->i_mode
= HOUGH
;
184 msg_Err( p_filter
, "no valid gradient mode provided (%s)", psz_method
);
185 p_filter
->p_sys
->i_mode
= GRADIENT
;
190 p_filter
->p_sys
->i_gradient_type
=
191 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"type" );
192 p_filter
->p_sys
->b_cartoon
=
193 var_CreateGetBoolCommand( p_filter
, FILTER_PREFIX
"cartoon" );
195 vlc_mutex_init( &p_filter
->p_sys
->lock
);
196 var_AddCallback( p_filter
, FILTER_PREFIX
"mode",
197 GradientCallback
, p_filter
->p_sys
);
198 var_AddCallback( p_filter
, FILTER_PREFIX
"type",
199 GradientCallback
, p_filter
->p_sys
);
200 var_AddCallback( p_filter
, FILTER_PREFIX
"cartoon",
201 GradientCallback
, p_filter
->p_sys
);
203 p_filter
->p_sys
->p_buf32
= NULL
;
204 p_filter
->p_sys
->p_buf32_bis
= NULL
;
205 p_filter
->p_sys
->p_buf8
= NULL
;
210 /*****************************************************************************
211 * Destroy: destroy Distort video thread output method
212 *****************************************************************************
213 * Terminate an output method created by DistortCreateOutputMethod
214 *****************************************************************************/
215 static void Destroy( vlc_object_t
*p_this
)
217 filter_t
*p_filter
= (filter_t
*)p_this
;
218 filter_sys_t
*p_sys
= p_filter
->p_sys
;
220 var_DelCallback( p_filter
, FILTER_PREFIX
"mode",
221 GradientCallback
, p_sys
);
222 var_DelCallback( p_filter
, FILTER_PREFIX
"type",
223 GradientCallback
, p_sys
);
224 var_DelCallback( p_filter
, FILTER_PREFIX
"cartoon",
225 GradientCallback
, p_sys
);
226 vlc_mutex_destroy( &p_sys
->lock
);
228 free( p_sys
->p_buf32
);
229 free( p_sys
->p_buf32_bis
);
230 free( p_sys
->p_buf8
);
231 free( p_sys
->p_pre_hough
);
236 /*****************************************************************************
237 * Render: displays previously rendered output
238 *****************************************************************************
239 * This function send the currently rendered image to Distort image, waits
240 * until it is displayed and switch the two rendering buffers, preparing next
242 *****************************************************************************/
243 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
247 if( !p_pic
) return NULL
;
249 p_outpic
= filter_NewPicture( p_filter
);
252 picture_Release( p_pic
);
256 vlc_mutex_lock( &p_filter
->p_sys
->lock
);
257 switch( p_filter
->p_sys
->i_mode
)
260 FilterEdge( p_filter
, p_pic
, p_outpic
);
264 FilterGradient( p_filter
, p_pic
, p_outpic
);
268 FilterHough( p_filter
, p_pic
, p_outpic
);
274 vlc_mutex_unlock( &p_filter
->p_sys
->lock
);
276 return CopyInfoAndRelease( p_outpic
, p_pic
);
279 /*****************************************************************************
280 * Gaussian Convolution
281 *****************************************************************************
282 * Gaussian convolution ( sigma == 1.4 )
284 * | 2 4 5 4 2 | | 2 4 4 4 2 |
285 * | 4 9 12 9 4 | | 4 8 12 8 4 |
286 * | 5 12 15 12 5 | ~ | 4 12 16 12 4 |
287 * | 4 9 12 9 4 | | 4 8 12 8 4 |
288 * | 2 4 5 4 2 | | 2 4 4 4 2 |
289 *****************************************************************************/
290 static void GaussianConvolution( picture_t
*p_inpic
, uint32_t *p_smooth
)
292 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
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_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
297 for( int y
= 2; y
< i_num_lines
- 2; y
++ )
299 for( int x
= 2; x
< i_src_visible
- 2; x
++ )
301 p_smooth
[y
*i_src_visible
+x
] = (uint32_t)(
303 ( p_inpix
[(y
-2)*i_src_pitch
+x
-2] )
304 + ((p_inpix
[(y
-2)*i_src_pitch
+x
-1]
305 + p_inpix
[(y
-2)*i_src_pitch
+x
]
306 + p_inpix
[(y
-2)*i_src_pitch
+x
+1])<<1 )
307 + ( p_inpix
[(y
-2)*i_src_pitch
+x
+2] )
309 + ((p_inpix
[(y
-1)*i_src_pitch
+x
-2]
310 + ( p_inpix
[(y
-1)*i_src_pitch
+x
-1]<<1 )
311 + ( p_inpix
[(y
-1)*i_src_pitch
+x
]*3 )
312 + ( p_inpix
[(y
-1)*i_src_pitch
+x
+1]<<1 )
313 + p_inpix
[(y
-1)*i_src_pitch
+x
+2]
315 + p_inpix
[y
*i_src_pitch
+x
-2]
316 + ( p_inpix
[y
*i_src_pitch
+x
-1]*3 )
317 + ( p_inpix
[y
*i_src_pitch
+x
]<<2 )
318 + ( p_inpix
[y
*i_src_pitch
+x
+1]*3 )
319 + p_inpix
[y
*i_src_pitch
+x
+2]
321 + p_inpix
[(y
+1)*i_src_pitch
+x
-2]
322 + ( p_inpix
[(y
+1)*i_src_pitch
+x
-1]<<1 )
323 + ( p_inpix
[(y
+1)*i_src_pitch
+x
]*3 )
324 + ( p_inpix
[(y
+1)*i_src_pitch
+x
+1]<<1 )
325 + p_inpix
[(y
+1)*i_src_pitch
+x
+2] )<<1 )
327 + ( p_inpix
[(y
+2)*i_src_pitch
+x
-2] )
328 + ((p_inpix
[(y
+2)*i_src_pitch
+x
-1]
329 + p_inpix
[(y
+2)*i_src_pitch
+x
]
330 + p_inpix
[(y
+2)*i_src_pitch
+x
+1])<<1 )
331 + ( p_inpix
[(y
+2)*i_src_pitch
+x
+2] )
337 /*****************************************************************************
338 * FilterGradient: Sobel
339 *****************************************************************************/
340 static void FilterGradient( filter_t
*p_filter
, picture_t
*p_inpic
,
341 picture_t
*p_outpic
)
343 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
344 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
345 const int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
346 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
348 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
349 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
352 if( !p_filter
->p_sys
->p_buf32
)
353 p_filter
->p_sys
->p_buf32
=
354 (uint32_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint32_t));
355 p_smooth
= p_filter
->p_sys
->p_buf32
;
357 if( !p_smooth
) return;
359 if( p_filter
->p_sys
->b_cartoon
)
361 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
362 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
366 memset( p_outpic
->p
[U_PLANE
].p_pixels
, 0x80,
367 p_outpic
->p
[U_PLANE
].i_lines
* p_outpic
->p
[U_PLANE
].i_pitch
);
368 memset( p_outpic
->p
[V_PLANE
].p_pixels
, 0x80,
369 p_outpic
->p
[V_PLANE
].i_lines
* p_outpic
->p
[V_PLANE
].i_pitch
);
372 GaussianConvolution( p_inpic
, p_smooth
);
377 | -2 0 2 | and | 0 0 0 |
378 | -1 0 1 | | -1 -2 -1 | */
381 for( int y = 1; y < i_num_lines - 1; y++ ) \
383 for( int x = 1; x < i_src_visible - 1; x++ ) \
388 ( p_smooth[(y-1)*i_src_visible+x-1] \
389 - p_smooth[(y+1)*i_src_visible+x-1] ) \
390 + ( ( p_smooth[(y-1)*i_src_visible+x] \
391 - p_smooth[(y+1)*i_src_visible+x] ) <<1 ) \
392 + ( p_smooth[(y-1)*i_src_visible+x+1] \
393 - p_smooth[(y+1)*i_src_visible+x+1] ) \
397 ( p_smooth[(y-1)*i_src_visible+x-1] \
398 - p_smooth[(y-1)*i_src_visible+x+1] ) \
399 + ( ( p_smooth[y*i_src_visible+x-1] \
400 - p_smooth[y*i_src_visible+x+1] ) <<1 ) \
401 + ( p_smooth[(y+1)*i_src_visible+x-1] \
402 - p_smooth[(y+1)*i_src_visible+x+1] ) \
405 if( p_filter
->p_sys
->i_gradient_type
)
407 if( p_filter
->p_sys
->b_cartoon
)
412 p_outpix
[y
*i_dst_pitch
+x
] = 0x00;
416 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
417 p_outpix
[y
*i_dst_pitch
+x
] =
418 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
419 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
420 p_outpix
[y
*i_dst_pitch
+x
] =
421 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
422 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
423 p_outpix
[y
*i_dst_pitch
+x
] =
424 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
426 p_outpix
[y
*i_dst_pitch
+x
] =
427 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
434 p_outpix
[y
*i_dst_pitch
+x
] = clip_uint8_vlc( a
);
442 p_outpix
[y
*i_dst_pitch
+x
] = 0;
444 p_outpix
[y
*i_dst_pitch
+x
] = 0xff-(uint8_t)a
;
450 /*****************************************************************************
451 * FilterEdge: Canny edge detection algorithm
452 *****************************************************************************
453 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
454 * (well ... my implementation isn't really the canny algorithm ... but some
455 * ideas are the same)
456 *****************************************************************************/
465 static void FilterEdge( filter_t
*p_filter
, picture_t
*p_inpic
,
466 picture_t
*p_outpic
)
468 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
469 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
470 const int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
471 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
473 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
474 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
480 if( !p_filter
->p_sys
->p_buf32
)
481 p_filter
->p_sys
->p_buf32
=
482 (uint32_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint32_t));
483 p_smooth
= p_filter
->p_sys
->p_buf32
;
485 if( !p_filter
->p_sys
->p_buf32_bis
)
486 p_filter
->p_sys
->p_buf32_bis
=
487 (uint32_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint32_t));
488 p_grad
= p_filter
->p_sys
->p_buf32_bis
;
490 if( !p_filter
->p_sys
->p_buf8
)
491 p_filter
->p_sys
->p_buf8
=
492 (uint8_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint8_t));
493 p_theta
= p_filter
->p_sys
->p_buf8
;
495 if( !p_smooth
|| !p_grad
|| !p_theta
) return;
497 if( p_filter
->p_sys
->b_cartoon
)
499 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
500 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
504 memset( p_outpic
->p
[Y_PLANE
].p_pixels
, 0xff,
505 p_outpic
->p
[Y_PLANE
].i_lines
* p_outpic
->p
[Y_PLANE
].i_pitch
);
506 memset( p_outpic
->p
[U_PLANE
].p_pixels
, 0x80,
507 p_outpic
->p
[U_PLANE
].i_lines
* p_outpic
->p
[U_PLANE
].i_pitch
);
508 memset( p_outpic
->p
[V_PLANE
].p_pixels
, 0x80,
509 p_outpic
->p
[V_PLANE
].i_lines
* p_outpic
->p
[V_PLANE
].i_pitch
);
512 GaussianConvolution( p_inpic
, p_smooth
);
517 | -2 0 2 | and | 0 0 0 |
518 | -1 0 1 | | -1 -2 -1 | */
520 for( int y
= 1; y
< i_num_lines
- 1; y
++ )
522 for( int x
= 1; x
< i_src_visible
- 1; x
++ )
526 ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
527 - p_smooth
[(y
+1)*i_src_visible
+x
-1] )
528 + ( ( p_smooth
[(y
-1)*i_src_visible
+x
]
529 - p_smooth
[(y
+1)*i_src_visible
+x
] ) <<1 )
530 + ( p_smooth
[(y
-1)*i_src_visible
+x
+1]
531 - p_smooth
[(y
+1)*i_src_visible
+x
+1] );
533 ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
534 - p_smooth
[(y
-1)*i_src_visible
+x
+1] )
535 + ( ( p_smooth
[y
*i_src_visible
+x
-1]
536 - p_smooth
[y
*i_src_visible
+x
+1] ) <<1 )
537 + ( p_smooth
[(y
+1)*i_src_visible
+x
-1]
538 - p_smooth
[(y
+1)*i_src_visible
+x
+1] );
540 p_grad
[y
*i_src_visible
+x
] = (uint32_t)(abs( gradx
) + abs( grady
));
542 /* tan( 22.5 ) = 0,414213562 .. * 128 = 53
543 * tan( 26,565051177 ) = 0.5
544 * tan( 45 + 22.5 ) = 2,414213562 .. * 128 = 309
545 * tan( 63,434948823 ) 2 */
546 if( (grady
<<1) > gradx
)
547 p_theta
[y
*i_src_visible
+x
] = THETA_P
;
548 else if( (grady
<<1) < -gradx
)
549 p_theta
[y
*i_src_visible
+x
] = THETA_M
;
550 else if( !gradx
|| abs(grady
) > abs(gradx
)<<1 )
551 p_theta
[y
*i_src_visible
+x
] = THETA_Y
;
553 p_theta
[y
*i_src_visible
+x
] = THETA_X
;
558 for( int y
= 1; y
< i_num_lines
- 1; y
++ )
560 for( int x
= 1; x
< i_src_visible
- 1; x
++ )
562 if( p_grad
[y
*i_src_visible
+x
] > 40 )
564 switch( p_theta
[y
*i_src_visible
+x
] )
567 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
]
568 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
] )
570 p_outpix
[y
*i_dst_pitch
+x
] = 0;
572 } else goto colorize
;
574 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
-1]
575 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
+1] )
577 p_outpix
[y
*i_dst_pitch
+x
] = 0;
579 } else goto colorize
;
581 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
+1]
582 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
-1] )
584 p_outpix
[y
*i_dst_pitch
+x
] = 0;
586 } else goto colorize
;
588 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
-1]
589 && p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
+1] )
591 p_outpix
[y
*i_dst_pitch
+x
] = 0;
593 } else goto colorize
;
599 if( p_filter
->p_sys
->b_cartoon
)
601 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
602 p_outpix
[y
*i_dst_pitch
+x
] = (uint8_t)
603 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
604 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
605 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
606 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
607 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
608 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
609 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
611 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
612 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
619 /*****************************************************************************
621 *****************************************************************************/
622 #define p_pre_hough p_filter->p_sys->p_pre_hough
623 static void FilterHough( filter_t
*p_filter
, picture_t
*p_inpic
,
624 picture_t
*p_outpic
)
626 int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
627 int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
628 int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
630 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
632 int i_diag
= sqrt( i_num_lines
* i_num_lines
+
633 i_src_visible
* i_src_visible
);
634 int i_max
, i_phi_max
, i_rho
, i_rho_max
;
636 double d_step
= M_PI
/ i_nb_steps
;
641 int *p_hough
= malloc( i_diag
* i_nb_steps
* sizeof(int) );
642 if( ! p_hough
) return;
644 p_smooth
= (uint32_t *)malloc( i_num_lines
*i_src_visible
*sizeof(uint32_t));
653 msg_Dbg(p_filter
, "Starting precalculation");
654 p_pre_hough
= malloc( i_num_lines
*i_src_visible
*i_nb_steps
*sizeof(int));
661 for( int i
= 0; i
< i_nb_steps
; i
++)
663 d_sin
= sin(d_step
* i
);
664 d_cos
= cos(d_step
* i
);
665 for( int y
= 0; y
< i_num_lines
; y
++ )
666 for( int x
= 0; x
< i_src_visible
; x
++ )
668 p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
] =
669 ceil(x
*d_sin
+ y
*d_cos
);
672 msg_Dbg(p_filter
, "Precalculation done");
675 memset( p_hough
, 0, i_diag
* i_nb_steps
* sizeof(int) );
677 plane_CopyPixels( &p_outpic
->p
[Y_PLANE
], &p_inpic
->p
[Y_PLANE
] );
678 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
679 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
681 GaussianConvolution( p_inpic
, p_smooth
);
686 | -2 0 2 | and | 0 0 0 |
687 | -1 0 1 | | -1 -2 -1 | */
692 for( int y
= 4; y
< i_num_lines
- 4; y
++ )
694 for( int x
= 4; x
< i_src_visible
- 4; x
++ )
699 ( ( p_smooth
[(y
-1)*i_src_visible
+x
]
700 - p_smooth
[(y
+1)*i_src_visible
+x
] ) <<1 )
701 + ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
702 - p_smooth
[(y
+1)*i_src_visible
+x
-1] )
703 + ( p_smooth
[(y
-1)*i_src_visible
+x
+1]
704 - p_smooth
[(y
+1)*i_src_visible
+x
+1] )
708 ( ( p_smooth
[y
*i_src_visible
+x
-1]
709 - p_smooth
[y
*i_src_visible
+x
+1] ) <<1 )
710 + ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
711 - p_smooth
[(y
-1)*i_src_visible
+x
+1] )
712 + ( p_smooth
[(y
+1)*i_src_visible
+x
-1]
713 - p_smooth
[(y
+1)*i_src_visible
+x
+1] )
718 for( int i
= 0; i
< i_nb_steps
; i
++ )
720 i_rho
= p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
];
721 if( p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
]++ > i_max
)
723 i_max
= p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
];
732 d_sin
= sin(i_phi_max
*d_step
);
733 d_cos
= cos(i_phi_max
*d_step
);
736 for( int x
= 0; x
< i_src_visible
; x
++ )
738 int y
= (i_rho_max
- x
* d_sin
) / d_cos
;
739 if( y
>= 0 && y
< i_num_lines
)
740 p_outpix
[y
*i_dst_pitch
+x
] = 255;
750 static int GradientCallback( vlc_object_t
*p_this
, char const *psz_var
,
751 vlc_value_t oldval
, vlc_value_t newval
,
755 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
757 vlc_mutex_lock( &p_sys
->lock
);
758 if( !strcmp( psz_var
, FILTER_PREFIX
"mode" ) )
760 if( !strcmp( newval
.psz_string
, "gradient" ) )
762 p_sys
->i_mode
= GRADIENT
;
764 else if( !strcmp( newval
.psz_string
, "edge" ) )
766 p_sys
->i_mode
= EDGE
;
768 else if( !strcmp( newval
.psz_string
, "hough" ) )
770 p_sys
->i_mode
= HOUGH
;
774 msg_Err( p_this
, "no valid gradient mode provided (%s)", newval
.psz_string
);
775 p_sys
->i_mode
= GRADIENT
;
778 else if( !strcmp( psz_var
, FILTER_PREFIX
"type" ) )
780 p_sys
->i_gradient_type
= newval
.i_int
;
782 else if( !strcmp( psz_var
, FILTER_PREFIX
"cartoon" ) )
784 p_sys
->b_cartoon
= newval
.b_bool
;
786 vlc_mutex_unlock( &p_sys
->lock
);