]> git.sesse.net Git - vlc/blob - modules/video_filter/colorthres.c
f1a13082194fbca71b8e5705ab61828a49a2956c
[vlc] / modules / video_filter / colorthres.c
1 /*****************************************************************************
2  * colorthres.c: Threshold color based on similarity to reference color
3  *****************************************************************************
4  * Copyright (C) 2000-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sigmund Augdal <dnumgis@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <errno.h>
33 #include <math.h>
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_sout.h>
38
39 #include <vlc_filter.h>
40 #include "filter_picture.h"
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static int  Create    ( vlc_object_t * );
46 static void Destroy   ( vlc_object_t * );
47
48 static picture_t *Filter( filter_t *, picture_t * );
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 #define COLOR_TEXT N_("Color")
54 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
55     "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
56     "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
57     " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
58 #define COLOR_HELP N_("Select one color in the video")
59 static const int pi_color_values[] = {
60   0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
61
62 static const char *const ppsz_color_descriptions[] = {
63   N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
64
65 #define CFG_PREFIX "colorthres-"
66
67 vlc_module_begin ()
68     set_description( N_("Color threshold filter") )
69     set_shortname( N_("Color threshold" ))
70     set_help(COLOR_HELP)
71     set_category( CAT_VIDEO )
72     set_subcategory( SUBCAT_VIDEO_VFILTER )
73     set_capability( "video filter2", 0 )
74     add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
75                  COLOR_LONGTEXT, false )
76         change_integer_list( pi_color_values, ppsz_color_descriptions, NULL )
77     add_integer( CFG_PREFIX "saturationthres", 20, NULL,
78                  N_("Saturaton threshold"), "", false )
79     add_integer( CFG_PREFIX "similaritythres", 15, NULL,
80                  N_("Similarity threshold"), "", false )
81     set_callbacks( Create, Destroy )
82 vlc_module_end ()
83
84 static const char *const ppsz_filter_options[] = {
85     "color", "saturationthes", "similaritythres", NULL
86 };
87
88 /*****************************************************************************
89  * callback prototypes
90  *****************************************************************************/
91 static int FilterCallback( vlc_object_t *, char const *,
92                            vlc_value_t, vlc_value_t, void * );
93
94
95 /*****************************************************************************
96  * filter_sys_t: adjust filter method descriptor
97  *****************************************************************************/
98 struct filter_sys_t
99 {
100     int i_simthres;
101     int i_satthres;
102     int i_color;
103     vlc_mutex_t lock;
104 };
105
106 /*****************************************************************************
107  * Create: allocates adjust video thread output method
108  *****************************************************************************
109  * This function allocates and initializes a adjust vout method.
110  *****************************************************************************/
111 static int Create( vlc_object_t *p_this )
112 {
113     filter_t *p_filter = (filter_t *)p_this;
114     filter_sys_t *p_sys;
115
116     switch( p_filter->fmt_in.video.i_chroma )
117     {
118         CASE_PLANAR_YUV
119             break;
120
121         default:
122             msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
123                      (char*)&(p_filter->fmt_in.video.i_chroma) );
124             return VLC_EGENERIC;
125     }
126
127     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
128     {
129         msg_Err( p_filter, "Input and output chromas don't match" );
130         return VLC_EGENERIC;
131     }
132
133     /* Allocate structure */
134     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
135     if( p_filter->p_sys == NULL )
136         return VLC_ENOMEM;
137
138     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
139                        p_filter->p_cfg );
140     p_sys->i_color = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
141     p_sys->i_simthres = var_CreateGetIntegerCommand( p_filter,
142                                                      CFG_PREFIX "similaritythres" );
143     p_sys->i_satthres = var_CreateGetIntegerCommand( p_filter,
144                                                      CFG_PREFIX "saturationthres" );
145
146     vlc_mutex_init( &p_sys->lock );
147
148     var_AddCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
149     var_AddCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
150     var_AddCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
151
152     p_filter->pf_video_filter = Filter;
153
154     return VLC_SUCCESS;
155 }
156
157 /*****************************************************************************
158  * Destroy: destroy adjust video thread output method
159  *****************************************************************************
160  * Terminate an output method created by adjustCreateOutputMethod
161  *****************************************************************************/
162 static void Destroy( vlc_object_t *p_this )
163 {
164     filter_t *p_filter = (filter_t *)p_this;
165
166     var_DelCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
167     var_DelCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
168     var_DelCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
169
170     vlc_mutex_destroy( &p_filter->p_sys->lock );
171     free( p_filter->p_sys );
172 }
173
174 /*****************************************************************************
175  * Render: displays previously rendered output
176  *****************************************************************************
177  * This function send the currently rendered image to adjust modified image,
178  * waits until it is displayed and switch the two rendering buffers, preparing
179  * next frame.
180  *****************************************************************************/
181 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
182 {
183     picture_t *p_outpic;
184     filter_sys_t *p_sys = p_filter->p_sys;
185     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
186     uint8_t *p_out_y, *p_out_u, *p_out_v;
187
188     vlc_mutex_lock( &p_sys->lock );
189     int i_simthres = p_sys->i_simthres;
190     int i_satthres = p_sys->i_satthres;
191     int i_color = p_sys->i_color;
192     vlc_mutex_unlock( &p_sys->lock );
193
194     if( !p_pic ) return NULL;
195
196     p_outpic = filter_NewPicture( p_filter );
197     if( !p_outpic )
198     {
199         picture_Release( p_pic );
200         return NULL;
201     }
202
203     p_in_u = p_pic->p[U_PLANE].p_pixels;
204     p_in_v = p_pic->p[V_PLANE].p_pixels;
205     p_in_y = p_pic->p[Y_PLANE].p_pixels;
206     p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
207                         * p_pic->p[U_PLANE].i_pitch - 8;
208
209     p_out_y = p_outpic->p[Y_PLANE].p_pixels;
210     p_out_u = p_outpic->p[U_PLANE].p_pixels;
211     p_out_v = p_outpic->p[V_PLANE].p_pixels;
212
213     /* Create grayscale version of input */
214     vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
215                * p_pic->p[Y_PLANE].i_pitch - 8 );
216     vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
217                * p_pic->p[U_PLANE].i_pitch - 8 );
218     vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
219                * p_pic->p[U_PLANE].i_pitch - 8 );
220
221     /*
222      * Do the U and V planes
223      */
224     int i_red = ( i_color & 0xFF0000 ) >> 16;
225     int i_green = ( i_color & 0xFF00 ) >> 8;
226     int i_blue = i_color & 0xFF;
227     int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
228                      112 * i_blue + 128) >> 8) + 128;
229     int i_v = (int8_t)(( 112 * i_red  -  94 * i_green -
230                       18 * i_blue + 128) >> 8) + 128;
231     int refu = i_u - 0x80;         /*bright red*/
232     int refv = i_v - 0x80;
233     int reflength = sqrt(refu*refu+refv*refv);
234
235     while( p_in_u < p_in_end_u ) {
236         /* Length of color vector */
237         int inu = (*p_in_u) - 0x80;
238         int inv = (*p_in_v) - 0x80;
239         int length = sqrt(inu*inu+inv*inv);
240
241         int diffu = refu * length - inu *reflength;
242         int diffv = refv * length - inv *reflength;
243         long long int difflen2=diffu*diffu;
244         difflen2 +=diffv*diffv;
245         long long int thres = length*reflength;
246         thres *= thres;
247         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
248             *p_out_u = *p_in_u;
249             *p_out_v = *p_in_v;
250 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
251         }
252         p_in_u++;
253         p_in_v++;
254         p_out_u++;
255         p_out_v++;
256     }
257
258     return CopyInfoAndRelease( p_outpic, p_pic );
259 }
260
261 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
262                             vlc_value_t oldval, vlc_value_t newval, void *p_data )
263 {
264     (void)oldval;    (void)p_data;
265     filter_t *p_filter = (filter_t*)p_this;
266     filter_sys_t *p_sys = p_filter->p_sys;
267
268     if( !strcmp( psz_var, CFG_PREFIX "color" ) )
269     {
270         vlc_mutex_lock( &p_sys->lock );
271         p_sys->i_color = newval.i_int;
272         vlc_mutex_unlock( &p_sys->lock );
273     }
274     else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
275     {
276         vlc_mutex_lock( &p_sys->lock );
277         p_sys->i_simthres = newval.i_int;
278         vlc_mutex_unlock( &p_sys->lock );
279     }
280     else /* CFG_PREFIX "saturationthres" */
281     {
282         vlc_mutex_lock( &p_sys->lock );
283         p_sys->i_satthres = newval.i_int;
284         vlc_mutex_unlock( &p_sys->lock );
285     }
286
287     return VLC_SUCCESS;
288 }