1 /*****************************************************************************
2 * colorthres.c: Theshold color based on similarity to reference color
3 *****************************************************************************
4 * Copyright (C) 2000-2006 the VideoLAN team
7 * Authors: Sigmund Augdal <dnumgis@videolan.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
36 #include "vlc_filter.h"
38 /*****************************************************************************
40 *****************************************************************************/
41 static int Create ( vlc_object_t * );
42 static void Destroy ( vlc_object_t * );
44 static picture_t *Filter( filter_t *, picture_t * );
46 /*****************************************************************************
48 *****************************************************************************/
49 #define COLOR_TEXT N_("Color")
50 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
51 "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
52 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
53 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
54 static int pi_color_values[] = {
55 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
57 static char *ppsz_color_descriptions[] = {
58 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
62 set_description( _("Color threshold filter") );
63 set_shortname( _("Color threshold" ));
64 set_category( CAT_VIDEO );
65 set_subcategory( SUBCAT_VIDEO_VFILTER );
66 set_capability( "video filter2", 0 );
67 add_integer( "colorthres-color", 0x00FF0000, NULL, COLOR_TEXT,
68 COLOR_LONGTEXT, VLC_FALSE );
69 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
70 add_integer( "colorthres-saturationthres", 20, NULL, "saturaton threshold",
72 add_integer( "colorthres-similaritythres", 15, NULL, "similarity threshold",
74 set_callbacks( Create, Destroy );
77 /*****************************************************************************
78 * filter_sys_t: adjust filter method descriptor
79 *****************************************************************************/
84 /*****************************************************************************
85 * Create: allocates adjust video thread output method
86 *****************************************************************************
87 * This function allocates and initializes a adjust vout method.
88 *****************************************************************************/
89 static int Create( vlc_object_t *p_this )
91 filter_t *p_filter = (filter_t *)p_this;
93 /* XXX: we might need to add/remove some FOURCCs ... */
94 if( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','0') )
96 msg_Err( p_filter, "Unsupported input chroma (%4s)",
97 (char*)&(p_filter->fmt_in.video.i_chroma) );
101 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
103 msg_Err( p_filter, "Input and output chromas don't match" );
107 var_Create( p_filter, "colorthres-color", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
108 var_Create( p_filter, "colorthres-similaritythres", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
109 var_Create( p_filter, "colorthres-saturationthres", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
110 /* Allocate structure */
111 p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
112 if( p_filter->p_sys == NULL )
114 msg_Err( p_filter, "out of memory" );
118 p_filter->pf_video_filter = Filter;
123 /*****************************************************************************
124 * Destroy: destroy adjust video thread output method
125 *****************************************************************************
126 * Terminate an output method created by adjustCreateOutputMethod
127 *****************************************************************************/
128 static void Destroy( vlc_object_t *p_this )
130 filter_t *p_filter = (filter_t *)p_this;
131 free( p_filter->p_sys );
134 /*****************************************************************************
135 * Render: displays previously rendered output
136 *****************************************************************************
137 * This function send the currently rendered image to adjust modified image,
138 * waits until it is displayed and switch the two rendering buffers, preparing
140 *****************************************************************************/
141 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
144 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
145 uint8_t *p_out_y, *p_out_u, *p_out_v;
146 int i_simthres = var_GetInteger( p_filter, "colorthres-similaritythres" );
147 int i_satthres = var_GetInteger( p_filter, "colorthres-saturationthres" );
148 int i_color = var_GetInteger( p_filter, "colorthres-color" );
150 if( !p_pic ) return NULL;
152 p_outpic = p_filter->pf_vout_buffer_new( p_filter );
155 msg_Warn( p_filter, "can't get output picture" );
156 if( p_pic->pf_release )
157 p_pic->pf_release( p_pic );
161 p_in_u = p_pic->p[U_PLANE].p_pixels;
162 p_in_v = p_pic->p[V_PLANE].p_pixels;
163 p_in_y = p_pic->p[Y_PLANE].p_pixels;
164 p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
165 * p_pic->p[U_PLANE].i_pitch - 8;
167 p_out_y = p_outpic->p[Y_PLANE].p_pixels;
168 p_out_u = p_outpic->p[U_PLANE].p_pixels;
169 p_out_v = p_outpic->p[V_PLANE].p_pixels;
171 /* Create grayscale version of input */
172 memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
173 * p_pic->p[Y_PLANE].i_pitch - 8 );
174 memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
175 * p_pic->p[U_PLANE].i_pitch - 8 );
176 memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
177 * p_pic->p[U_PLANE].i_pitch - 8 );
181 * Do the U and V planes
183 int i_red = ( i_color & 0xFF0000 ) >> 16;
184 int i_green = ( i_color & 0xFF00 ) >> 8;
185 int i_blue = i_color & 0xFF;
186 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
187 112 * i_blue + 128) >> 8) + 128;
188 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
189 18 * i_blue + 128) >> 8) + 128;
190 int refu = i_u - 0x80; /*bright red*/
191 int refv = i_v - 0x80;
192 int reflength = sqrt(refu*refu+refv*refv);
194 while( p_in_u < p_in_end_u ) {
195 /* Length of color vector */
196 int inu = (*p_in_u) - 0x80;
197 int inv = (*p_in_v) - 0x80;
198 int length = sqrt(inu*inu+inv*inv);
200 int diffu = refu * length - inu *reflength;
201 int diffv = refv * length - inv *reflength;
202 long long int difflen2=diffu*diffu;
203 difflen2 +=diffv*diffv;
204 long long int thres = length*reflength;
206 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
209 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
219 p_outpic->date = p_pic->date;
220 p_outpic->b_force = p_pic->b_force;
221 p_outpic->i_nb_fields = p_pic->i_nb_fields;
222 p_outpic->b_progressive = p_pic->b_progressive;
223 p_outpic->b_top_field_first = p_pic->b_top_field_first;
225 if( p_pic->pf_release )
226 p_pic->pf_release( p_pic );