]> git.sesse.net Git - vlc/blob - modules/video_filter/colorthres.c
67ddf2429b83aca4c26a0c88c25ec6588218c448
[vlc] / modules / video_filter / colorthres.c
1 /*****************************************************************************
2  * colorthres.c: Theshold color based on similarity to reference color
3  *****************************************************************************
4  * Copyright (C) 2000-2006 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 #include <errno.h>
28 #include <math.h>
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_sout.h>
37 #include <vlc_vout.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 static const int pi_color_values[] = {
59   0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
60
61 static const char *const ppsz_color_descriptions[] = {
62   N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
63
64 #define CFG_PREFIX "colorthres-"
65
66 vlc_module_begin();
67     set_description( N_("Color threshold filter") );
68     set_shortname( N_("Color threshold" ));
69     set_category( CAT_VIDEO );
70     set_subcategory( SUBCAT_VIDEO_VFILTER );
71     set_capability( "video filter2", 0 );
72     add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
73                  COLOR_LONGTEXT, false );
74         change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
75     add_integer( CFG_PREFIX "saturationthres", 20, NULL,
76                  _("Saturaton threshold"), "", false );
77     add_integer( CFG_PREFIX "similaritythres", 15, NULL,
78                  _("Similarity threshold"), "", false );
79     set_callbacks( Create, Destroy );
80 vlc_module_end();
81
82 static const char *const ppsz_filter_options[] = {
83     "color", "saturationthes", "similaritythres", NULL
84 };
85
86 /*****************************************************************************
87  * filter_sys_t: adjust filter method descriptor
88  *****************************************************************************/
89 struct filter_sys_t
90 {
91 };
92
93 /*****************************************************************************
94  * Create: allocates adjust video thread output method
95  *****************************************************************************
96  * This function allocates and initializes a adjust vout method.
97  *****************************************************************************/
98 static int Create( vlc_object_t *p_this )
99 {
100     filter_t *p_filter = (filter_t *)p_this;
101
102     switch( p_filter->fmt_in.video.i_chroma )
103     {
104         CASE_PLANAR_YUV
105             break;
106
107         default:
108             msg_Err( p_filter, "Unsupported input chroma (%4s)",
109                      (char*)&(p_filter->fmt_in.video.i_chroma) );
110             return VLC_EGENERIC;
111     }
112
113     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
114     {
115         msg_Err( p_filter, "Input and output chromas don't match" );
116         return VLC_EGENERIC;
117     }
118
119     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
120                        p_filter->p_cfg );
121     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
122     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "similaritythres" );
123     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "saturationthres" );
124
125     /* Allocate structure */
126     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
127     if( p_filter->p_sys == NULL )
128     {
129         msg_Err( p_filter, "out of memory" );
130         return VLC_ENOMEM;
131     }
132
133     p_filter->pf_video_filter = Filter;
134
135     return VLC_SUCCESS;
136 }
137
138 /*****************************************************************************
139  * Destroy: destroy adjust video thread output method
140  *****************************************************************************
141  * Terminate an output method created by adjustCreateOutputMethod
142  *****************************************************************************/
143 static void Destroy( vlc_object_t *p_this )
144 {
145     filter_t *p_filter = (filter_t *)p_this;
146     free( p_filter->p_sys );
147 }
148
149 /*****************************************************************************
150  * Render: displays previously rendered output
151  *****************************************************************************
152  * This function send the currently rendered image to adjust modified image,
153  * waits until it is displayed and switch the two rendering buffers, preparing
154  * next frame.
155  *****************************************************************************/
156 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
157 {
158     picture_t *p_outpic;
159     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
160     uint8_t *p_out_y, *p_out_u, *p_out_v;
161     int i_simthres = var_GetInteger( p_filter, "colorthres-similaritythres" );
162     int i_satthres = var_GetInteger( p_filter, "colorthres-saturationthres" );
163     int i_color = var_GetInteger( p_filter, "colorthres-color" );
164
165     if( !p_pic ) return NULL;
166
167     p_outpic = p_filter->pf_vout_buffer_new( p_filter );
168     if( !p_outpic )
169     {
170         msg_Warn( p_filter, "can't get output picture" );
171         if( p_pic->pf_release )
172             p_pic->pf_release( p_pic );
173         return NULL;
174     }
175
176     p_in_u = p_pic->p[U_PLANE].p_pixels;
177     p_in_v = p_pic->p[V_PLANE].p_pixels;
178     p_in_y = p_pic->p[Y_PLANE].p_pixels;
179     p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
180                         * p_pic->p[U_PLANE].i_pitch - 8;
181
182     p_out_y = p_outpic->p[Y_PLANE].p_pixels;
183     p_out_u = p_outpic->p[U_PLANE].p_pixels;
184     p_out_v = p_outpic->p[V_PLANE].p_pixels;
185
186     /* Create grayscale version of input */
187     vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
188                * p_pic->p[Y_PLANE].i_pitch - 8 );
189     vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
190                * p_pic->p[U_PLANE].i_pitch - 8 );
191     vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
192                * p_pic->p[U_PLANE].i_pitch - 8 );
193
194     /*
195      * Do the U and V planes
196      */
197     int i_red = ( i_color & 0xFF0000 ) >> 16;
198     int i_green = ( i_color & 0xFF00 ) >> 8;
199     int i_blue = i_color & 0xFF;
200     int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
201                      112 * i_blue + 128) >> 8) + 128;
202     int i_v = (int8_t)(( 112 * i_red  -  94 * i_green -
203                       18 * i_blue + 128) >> 8) + 128;
204     int refu = i_u - 0x80;         /*bright red*/
205     int refv = i_v - 0x80;
206     int reflength = sqrt(refu*refu+refv*refv);
207
208     while( p_in_u < p_in_end_u ) {
209         /* Length of color vector */
210         int inu = (*p_in_u) - 0x80;
211         int inv = (*p_in_v) - 0x80;
212         int length = sqrt(inu*inu+inv*inv);
213
214         int diffu = refu * length - inu *reflength;
215         int diffv = refv * length - inv *reflength;
216         long long int difflen2=diffu*diffu;
217         difflen2 +=diffv*diffv;
218         long long int thres = length*reflength;
219         thres *= thres;
220         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
221             *p_out_u = *p_in_u;
222             *p_out_v = *p_in_v;
223 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
224         }
225         p_in_u++;
226         p_in_v++;
227         p_out_u++;
228         p_out_v++;
229     }
230
231     return CopyInfoAndRelease( p_outpic, p_pic );
232 }