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 const 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 */
173 pf_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
174 * p_pic->p[Y_PLANE].i_pitch - 8 );
176 pf_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
177 * p_pic->p[U_PLANE].i_pitch - 8 );
179 pf_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
180 * p_pic->p[U_PLANE].i_pitch - 8 );
183 * Do the U and V planes
185 int i_red = ( i_color & 0xFF0000 ) >> 16;
186 int i_green = ( i_color & 0xFF00 ) >> 8;
187 int i_blue = i_color & 0xFF;
188 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
189 112 * i_blue + 128) >> 8) + 128;
190 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
191 18 * i_blue + 128) >> 8) + 128;
192 int refu = i_u - 0x80; /*bright red*/
193 int refv = i_v - 0x80;
194 int reflength = sqrt(refu*refu+refv*refv);
196 while( p_in_u < p_in_end_u ) {
197 /* Length of color vector */
198 int inu = (*p_in_u) - 0x80;
199 int inv = (*p_in_v) - 0x80;
200 int length = sqrt(inu*inu+inv*inv);
202 int diffu = refu * length - inu *reflength;
203 int diffv = refv * length - inv *reflength;
204 long long int difflen2=diffu*diffu;
205 difflen2 +=diffv*diffv;
206 long long int thres = length*reflength;
208 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
211 // 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 );