1 /*****************************************************************************
2 * gradient.c : Gradient and edge detection video effects plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2008 VLC authors and VideoLAN
6 * Authors: Samuel Hocevar <sam@zoy.org>
7 * Antoine Cellerier <dionoea -at- videolan -dot- org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <math.h> /* sin(), cos() */
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <vlc_filter.h>
38 #include <vlc_picture.h>
39 #include "filter_picture.h"
41 enum { GRADIENT
, EDGE
, HOUGH
};
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Create ( vlc_object_t
* );
47 static void Destroy ( vlc_object_t
* );
49 static picture_t
*Filter( filter_t
*, picture_t
* );
50 static int GradientCallback( vlc_object_t
*, char const *,
51 vlc_value_t
, vlc_value_t
,
54 static void FilterGradient( filter_t
*, picture_t
*, picture_t
* );
55 static void FilterEdge ( filter_t
*, picture_t
*, picture_t
* );
56 static void FilterHough ( filter_t
*, picture_t
*, picture_t
* );
58 /*****************************************************************************
60 *****************************************************************************/
61 #define MODE_TEXT N_("Distort mode")
62 #define MODE_LONGTEXT N_("Distort mode, one of \"gradient\", \"edge\" and \"hough\".")
64 #define GRADIENT_TEXT N_("Gradient image type")
65 #define GRADIENT_LONGTEXT N_("Gradient image type (0 or 1). 0 will " \
66 "turn the image to white while 1 will keep colors." )
68 #define CARTOON_TEXT N_("Apply cartoon effect")
69 #define CARTOON_LONGTEXT N_("Apply cartoon effect. It is only used by " \
70 "\"gradient\" and \"edge\".")
72 #define GRADIENT_HELP N_("Apply color gradient or edge detection effects")
74 static const char *const mode_list
[] = { "gradient", "edge", "hough" };
75 static const char *const mode_list_text
[] = { N_("Gradient"), N_("Edge"), N_("Hough") };
77 #define FILTER_PREFIX "gradient-"
80 set_description( N_("Gradient video filter") )
81 set_shortname( N_( "Gradient" ))
82 set_help(GRADIENT_HELP
)
83 set_capability( "video filter", 0 )
84 set_category( CAT_VIDEO
)
85 set_subcategory( SUBCAT_VIDEO_VFILTER
)
87 add_string( FILTER_PREFIX
"mode", "gradient",
88 MODE_TEXT
, MODE_LONGTEXT
, false )
89 change_string_list( mode_list
, mode_list_text
)
91 add_integer_with_range( FILTER_PREFIX
"type", 0, 0, 1,
92 GRADIENT_TEXT
, GRADIENT_LONGTEXT
, false )
93 add_bool( FILTER_PREFIX
"cartoon", true,
94 CARTOON_TEXT
, CARTOON_LONGTEXT
, false )
96 add_shortcut( "gradient" )
97 set_callbacks( Create
, Destroy
)
100 static const char *const ppsz_filter_options
[] = {
101 "mode", "type", "cartoon", NULL
104 /*****************************************************************************
105 * filter_sys_t: Distort video output method descriptor
106 *****************************************************************************
107 * This structure is part of the video output thread descriptor.
108 * It describes the Distort specific properties of an output thread.
109 *****************************************************************************/
115 /* For the gradient mode */
120 uint32_t *p_buf32_bis
;
127 /*****************************************************************************
128 * Create: allocates Distort video thread output method
129 *****************************************************************************
130 * This function allocates and initializes a Distort vout method.
131 *****************************************************************************/
132 static int Create( vlc_object_t
*p_this
)
134 filter_t
*p_filter
= (filter_t
*)p_this
;
137 switch( p_filter
->fmt_in
.video
.i_chroma
)
143 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
144 (char*)&(p_filter
->fmt_in
.video
.i_chroma
) );
148 /* Allocate structure */
149 filter_sys_t
*p_sys
= malloc( sizeof( filter_sys_t
) );
152 p_filter
->p_sys
= p_sys
;
154 p_filter
->pf_video_filter
= Filter
;
156 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_sys
->i_mode
= GRADIENT
;
170 if( !strcmp( psz_method
, "gradient" ) )
172 p_sys
->i_mode
= GRADIENT
;
174 else if( !strcmp( psz_method
, "edge" ) )
176 p_sys
->i_mode
= EDGE
;
178 else if( !strcmp( psz_method
, "hough" ) )
180 p_sys
->i_mode
= HOUGH
;
184 msg_Err( p_filter
, "no valid gradient mode provided (%s)", psz_method
);
185 p_sys
->i_mode
= GRADIENT
;
190 p_sys
->i_gradient_type
=
191 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"type" );
193 var_CreateGetBoolCommand( p_filter
, FILTER_PREFIX
"cartoon" );
195 vlc_mutex_init( &p_sys
->lock
);
196 var_AddCallback( p_filter
, FILTER_PREFIX
"mode",
197 GradientCallback
, p_sys
);
198 var_AddCallback( p_filter
, FILTER_PREFIX
"type",
199 GradientCallback
, p_sys
);
200 var_AddCallback( p_filter
, FILTER_PREFIX
"cartoon",
201 GradientCallback
, p_sys
);
203 p_sys
->p_buf32
= NULL
;
204 p_sys
->p_buf32_bis
= NULL
;
205 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
);
227 free( p_sys
->p_buf32
);
228 free( p_sys
->p_buf32_bis
);
229 free( p_sys
->p_buf8
);
230 free( p_sys
->p_pre_hough
);
235 /*****************************************************************************
236 * Render: displays previously rendered output
237 *****************************************************************************
238 * This function send the currently rendered image to Distort image, waits
239 * until it is displayed and switch the two rendering buffers, preparing next
241 *****************************************************************************/
242 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
246 if( !p_pic
) return NULL
;
248 p_outpic
= filter_NewPicture( p_filter
);
251 picture_Release( p_pic
);
255 filter_sys_t
*p_sys
= p_filter
->p_sys
;
257 vlc_mutex_lock( &p_sys
->lock
);
258 switch( p_sys
->i_mode
)
261 FilterEdge( p_filter
, p_pic
, p_outpic
);
265 FilterGradient( p_filter
, p_pic
, p_outpic
);
269 FilterHough( p_filter
, p_pic
, p_outpic
);
275 vlc_mutex_unlock( &p_sys
->lock
);
277 return CopyInfoAndRelease( p_outpic
, p_pic
);
280 /*****************************************************************************
281 * Gaussian Convolution
282 *****************************************************************************
283 * Gaussian convolution ( sigma == 1.4 )
285 * | 2 4 5 4 2 | | 2 4 4 4 2 |
286 * | 4 9 12 9 4 | | 4 8 12 8 4 |
287 * | 5 12 15 12 5 | ~ | 4 12 16 12 4 |
288 * | 4 9 12 9 4 | | 4 8 12 8 4 |
289 * | 2 4 5 4 2 | | 2 4 4 4 2 |
290 *****************************************************************************/
291 static void GaussianConvolution( picture_t
*p_inpic
, uint32_t *p_smooth
)
293 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
294 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
295 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
296 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
298 for( int y
= 2; y
< i_num_lines
- 2; y
++ )
300 for( int 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
)
344 filter_sys_t
*p_sys
= p_filter
->p_sys
;
346 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
347 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
348 const int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
349 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
351 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
352 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
355 if( !p_sys
->p_buf32
)
357 vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint32_t));
358 p_smooth
= p_sys
->p_buf32
;
360 if( !p_smooth
) return;
362 if( p_sys
->b_cartoon
)
364 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
365 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
369 memset( p_outpic
->p
[U_PLANE
].p_pixels
, 0x80,
370 p_outpic
->p
[U_PLANE
].i_lines
* p_outpic
->p
[U_PLANE
].i_pitch
);
371 memset( p_outpic
->p
[V_PLANE
].p_pixels
, 0x80,
372 p_outpic
->p
[V_PLANE
].i_lines
* p_outpic
->p
[V_PLANE
].i_pitch
);
375 GaussianConvolution( p_inpic
, p_smooth
);
380 | -2 0 2 | and | 0 0 0 |
381 | -1 0 1 | | -1 -2 -1 | */
384 for( int y = 1; y < i_num_lines - 1; y++ ) \
386 for( int x = 1; x < i_src_visible - 1; x++ ) \
389 abs(((int)p_smooth[(y - 1) * i_src_visible + x - 1] \
390 - (int)p_smooth[(y + 1) * i_src_visible + x - 1]) \
391 + (((int)p_smooth[(y - 1) * i_src_visible + x] \
392 - (int)p_smooth[(y + 1) * i_src_visible + x]) * 2) \
393 + ((int)p_smooth[(y - 1) * i_src_visible + x + 1] \
394 - (int)p_smooth[(y + 1) * i_src_visible + x + 1])) \
395 + abs(((int)p_smooth[(y - 1) * i_src_visible + x - 1] \
396 - (int)p_smooth[(y - 1) * i_src_visible + x + 1]) \
397 + (((int)p_smooth[y * i_src_visible + x - 1] \
398 - (int)p_smooth[y * i_src_visible + x + 1]) * 2) \
399 + ((int)p_smooth[(y + 1) * i_src_visible + x - 1] \
400 - (int)p_smooth[(y + 1) * i_src_visible + x + 1]));
402 if( p_sys
->i_gradient_type
)
404 if( p_sys
->b_cartoon
)
409 p_outpix
[y
*i_dst_pitch
+x
] = 0x00;
413 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
414 p_outpix
[y
*i_dst_pitch
+x
] =
415 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
416 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
417 p_outpix
[y
*i_dst_pitch
+x
] =
418 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
419 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
420 p_outpix
[y
*i_dst_pitch
+x
] =
421 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
423 p_outpix
[y
*i_dst_pitch
+x
] =
424 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
431 p_outpix
[y
*i_dst_pitch
+x
] = clip_uint8_vlc( a
);
439 p_outpix
[y
*i_dst_pitch
+x
] = 0;
441 p_outpix
[y
*i_dst_pitch
+x
] = 0xff-(uint8_t)a
;
447 /*****************************************************************************
448 * FilterEdge: Canny edge detection algorithm
449 *****************************************************************************
450 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
451 * (well ... my implementation isn't really the canny algorithm ... but some
452 * ideas are the same)
453 *****************************************************************************/
462 static void FilterEdge( filter_t
*p_filter
, picture_t
*p_inpic
,
463 picture_t
*p_outpic
)
465 filter_sys_t
*p_sys
= p_filter
->p_sys
;
467 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
468 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
469 const int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
470 const int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
472 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
473 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
479 if( !p_sys
->p_buf32
)
481 vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint32_t));
482 p_smooth
= p_sys
->p_buf32
;
484 if( !p_sys
->p_buf32_bis
)
486 vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint32_t));
487 p_grad
= p_sys
->p_buf32_bis
;
491 vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint8_t));
492 p_theta
= p_sys
->p_buf8
;
494 if( !p_smooth
|| !p_grad
|| !p_theta
) return;
496 if( p_sys
->b_cartoon
)
498 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
499 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
503 memset( p_outpic
->p
[Y_PLANE
].p_pixels
, 0xff,
504 p_outpic
->p
[Y_PLANE
].i_lines
* p_outpic
->p
[Y_PLANE
].i_pitch
);
505 memset( p_outpic
->p
[U_PLANE
].p_pixels
, 0x80,
506 p_outpic
->p
[U_PLANE
].i_lines
* p_outpic
->p
[U_PLANE
].i_pitch
);
507 memset( p_outpic
->p
[V_PLANE
].p_pixels
, 0x80,
508 p_outpic
->p
[V_PLANE
].i_lines
* p_outpic
->p
[V_PLANE
].i_pitch
);
511 GaussianConvolution( p_inpic
, p_smooth
);
516 | -2 0 2 | and | 0 0 0 |
517 | -1 0 1 | | -1 -2 -1 | */
519 for( int y
= 1; y
< i_num_lines
- 1; y
++ )
521 for( int x
= 1; x
< i_src_visible
- 1; x
++ )
525 ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
526 - p_smooth
[(y
+1)*i_src_visible
+x
-1] )
527 + ( ( p_smooth
[(y
-1)*i_src_visible
+x
]
528 - p_smooth
[(y
+1)*i_src_visible
+x
] ) <<1 )
529 + ( p_smooth
[(y
-1)*i_src_visible
+x
+1]
530 - p_smooth
[(y
+1)*i_src_visible
+x
+1] );
532 ( p_smooth
[(y
-1)*i_src_visible
+x
-1]
533 - p_smooth
[(y
-1)*i_src_visible
+x
+1] )
534 + ( ( p_smooth
[y
*i_src_visible
+x
-1]
535 - p_smooth
[y
*i_src_visible
+x
+1] ) <<1 )
536 + ( p_smooth
[(y
+1)*i_src_visible
+x
-1]
537 - p_smooth
[(y
+1)*i_src_visible
+x
+1] );
539 p_grad
[y
*i_src_visible
+x
] = (uint32_t)(abs( gradx
) + abs( grady
));
541 /* tan( 22.5 ) = 0,414213562 .. * 128 = 53
542 * tan( 26,565051177 ) = 0.5
543 * tan( 45 + 22.5 ) = 2,414213562 .. * 128 = 309
544 * tan( 63,434948823 ) 2 */
545 if( (grady
<<1) > gradx
)
546 p_theta
[y
*i_src_visible
+x
] = THETA_P
;
547 else if( (grady
<<1) < -gradx
)
548 p_theta
[y
*i_src_visible
+x
] = THETA_M
;
549 else if( !gradx
|| abs(grady
) > abs(gradx
)<<1 )
550 p_theta
[y
*i_src_visible
+x
] = THETA_Y
;
552 p_theta
[y
*i_src_visible
+x
] = THETA_X
;
557 for( int y
= 1; y
< i_num_lines
- 1; y
++ )
559 for( int x
= 1; x
< i_src_visible
- 1; x
++ )
561 if( p_grad
[y
*i_src_visible
+x
] > 40 )
563 switch( p_theta
[y
*i_src_visible
+x
] )
566 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
]
567 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
] )
569 p_outpix
[y
*i_dst_pitch
+x
] = 0;
571 } else goto colorize
;
573 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
-1]
574 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
+1] )
576 p_outpix
[y
*i_dst_pitch
+x
] = 0;
578 } else goto colorize
;
580 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
-1)*i_src_visible
+x
+1]
581 && p_grad
[y
*i_src_visible
+x
] > p_grad
[(y
+1)*i_src_visible
+x
-1] )
583 p_outpix
[y
*i_dst_pitch
+x
] = 0;
585 } else goto colorize
;
587 if( p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
-1]
588 && p_grad
[y
*i_src_visible
+x
] > p_grad
[y
*i_src_visible
+x
+1] )
590 p_outpix
[y
*i_dst_pitch
+x
] = 0;
592 } else goto colorize
;
598 if( p_sys
->b_cartoon
)
600 if( p_smooth
[y
*i_src_visible
+x
] > 0xa0 )
601 p_outpix
[y
*i_dst_pitch
+x
] = (uint8_t)
602 0xff - ((0xff - p_inpix
[y
*i_src_pitch
+x
] )>>2);
603 else if( p_smooth
[y
*i_src_visible
+x
] > 0x70 )
604 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
605 0xa0 - ((0xa0 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
606 else if( p_smooth
[y
*i_src_visible
+x
] > 0x28 )
607 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
608 0x70 - ((0x70 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
610 p_outpix
[y
*i_dst_pitch
+x
] =(uint8_t)
611 0x28 - ((0x28 - p_inpix
[y
*i_src_pitch
+x
] )>>2);
618 /*****************************************************************************
620 *****************************************************************************/
621 #define p_pre_hough p_sys->p_pre_hough
622 static void FilterHough( filter_t
*p_filter
, picture_t
*p_inpic
,
623 picture_t
*p_outpic
)
625 filter_sys_t
*p_sys
= p_filter
->p_sys
;
627 int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
628 int i_dst_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
629 int i_num_lines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
631 uint8_t *p_outpix
= p_outpic
->p
[Y_PLANE
].p_pixels
;
633 int i_diag
= sqrt( i_num_lines
* i_num_lines
+
634 i_src_visible
* i_src_visible
);
635 int i_max
, i_phi_max
, i_rho
, i_rho_max
;
637 double d_step
= M_PI
/ i_nb_steps
;
642 int *p_hough
= vlc_alloc( i_diag
* i_nb_steps
, sizeof(int) );
643 if( ! p_hough
) return;
645 p_smooth
= vlc_alloc( i_num_lines
* i_src_visible
, sizeof(uint32_t));
654 msg_Dbg(p_filter
, "Starting precalculation");
655 p_pre_hough
= vlc_alloc( i_num_lines
*i_src_visible
*i_nb_steps
,sizeof(int));
662 for( int i
= 0; i
< i_nb_steps
; i
++)
664 d_sin
= sin(d_step
* i
);
665 d_cos
= cos(d_step
* i
);
666 for( int y
= 0; y
< i_num_lines
; y
++ )
667 for( int x
= 0; x
< i_src_visible
; x
++ )
669 p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
] =
670 ceil(x
*d_sin
+ y
*d_cos
);
673 msg_Dbg(p_filter
, "Precalculation done");
676 memset( p_hough
, 0, i_diag
* i_nb_steps
* sizeof(int) );
678 plane_CopyPixels( &p_outpic
->p
[Y_PLANE
], &p_inpic
->p
[Y_PLANE
] );
679 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_inpic
->p
[U_PLANE
] );
680 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_inpic
->p
[V_PLANE
] );
682 GaussianConvolution( p_inpic
, p_smooth
);
687 | -2 0 2 | and | 0 0 0 |
688 | -1 0 1 | | -1 -2 -1 | */
693 for( int y
= 4; y
< i_num_lines
- 4; y
++ )
695 for( int x
= 4; x
< i_src_visible
- 4; x
++ )
698 abs((((int)p_smooth
[(y
- 1) * i_src_visible
+ x
]
699 - (int)p_smooth
[(y
+ 1) * i_src_visible
+ x
]) * 2)
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]
703 - (int)p_smooth
[(y
+ 1) * i_src_visible
+ x
+ 1]))
704 + abs((((int)p_smooth
[y
* i_src_visible
+ x
- 1]
705 - (int)p_smooth
[y
* i_src_visible
+ x
+ 1]) * 2)
706 + ((int)p_smooth
[(y
- 1) * i_src_visible
+ x
- 1]
707 - (int)p_smooth
[(y
- 1) * i_src_visible
+ x
+ 1])
708 + ((int)p_smooth
[(y
+ 1) * i_src_visible
+ x
- 1]
709 - (int)p_smooth
[(y
+ 1) * i_src_visible
+ x
+ 1]));
712 for( int i
= 0; i
< i_nb_steps
; i
++ )
714 i_rho
= p_pre_hough
[(i
*i_num_lines
+y
)*i_src_visible
+ x
];
715 if( p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
]++ > i_max
)
717 i_max
= p_hough
[i_rho
+ i_diag
/2 + i
* i_diag
];
726 d_sin
= sin(i_phi_max
*d_step
);
727 d_cos
= cos(i_phi_max
*d_step
);
730 for( int x
= 0; x
< i_src_visible
; x
++ )
732 int y
= (i_rho_max
- x
* d_sin
) / d_cos
;
733 if( y
>= 0 && y
< i_num_lines
)
734 p_outpix
[y
*i_dst_pitch
+x
] = 255;
744 static int GradientCallback( vlc_object_t
*p_this
, char const *psz_var
,
745 vlc_value_t oldval
, vlc_value_t newval
,
749 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
751 vlc_mutex_lock( &p_sys
->lock
);
752 if( !strcmp( psz_var
, FILTER_PREFIX
"mode" ) )
754 if( !strcmp( newval
.psz_string
, "gradient" ) )
756 p_sys
->i_mode
= GRADIENT
;
758 else if( !strcmp( newval
.psz_string
, "edge" ) )
760 p_sys
->i_mode
= EDGE
;
762 else if( !strcmp( newval
.psz_string
, "hough" ) )
764 p_sys
->i_mode
= HOUGH
;
768 msg_Err( p_this
, "no valid gradient mode provided (%s)", newval
.psz_string
);
769 p_sys
->i_mode
= GRADIENT
;
772 else if( !strcmp( psz_var
, FILTER_PREFIX
"type" ) )
774 p_sys
->i_gradient_type
= newval
.i_int
;
776 else if( !strcmp( psz_var
, FILTER_PREFIX
"cartoon" ) )
778 p_sys
->b_cartoon
= newval
.b_bool
;
780 vlc_mutex_unlock( &p_sys
->lock
);