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 vlc_alloc( 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++ ) \
386 abs(((int)p_smooth[(y - 1) * i_src_visible + x - 1] \
387 - (int)p_smooth[(y + 1) * i_src_visible + x - 1]) \
388 + (((int)p_smooth[(y - 1) * i_src_visible + x] \
389 - (int)p_smooth[(y + 1) * i_src_visible + x]) * 2) \
390 + ((int)p_smooth[(y - 1) * i_src_visible + x + 1] \
391 - (int)p_smooth[(y + 1) * i_src_visible + x + 1])) \
392 + abs(((int)p_smooth[(y - 1) * i_src_visible + x - 1] \
393 - (int)p_smooth[(y - 1) * i_src_visible + x + 1]) \
394 + (((int)p_smooth[y * i_src_visible + x - 1] \
395 - (int)p_smooth[y * i_src_visible + x + 1]) * 2) \
396 + ((int)p_smooth[(y + 1) * i_src_visible + x - 1] \
397 - (int)p_smooth[(y + 1) * i_src_visible + x + 1]));
399 if( p_filter
->p_sys
->i_gradient_type
)
401 if( p_filter
->p_sys
->b_cartoon
)
406 p_outpix
[y
*i_dst_pitch
+x
] = 0x00;
410 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
411 p_outpix
[y
*i_dst_pitch
+x
] =
412 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
413 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
414 p_outpix
[y
*i_dst_pitch
+x
] =
415 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
416 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
417 p_outpix
[y
*i_dst_pitch
+x
] =
418 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
420 p_outpix
[y
*i_dst_pitch
+x
] =
421 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
428 p_outpix
[y
*i_dst_pitch
+x
] = clip_uint8_vlc( a
);
436 p_outpix
[y
*i_dst_pitch
+x
] = 0;
438 p_outpix
[y
*i_dst_pitch
+x
] = 0xff-(uint8_t)a
;
444 /*****************************************************************************
445 * FilterEdge: Canny edge detection algorithm
446 *****************************************************************************
447 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
448 * (well ... my implementation isn't really the canny algorithm ... but some
449 * ideas are the same)
450 *****************************************************************************/
459 static void FilterEdge( filter_t
*p_filter
, picture_t
*p_inpic
,
460 picture_t
*p_outpic
)
462 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
463 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
464 const int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
465 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
467 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
468 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
474 if( !p_filter
->p_sys
->p_buf32
)
475 p_filter
->p_sys
->p_buf32
=
476 vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint32_t));
477 p_smooth
= p_filter
->p_sys
->p_buf32
;
479 if( !p_filter
->p_sys
->p_buf32_bis
)
480 p_filter
->p_sys
->p_buf32_bis
=
481 vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint32_t));
482 p_grad
= p_filter
->p_sys
->p_buf32_bis
;
484 if( !p_filter
->p_sys
->p_buf8
)
485 p_filter
->p_sys
->p_buf8
=
486 vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint8_t));
487 p_theta
= p_filter
->p_sys
->p_buf8
;
489 if( !p_smooth
|| !p_grad
|| !p_theta
) return;
491 if( p_filter
->p_sys
->b_cartoon
)
493 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
494 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
498 memset( p_outpic
->p
[Y_PLANE
].p_pixels
, 0xff,
499 p_outpic
->p
[Y_PLANE
].i_lines
* p_outpic
->p
[Y_PLANE
].i_pitch
);
500 memset( p_outpic
->p
[U_PLANE
].p_pixels
, 0x80,
501 p_outpic
->p
[U_PLANE
].i_lines
* p_outpic
->p
[U_PLANE
].i_pitch
);
502 memset( p_outpic
->p
[V_PLANE
].p_pixels
, 0x80,
503 p_outpic
->p
[V_PLANE
].i_lines
* p_outpic
->p
[V_PLANE
].i_pitch
);
506 GaussianConvolution( p_inpic
, p_smooth
);
511 | -2 0 2 | and | 0 0 0 |
512 | -1 0 1 | | -1 -2 -1 | */
514 for( int y
= 1; y
< i_num_lines
- 1; y
++ )
516 for( int x
= 1; x
< i_src_visible
- 1; x
++ )
520 ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
521 - p_smooth
[(y
+1)*i_src_visible
+x
-1] )
522 + ( ( p_smooth
[(y
-1)*i_src_visible
+x
]
523 - p_smooth
[(y
+1)*i_src_visible
+x
] ) <<1 )
524 + ( p_smooth
[(y
-1)*i_src_visible
+x
+1]
525 - 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
+1] )
529 + ( ( p_smooth
[y
*i_src_visible
+x
-1]
530 - p_smooth
[y
*i_src_visible
+x
+1] ) <<1 )
531 + ( p_smooth
[(y
+1)*i_src_visible
+x
-1]
532 - p_smooth
[(y
+1)*i_src_visible
+x
+1] );
534 p_grad
[y
*i_src_visible
+x
] = (uint32_t)(abs( gradx
) + abs( grady
));
536 /* tan( 22.5 ) = 0,414213562 .. * 128 = 53
537 * tan( 26,565051177 ) = 0.5
538 * tan( 45 + 22.5 ) = 2,414213562 .. * 128 = 309
539 * tan( 63,434948823 ) 2 */
540 if( (grady
<<1) > gradx
)
541 p_theta
[y
*i_src_visible
+x
] = THETA_P
;
542 else if( (grady
<<1) < -gradx
)
543 p_theta
[y
*i_src_visible
+x
] = THETA_M
;
544 else if( !gradx
|| abs(grady
) > abs(gradx
)<<1 )
545 p_theta
[y
*i_src_visible
+x
] = THETA_Y
;
547 p_theta
[y
*i_src_visible
+x
] = THETA_X
;
552 for( int y
= 1; y
< i_num_lines
- 1; y
++ )
554 for( int x
= 1; x
< i_src_visible
- 1; x
++ )
556 if( p_grad
[y
*i_src_visible
+x
] > 40 )
558 switch( p_theta
[y
*i_src_visible
+x
] )
561 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
]
562 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
] )
564 p_outpix
[y
*i_dst_pitch
+x
] = 0;
566 } else goto colorize
;
568 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
-1]
569 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
+1] )
571 p_outpix
[y
*i_dst_pitch
+x
] = 0;
573 } else goto colorize
;
575 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
+1]
576 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
-1] )
578 p_outpix
[y
*i_dst_pitch
+x
] = 0;
580 } else goto colorize
;
582 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
-1]
583 && p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
+1] )
585 p_outpix
[y
*i_dst_pitch
+x
] = 0;
587 } else goto colorize
;
593 if( p_filter
->p_sys
->b_cartoon
)
595 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
596 p_outpix
[y
*i_dst_pitch
+x
] = (uint8_t)
597 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
598 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
599 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
600 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
601 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
602 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
603 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
605 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
606 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
613 /*****************************************************************************
615 *****************************************************************************/
616 #define p_pre_hough p_filter->p_sys->p_pre_hough
617 static void FilterHough( filter_t
*p_filter
, picture_t
*p_inpic
,
618 picture_t
*p_outpic
)
620 int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
621 int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
622 int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
624 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
626 int i_diag
= sqrt( i_num_lines
* i_num_lines
+
627 i_src_visible
* i_src_visible
);
628 int i_max
, i_phi_max
, i_rho
, i_rho_max
;
630 double d_step
= M_PI
/ i_nb_steps
;
635 int *p_hough
= vlc_alloc( i_diag
* i_nb_steps
, sizeof(int) );
636 if( ! p_hough
) return;
638 p_smooth
= vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint32_t));
647 msg_Dbg(p_filter
, "Starting precalculation");
648 p_pre_hough
= vlc_alloc( i_num_lines
*i_src_visible
*i_nb_steps
,sizeof(int));
655 for( int i
= 0; i
< i_nb_steps
; i
++)
657 d_sin
= sin(d_step
* i
);
658 d_cos
= cos(d_step
* i
);
659 for( int y
= 0; y
< i_num_lines
; y
++ )
660 for( int x
= 0; x
< i_src_visible
; x
++ )
662 p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
] =
663 ceil(x
*d_sin
+ y
*d_cos
);
666 msg_Dbg(p_filter
, "Precalculation done");
669 memset( p_hough
, 0, i_diag
* i_nb_steps
* sizeof(int) );
671 plane_CopyPixels( &p_outpic
->p
[Y_PLANE
], &p_inpic
->p
[Y_PLANE
] );
672 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
673 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
675 GaussianConvolution( p_inpic
, p_smooth
);
680 | -2 0 2 | and | 0 0 0 |
681 | -1 0 1 | | -1 -2 -1 | */
686 for( int y
= 4; y
< i_num_lines
- 4; y
++ )
688 for( int x
= 4; x
< i_src_visible
- 4; x
++ )
691 abs((((int)p_smooth
[(y
- 1) * i_src_visible
+ x
]
692 - (int)p_smooth
[(y
+ 1) * i_src_visible
+ x
]) * 2)
693 + ((int)p_smooth
[(y
- 1) * i_src_visible
+ x
- 1]
694 - (int)p_smooth
[(y
+ 1) * i_src_visible
+ x
- 1])
695 + ((int)p_smooth
[(y
- 1) * i_src_visible
+ x
+ 1]
696 - (int)p_smooth
[(y
+ 1) * i_src_visible
+ x
+ 1]))
697 + abs((((int)p_smooth
[y
* i_src_visible
+ x
- 1]
698 - (int)p_smooth
[y
* i_src_visible
+ x
+ 1]) * 2)
699 + ((int)p_smooth
[(y
- 1) * i_src_visible
+ x
- 1]
700 - (int)p_smooth
[(y
- 1) * i_src_visible
+ x
+ 1])
701 + ((int)p_smooth
[(y
+ 1) * i_src_visible
+ x
- 1]
702 - (int)p_smooth
[(y
+ 1) * i_src_visible
+ x
+ 1]));
705 for( int i
= 0; i
< i_nb_steps
; i
++ )
707 i_rho
= p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
];
708 if( p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
]++ > i_max
)
710 i_max
= p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
];
719 d_sin
= sin(i_phi_max
*d_step
);
720 d_cos
= cos(i_phi_max
*d_step
);
723 for( int x
= 0; x
< i_src_visible
; x
++ )
725 int y
= (i_rho_max
- x
* d_sin
) / d_cos
;
726 if( y
>= 0 && y
< i_num_lines
)
727 p_outpix
[y
*i_dst_pitch
+x
] = 255;
737 static int GradientCallback( vlc_object_t
*p_this
, char const *psz_var
,
738 vlc_value_t oldval
, vlc_value_t newval
,
742 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
744 vlc_mutex_lock( &p_sys
->lock
);
745 if( !strcmp( psz_var
, FILTER_PREFIX
"mode" ) )
747 if( !strcmp( newval
.psz_string
, "gradient" ) )
749 p_sys
->i_mode
= GRADIENT
;
751 else if( !strcmp( newval
.psz_string
, "edge" ) )
753 p_sys
->i_mode
= EDGE
;
755 else if( !strcmp( newval
.psz_string
, "hough" ) )
757 p_sys
->i_mode
= HOUGH
;
761 msg_Err( p_this
, "no valid gradient mode provided (%s)", newval
.psz_string
);
762 p_sys
->i_mode
= GRADIENT
;
765 else if( !strcmp( psz_var
, FILTER_PREFIX
"type" ) )
767 p_sys
->i_gradient_type
= newval
.i_int
;
769 else if( !strcmp( psz_var
, FILTER_PREFIX
"cartoon" ) )
771 p_sys
->b_cartoon
= newval
.b_bool
;
773 vlc_mutex_unlock( &p_sys
->lock
);