1 /*****************************************************************************
2 * gradient.c : Gradient and edge detection video effects plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2008 the VideoLAN team
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
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <math.h> /* sin(), cos() */
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
39 #include <vlc_filter.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 filter2", 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
, 0 )
92 add_integer_with_range( FILTER_PREFIX
"type", 0, 0, 1, NULL
,
93 GRADIENT_TEXT
, GRADIENT_LONGTEXT
, false )
94 add_bool( FILTER_PREFIX
"cartoon", true, NULL
,
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
;
298 for( y
= 2; y
< i_num_lines
- 2; y
++ )
300 for( x
= 2; x
< i_src_visible
- 2; x
++ )
302 p_smooth
[y
*i_src_visible
+x
] = (uint32_t)(
304 ( p_inpix
[(y
-2)*i_src_pitch
+x
-2] )
305 + ((p_inpix
[(y
-2)*i_src_pitch
+x
-1]
306 + p_inpix
[(y
-2)*i_src_pitch
+x
]
307 + p_inpix
[(y
-2)*i_src_pitch
+x
+1])<<1 )
308 + ( p_inpix
[(y
-2)*i_src_pitch
+x
+2] )
310 + ((p_inpix
[(y
-1)*i_src_pitch
+x
-2]
311 + ( p_inpix
[(y
-1)*i_src_pitch
+x
-1]<<1 )
312 + ( p_inpix
[(y
-1)*i_src_pitch
+x
]*3 )
313 + ( p_inpix
[(y
-1)*i_src_pitch
+x
+1]<<1 )
314 + p_inpix
[(y
-1)*i_src_pitch
+x
+2]
316 + p_inpix
[y
*i_src_pitch
+x
-2]
317 + ( p_inpix
[y
*i_src_pitch
+x
-1]*3 )
318 + ( p_inpix
[y
*i_src_pitch
+x
]<<2 )
319 + ( p_inpix
[y
*i_src_pitch
+x
+1]*3 )
320 + p_inpix
[y
*i_src_pitch
+x
+2]
322 + p_inpix
[(y
+1)*i_src_pitch
+x
-2]
323 + ( p_inpix
[(y
+1)*i_src_pitch
+x
-1]<<1 )
324 + ( p_inpix
[(y
+1)*i_src_pitch
+x
]*3 )
325 + ( p_inpix
[(y
+1)*i_src_pitch
+x
+1]<<1 )
326 + p_inpix
[(y
+1)*i_src_pitch
+x
+2] )<<1 )
328 + ( p_inpix
[(y
+2)*i_src_pitch
+x
-2] )
329 + ((p_inpix
[(y
+2)*i_src_pitch
+x
-1]
330 + p_inpix
[(y
+2)*i_src_pitch
+x
]
331 + p_inpix
[(y
+2)*i_src_pitch
+x
+1])<<1 )
332 + ( p_inpix
[(y
+2)*i_src_pitch
+x
+2] )
338 /*****************************************************************************
339 * FilterGradient: Sobel
340 *****************************************************************************/
341 static void FilterGradient( filter_t
*p_filter
, picture_t
*p_inpic
,
342 picture_t
*p_outpic
)
345 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
346 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
347 const int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
348 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
350 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
351 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
354 if( !p_filter
->p_sys
->p_buf32
)
355 p_filter
->p_sys
->p_buf32
=
356 (uint32_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint32_t));
357 p_smooth
= p_filter
->p_sys
->p_buf32
;
359 if( !p_smooth
) return;
361 if( p_filter
->p_sys
->b_cartoon
)
363 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
364 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
368 vlc_memset( p_outpic
->p
[U_PLANE
].p_pixels
, 0x80,
369 p_outpic
->p
[U_PLANE
].i_lines
* p_outpic
->p
[U_PLANE
].i_pitch
);
370 vlc_memset( p_outpic
->p
[V_PLANE
].p_pixels
, 0x80,
371 p_outpic
->p
[V_PLANE
].i_lines
* p_outpic
->p
[V_PLANE
].i_pitch
);
374 GaussianConvolution( p_inpic
, p_smooth
);
379 | -2 0 2 | and | 0 0 0 |
380 | -1 0 1 | | -1 -2 -1 | */
383 for( y = 1; y < i_num_lines - 1; y++ ) \
385 for( x = 1; x < i_src_visible - 1; x++ ) \
390 ( p_smooth[(y-1)*i_src_visible+x-1] \
391 - p_smooth[(y+1)*i_src_visible+x-1] ) \
392 + ( ( p_smooth[(y-1)*i_src_visible+x] \
393 - p_smooth[(y+1)*i_src_visible+x] ) <<1 ) \
394 + ( p_smooth[(y-1)*i_src_visible+x+1] \
395 - p_smooth[(y+1)*i_src_visible+x+1] ) \
399 ( p_smooth[(y-1)*i_src_visible+x-1] \
400 - p_smooth[(y-1)*i_src_visible+x+1] ) \
401 + ( ( p_smooth[y*i_src_visible+x-1] \
402 - p_smooth[y*i_src_visible+x+1] ) <<1 ) \
403 + ( p_smooth[(y+1)*i_src_visible+x-1] \
404 - p_smooth[(y+1)*i_src_visible+x+1] ) \
407 if( p_filter
->p_sys
->i_gradient_type
)
409 if( p_filter
->p_sys
->b_cartoon
)
414 p_outpix
[y
*i_dst_pitch
+x
] = 0x00;
418 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
419 p_outpix
[y
*i_dst_pitch
+x
] =
420 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
421 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
422 p_outpix
[y
*i_dst_pitch
+x
] =
423 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
424 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
425 p_outpix
[y
*i_dst_pitch
+x
] =
426 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
428 p_outpix
[y
*i_dst_pitch
+x
] =
429 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
436 p_outpix
[y
*i_dst_pitch
+x
] = clip_uint8_vlc( a
);
444 p_outpix
[y
*i_dst_pitch
+x
] = 0;
446 p_outpix
[y
*i_dst_pitch
+x
] = 0xff-(uint8_t)a
;
452 /*****************************************************************************
453 * FilterEdge: Canny edge detection algorithm
454 *****************************************************************************
455 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
456 * (well ... my implementation isn't really the canny algorithm ... but some
457 * ideas are the same)
458 *****************************************************************************/
467 static void FilterEdge( filter_t
*p_filter
, picture_t
*p_inpic
,
468 picture_t
*p_outpic
)
472 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
473 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
474 const int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
475 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
477 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
478 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
484 if( !p_filter
->p_sys
->p_buf32
)
485 p_filter
->p_sys
->p_buf32
=
486 (uint32_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint32_t));
487 p_smooth
= p_filter
->p_sys
->p_buf32
;
489 if( !p_filter
->p_sys
->p_buf32_bis
)
490 p_filter
->p_sys
->p_buf32_bis
=
491 (uint32_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint32_t));
492 p_grad
= p_filter
->p_sys
->p_buf32_bis
;
494 if( !p_filter
->p_sys
->p_buf8
)
495 p_filter
->p_sys
->p_buf8
=
496 (uint8_t *)malloc( i_num_lines
* i_src_visible
* sizeof(uint8_t));
497 p_theta
= p_filter
->p_sys
->p_buf8
;
499 if( !p_smooth
|| !p_grad
|| !p_theta
) return;
501 if( p_filter
->p_sys
->b_cartoon
)
503 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
504 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
508 vlc_memset( p_outpic
->p
[Y_PLANE
].p_pixels
, 0xff,
509 p_outpic
->p
[Y_PLANE
].i_lines
* p_outpic
->p
[Y_PLANE
].i_pitch
);
510 vlc_memset( p_outpic
->p
[U_PLANE
].p_pixels
, 0x80,
511 p_outpic
->p
[U_PLANE
].i_lines
* p_outpic
->p
[U_PLANE
].i_pitch
);
512 vlc_memset( p_outpic
->p
[V_PLANE
].p_pixels
, 0x80,
513 p_outpic
->p
[V_PLANE
].i_lines
* p_outpic
->p
[V_PLANE
].i_pitch
);
516 GaussianConvolution( p_inpic
, p_smooth
);
521 | -2 0 2 | and | 0 0 0 |
522 | -1 0 1 | | -1 -2 -1 | */
524 for( y
= 1; y
< i_num_lines
- 1; y
++ )
526 for( x
= 1; x
< i_src_visible
- 1; x
++ )
530 ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
531 - p_smooth
[(y
+1)*i_src_visible
+x
-1] )
532 + ( ( p_smooth
[(y
-1)*i_src_visible
+x
]
533 - p_smooth
[(y
+1)*i_src_visible
+x
] ) <<1 )
534 + ( p_smooth
[(y
-1)*i_src_visible
+x
+1]
535 - p_smooth
[(y
+1)*i_src_visible
+x
+1] );
537 ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
538 - p_smooth
[(y
-1)*i_src_visible
+x
+1] )
539 + ( ( p_smooth
[y
*i_src_visible
+x
-1]
540 - p_smooth
[y
*i_src_visible
+x
+1] ) <<1 )
541 + ( p_smooth
[(y
+1)*i_src_visible
+x
-1]
542 - p_smooth
[(y
+1)*i_src_visible
+x
+1] );
544 p_grad
[y
*i_src_visible
+x
] = (uint32_t)(abs( gradx
) + abs( grady
));
546 /* tan( 22.5 ) = 0,414213562 .. * 128 = 53
547 * tan( 26,565051177 ) = 0.5
548 * tan( 45 + 22.5 ) = 2,414213562 .. * 128 = 309
549 * tan( 63,434948823 ) 2 */
550 if( (grady
<<1) > gradx
)
551 p_theta
[y
*i_src_visible
+x
] = THETA_P
;
552 else if( (grady
<<1) < -gradx
)
553 p_theta
[y
*i_src_visible
+x
] = THETA_M
;
554 else if( !gradx
|| abs(grady
) > abs(gradx
)<<1 )
555 p_theta
[y
*i_src_visible
+x
] = THETA_Y
;
557 p_theta
[y
*i_src_visible
+x
] = THETA_X
;
562 for( y
= 1; y
< i_num_lines
- 1; y
++ )
564 for( x
= 1; x
< i_src_visible
- 1; x
++ )
566 if( p_grad
[y
*i_src_visible
+x
] > 40 )
568 switch( p_theta
[y
*i_src_visible
+x
] )
571 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
]
572 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
] )
574 p_outpix
[y
*i_dst_pitch
+x
] = 0;
576 } else goto colorize
;
578 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
-1]
579 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
+1] )
581 p_outpix
[y
*i_dst_pitch
+x
] = 0;
583 } else goto colorize
;
585 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
+1]
586 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
-1] )
588 p_outpix
[y
*i_dst_pitch
+x
] = 0;
590 } else goto colorize
;
592 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
-1]
593 && p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
+1] )
595 p_outpix
[y
*i_dst_pitch
+x
] = 0;
597 } else goto colorize
;
603 if( p_filter
->p_sys
->b_cartoon
)
605 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
606 p_outpix
[y
*i_dst_pitch
+x
] = (uint8_t)
607 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
608 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
609 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
610 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
611 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
612 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
613 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
615 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
616 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
623 /*****************************************************************************
625 *****************************************************************************/
626 #define p_pre_hough p_filter->p_sys->p_pre_hough
627 static void FilterHough( filter_t
*p_filter
, picture_t
*p_inpic
,
628 picture_t
*p_outpic
)
631 int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
632 int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
633 int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
635 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
637 int i_diag
= sqrt( i_num_lines
* i_num_lines
+
638 i_src_visible
* i_src_visible
);
639 int i_max
, i_phi_max
, i_rho
, i_rho_max
;
641 double d_step
= M_PI
/ i_nb_steps
;
646 int *p_hough
= malloc( i_diag
* i_nb_steps
* sizeof(int) );
647 if( ! p_hough
) return;
649 p_smooth
= (uint32_t *)malloc( i_num_lines
*i_src_visible
*sizeof(uint32_t));
658 msg_Dbg(p_filter
, "Starting precalculation");
659 p_pre_hough
= malloc( i_num_lines
*i_src_visible
*i_nb_steps
*sizeof(int));
666 for( i
= 0 ; i
< i_nb_steps
; i
++)
668 d_sin
= sin(d_step
* i
);
669 d_cos
= cos(d_step
* i
);
670 for( y
= 0 ; y
< i_num_lines
; y
++ )
671 for( x
= 0 ; x
< i_src_visible
; x
++ )
673 p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
] =
674 ceil(x
*d_sin
+ y
*d_cos
);
677 msg_Dbg(p_filter
, "Precalculation done");
680 vlc_memset( p_hough
, 0, i_diag
* i_nb_steps
* sizeof(int) );
682 plane_CopyPixels( &p_outpic
->p
[Y_PLANE
], &p_inpic
->p
[Y_PLANE
] );
683 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
684 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
686 GaussianConvolution( p_inpic
, p_smooth
);
691 | -2 0 2 | and | 0 0 0 |
692 | -1 0 1 | | -1 -2 -1 | */
697 for( y
= 4; y
< i_num_lines
- 4; y
++ )
699 for( x
= 4; x
< i_src_visible
- 4; x
++ )
704 ( ( p_smooth
[(y
-1)*i_src_visible
+x
]
705 - p_smooth
[(y
+1)*i_src_visible
+x
] ) <<1 )
706 + ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
707 - p_smooth
[(y
+1)*i_src_visible
+x
-1] )
708 + ( p_smooth
[(y
-1)*i_src_visible
+x
+1]
709 - p_smooth
[(y
+1)*i_src_visible
+x
+1] )
713 ( ( p_smooth
[y
*i_src_visible
+x
-1]
714 - p_smooth
[y
*i_src_visible
+x
+1] ) <<1 )
715 + ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
716 - p_smooth
[(y
-1)*i_src_visible
+x
+1] )
717 + ( p_smooth
[(y
+1)*i_src_visible
+x
-1]
718 - p_smooth
[(y
+1)*i_src_visible
+x
+1] )
723 for( i
= 0 ; i
< i_nb_steps
; i
++ )
725 i_rho
= p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
];
726 if( p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
]++ > i_max
)
728 i_max
= p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
];
737 d_sin
= sin(i_phi_max
*d_step
);
738 d_cos
= cos(i_phi_max
*d_step
);
741 for( x
= 0 ; x
< i_src_visible
; x
++ )
743 y
= (i_rho_max
- x
* d_sin
) / d_cos
;
744 if( y
>= 0 && y
< i_num_lines
)
745 p_outpix
[y
*i_dst_pitch
+x
] = 255;
755 static int GradientCallback( vlc_object_t
*p_this
, char const *psz_var
,
756 vlc_value_t oldval
, vlc_value_t newval
,
760 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
762 vlc_mutex_lock( &p_sys
->lock
);
763 if( !strcmp( psz_var
, FILTER_PREFIX
"mode" ) )
765 if( !strcmp( newval
.psz_string
, "gradient" ) )
767 p_sys
->i_mode
= GRADIENT
;
769 else if( !strcmp( newval
.psz_string
, "edge" ) )
771 p_sys
->i_mode
= EDGE
;
773 else if( !strcmp( newval
.psz_string
, "hough" ) )
775 p_sys
->i_mode
= HOUGH
;
779 msg_Err( p_this
, "no valid gradient mode provided (%s)", newval
.psz_string
);
780 p_sys
->i_mode
= GRADIENT
;
783 else if( !strcmp( psz_var
, FILTER_PREFIX
"type" ) )
785 p_sys
->i_gradient_type
= newval
.i_int
;
787 else if( !strcmp( psz_var
, FILTER_PREFIX
"cartoon" ) )
789 p_sys
->b_cartoon
= newval
.b_bool
;
791 vlc_mutex_unlock( &p_sys
->lock
);