From: <wt...@ke...> - 2008-05-29 11:30:22
|
CVS Root: /cvs/gstreamer Module: gst-plugins-good Changes by: wtay Date: Thu May 29 2008 11:30:30 UTC Log message: Based on patch by: Sebastian Keller <sebastian-keller at gmx dot de> * gst/alpha/gstalpha.c: (gst_alpha_class_init), (gst_alpha_init), (gst_alpha_set_property), (gst_alpha_get_property), (gst_alpha_chroma_key_ayuv), (gst_alpha_chromakey_row_i420): Try to skip pixels or areas that are too dark or too bright for us to do meaningfull color detection. Added properties to control the sensitivity to light and darkness. Added some small cleanups. Fixes #512345. Modified files: . : ChangeLog gst/alpha : gstalpha.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-good/ChangeLog.diff?r1=1.3500&r2=1.3501 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-good/gst/alpha/gstalpha.c.diff?r1=1.24&r2=1.25 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gst-plugins-good/ChangeLog,v retrieving revision 1.3500 retrieving revision 1.3501 diff -u -d -r1.3500 -r1.3501 --- ChangeLog 28 May 2008 20:01:29 -0000 1.3500 +++ ChangeLog 29 May 2008 11:30:14 -0000 1.3501 @@ -1,3 +1,15 @@ +2008-05-29 Wim Taymans <wim...@co...> + + Based on patch by: Sebastian Keller <sebastian-keller at gmx dot de> + * gst/alpha/gstalpha.c: (gst_alpha_class_init), (gst_alpha_init), + (gst_alpha_set_property), (gst_alpha_get_property), + (gst_alpha_chroma_key_ayuv), (gst_alpha_chromakey_row_i420): + Try to skip pixels or areas that are too dark or too bright for us to do + meaningfull color detection. + Added properties to control the sensitivity to light and darkness. + Added some small cleanups. Fixes #512345. 2008-05-28 Jan Schmidt <jan...@su...> * docs/plugins/.cvsignore: Index: gstalpha.c RCS file: /cvs/gstreamer/gst-plugins-good/gst/alpha/gstalpha.c,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- gstalpha.c 31 Jan 2008 00:00:23 -0000 1.24 +++ gstalpha.c 29 May 2008 11:30:16 -0000 1.25 @@ -81,6 +81,8 @@ gfloat angle; gfloat noise_level; + guint black_sensitivity; + guint white_sensitivity; gfloat y; /* chroma color */ gint8 cb, cr; @@ -121,18 +123,22 @@ #define DEFAULT_TARGET_B 0 #define DEFAULT_ANGLE 20.0 #define DEFAULT_NOISE_LEVEL 2.0 +#define DEFAULT_BLACK_SENSITIVITY 100 +#define DEFAULT_WHITE_SENSITIVITY 100 enum { - ARG_0, - ARG_METHOD, - ARG_ALPHA, - ARG_TARGET_R, - ARG_TARGET_G, - ARG_TARGET_B, - ARG_ANGLE, - ARG_NOISE_LEVEL, - /* FILL ME */ + PROP_0, + PROP_METHOD, + PROP_ALPHA, + PROP_TARGET_R, + PROP_TARGET_G, + PROP_TARGET_B, + PROP_ANGLE, + PROP_NOISE_LEVEL, + PROP_BLACK_SENSITIVITY, + PROP_WHITE_SENSITIVITY, + PROP_LAST }; static GstStaticPadTemplate gst_alpha_src_template = @@ -216,34 +222,45 @@ gobject_class->set_property = gst_alpha_set_property; gobject_class->get_property = gst_alpha_get_property; - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD, + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD, g_param_spec_enum ("method", "Method", "How the alpha channels should be created", GST_TYPE_ALPHA_METHOD, DEFAULT_METHOD, (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ALPHA, + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA, g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel", 0.0, 1.0, DEFAULT_ALPHA, (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TARGET_R, + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R, g_param_spec_uint ("target_r", "Target Red", "The Red target", 0, 255, DEFAULT_TARGET_R, - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TARGET_G, + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G, g_param_spec_uint ("target_g", "Target Green", "The Green target", 0, 255, DEFAULT_TARGET_G, - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TARGET_B, + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B, g_param_spec_uint ("target_b", "Target Blue", "The Blue target", 0, 255, DEFAULT_TARGET_B, - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ANGLE, + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE, g_param_spec_float ("angle", "Angle", "Size of the colorcube to change", 0.0, 90.0, DEFAULT_ANGLE, - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NOISE_LEVEL, + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL, g_param_spec_float ("noise_level", "Noise Level", "Size of noise radius", 0.0, 64.0, DEFAULT_NOISE_LEVEL, + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity", + "Black Sensitivity", "Sensitivity to dark colors", 0, 128, + DEFAULT_BLACK_SENSITIVITY, + (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); + PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity", + "Sensitivity", "Sensitivity to bright colors", 0, 128, + DEFAULT_WHITE_SENSITIVITY, btrans_class->start = GST_DEBUG_FUNCPTR (gst_alpha_start); btrans_class->transform = GST_DEBUG_FUNCPTR (gst_alpha_transform); @@ -262,6 +279,8 @@ alpha->target_b = DEFAULT_TARGET_B; alpha->angle = DEFAULT_ANGLE; alpha->noise_level = DEFAULT_NOISE_LEVEL; + alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY; + alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY; } /* do we need this function? */ @@ -276,7 +295,7 @@ alpha = GST_ALPHA (object); switch (prop_id) { - case ARG_METHOD: + case PROP_METHOD: alpha->method = g_value_get_enum (value); switch (alpha->method) { case ALPHA_METHOD_GREEN: @@ -294,29 +313,35 @@ } gst_alpha_init_params (alpha); break; - case ARG_ALPHA: + case PROP_ALPHA: alpha->alpha = g_value_get_double (value); - case ARG_TARGET_R: + case PROP_TARGET_R: alpha->target_r = g_value_get_uint (value); - case ARG_TARGET_G: + case PROP_TARGET_G: alpha->target_g = g_value_get_uint (value); - case ARG_TARGET_B: + case PROP_TARGET_B: alpha->target_b = g_value_get_uint (value); - case ARG_ANGLE: + case PROP_ANGLE: alpha->angle = g_value_get_float (value); - case ARG_NOISE_LEVEL: + case PROP_NOISE_LEVEL: alpha->noise_level = g_value_get_float (value); + case PROP_BLACK_SENSITIVITY: + alpha->black_sensitivity = g_value_get_uint (value); + break; + case PROP_WHITE_SENSITIVITY: + alpha->white_sensitivity = g_value_get_uint (value); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -333,27 +358,33 @@ g_value_set_enum (value, alpha->method); g_value_set_double (value, alpha->alpha); g_value_set_uint (value, alpha->target_r); g_value_set_uint (value, alpha->target_g); g_value_set_uint (value, alpha->target_b); g_value_set_float (value, alpha->angle); g_value_set_float (value, alpha->noise_level); + g_value_set_uint (value, alpha->black_sensitivity); + g_value_set_uint (value, alpha->white_sensitivity); @@ -525,6 +556,10 @@ gint x, z, u, v, y, a; gint tmp, tmp1; gint x1, y1; + gint smin, smax; + smin = 128 - alpha->black_sensitivity; + smax = 128 + alpha->white_sensitivity; src1 = src; dest1 = dest; @@ -536,6 +571,114 @@ u = *src1++ - 128; v = *src1++ - 128; + if (y < smin || y > smax) { + /* too dark or too bright, keep alpha */ + b_alpha = a; + } else { + /* Convert foreground to XZ coords where X direction is defined by + the key color */ + tmp = ((short) u * alpha->cb + (short) v * alpha->cr) >> 7; + x = CLAMP (tmp, -128, 127); + tmp = ((short) v * alpha->cb - (short) u * alpha->cr) >> 7; + z = CLAMP (tmp, -128, 127); + /* WARNING: accept angle should never be set greater than "somewhat less + than 90 degrees" to avoid dealing with negative/infinite tg. In reality, + 80 degrees should be enough if foreground is reasonable. If this seems + to be a problem, go to alternative ways of checking point position + (scalar product or line equations). This angle should not be too small + either to avoid infinite ctg (used to suppress foreground without use of + division) */ + tmp = ((short) (x) * alpha->accept_angle_tg) >> 4; + tmp = MIN (tmp, 127); + if (abs (z) > tmp) { + /* keep foreground Kfg = 0 */ + b_alpha = a; + } else { + /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord + according to Kfg */ + tmp = ((short) (z) * alpha->accept_angle_ctg) >> 4; + tmp = CLAMP (tmp, -128, 127); + x1 = abs (tmp); + y1 = z; + tmp1 = x - x1; + tmp1 = MAX (tmp1, 0); + b_alpha = (((unsigned char) (tmp1) * + (unsigned short) (alpha->one_over_kc)) / 2); + b_alpha = 255 - CLAMP (b_alpha, 0, 255); + b_alpha = (a * b_alpha) >> 8; + tmp = ((unsigned short) (tmp1) * alpha->kfgy_scale) >> 4; + tmp1 = MIN (tmp, 255); + tmp = y - tmp1; + y = MAX (tmp, 0); + /* Convert suppressed foreground back to CbCr */ + tmp = ((char) (x1) * (short) (alpha->cb) - + (char) (y1) * (short) (alpha->cr)) >> 7; + u = CLAMP (tmp, -128, 127); + tmp = ((char) (x1) * (short) (alpha->cr) + + (char) (y1) * (short) (alpha->cb)) >> 7; + v = CLAMP (tmp, -128, 127); + /* Deal with noise. For now, a circle around the key color with + radius of noise_level treated as exact key color. Introduces + sharp transitions. + */ + tmp = z * (short) (z) + (x - alpha->kg) * (short) (x - alpha->kg); + tmp = MIN (tmp, 0xffff); + if (tmp < alpha->noise_level * alpha->noise_level) { + b_alpha = 0; + } + } + } + u += 128; + v += 128; + *dest1++ = b_alpha; + *dest1++ = y; + *dest1++ = u; + *dest1++ = v; + } + } +} +static void +gst_alpha_chromakey_row_i420 (GstAlpha * alpha, guint8 * dest1, guint8 * dest2, + guint8 * srcY1, guint8 * srcY2, guint8 * srcU, guint8 * srcV, gint width) +{ + gint xpos; + gint b_alpha; + gint x, z, u, v, y11, y12, y21, y22, a; + gint tmp, tmp1; + gint x1, y1; + a = 255 * alpha->alpha; + for (xpos = 0; xpos < width / 2; xpos++) { + y11 = *srcY1++; + y12 = *srcY1++; + y21 = *srcY2++; + y22 = *srcY2++; + u = *srcU++ - 128; + v = *srcV++ - 128; + if (y11 < smin || y11 > smax || + y12 < smin || y12 > smax || + y21 < smin || y21 > smax || y22 < smin || y22 > smax) { + /* too dark or too bright, make opaque */ + b_alpha = 255; + } else { /* Convert foreground to XZ coords where X direction is defined by the key color */ tmp = ((short) u * alpha->cb + (short) v * alpha->cr) >> 7; @@ -556,7 +699,7 @@ if (abs (z) > tmp) { /* keep foreground Kfg = 0 */ - b_alpha = a; + b_alpha = 255; } else { /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord according to Kfg */ @@ -575,8 +718,14 @@ tmp = ((unsigned short) (tmp1) * alpha->kfgy_scale) >> 4; tmp1 = MIN (tmp, 255); - tmp = y - tmp1; - y = MAX (tmp, 0); + tmp = y11 - tmp1; + y11 = MAX (tmp, 0); + tmp = y12 - tmp1; + y12 = MAX (tmp, 0); + tmp = y21 - tmp1; + y21 = MAX (tmp, 0); + tmp = y22 - tmp1; + y22 = MAX (tmp, 0); /* Convert suppressed foreground back to CbCr */ tmp = ((char) (x1) * (short) (alpha->cb) - @@ -595,109 +744,10 @@ tmp = MIN (tmp, 0xffff); if (tmp < alpha->noise_level * alpha->noise_level) { + /* Uncomment this if you want total suppression within the noise circle */ b_alpha = 0; } - - u += 128; - v += 128; - *dest1++ = b_alpha; - *dest1++ = y; - *dest1++ = u; - *dest1++ = v; - } - } -} -static void -gst_alpha_chromakey_row_i420 (GstAlpha * alpha, guint8 * dest1, guint8 * dest2, - guint8 * srcY1, guint8 * srcY2, guint8 * srcU, guint8 * srcV, gint width) -{ - gint xpos; - gint b_alpha; - gint x, z, u, v, y11, y12, y21, y22, a; - gint tmp, tmp1; - gint x1, y1; - a = 255 * alpha->alpha; - for (xpos = 0; xpos < width / 2; xpos++) { - y11 = *srcY1++; - y12 = *srcY1++; - y21 = *srcY2++; - y22 = *srcY2++; - u = *srcU++ - 128; - v = *srcV++ - 128; - /* Convert foreground to XZ coords where X direction is defined by - the key color */ - tmp = ((short) u * alpha->cb + (short) v * alpha->cr) >> 7; - x = CLAMP (tmp, -128, 127); - tmp = ((short) v * alpha->cb - (short) u * alpha->cr) >> 7; - z = CLAMP (tmp, -128, 127); - /* WARNING: accept angle should never be set greater than "somewhat less - than 90 degrees" to avoid dealing with negative/infinite tg. In reality, - 80 degrees should be enough if foreground is reasonable. If this seems - to be a problem, go to alternative ways of checking point position - (scalar product or line equations). This angle should not be too small - either to avoid infinite ctg (used to suppress foreground without use of - division) */ - tmp = ((short) (x) * alpha->accept_angle_tg) >> 4; - tmp = MIN (tmp, 127); - if (abs (z) > tmp) { - /* keep foreground Kfg = 0 */ - b_alpha = 255; - } else { - /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord - according to Kfg */ - tmp = ((short) (z) * alpha->accept_angle_ctg) >> 4; - tmp = CLAMP (tmp, -128, 127); - x1 = abs (tmp); - y1 = z; - tmp1 = x - x1; - tmp1 = MAX (tmp1, 0); - b_alpha = (((unsigned char) (tmp1) * - (unsigned short) (alpha->one_over_kc)) / 2); - b_alpha = 255 - CLAMP (b_alpha, 0, 255); - b_alpha = (a * b_alpha) >> 8; - tmp = ((unsigned short) (tmp1) * alpha->kfgy_scale) >> 4; - tmp1 = MIN (tmp, 255); - tmp = y11 - tmp1; - y11 = MAX (tmp, 0); - tmp = y12 - tmp1; - y12 = MAX (tmp, 0); - tmp = y21 - tmp1; - y21 = MAX (tmp, 0); - tmp = y22 - tmp1; - y22 = MAX (tmp, 0); - /* Convert suppressed foreground back to CbCr */ - tmp = ((char) (x1) * (short) (alpha->cb) - - (char) (y1) * (short) (alpha->cr)) >> 7; - u = CLAMP (tmp, -128, 127); - tmp = ((char) (x1) * (short) (alpha->cr) + - (char) (y1) * (short) (alpha->cb)) >> 7; - v = CLAMP (tmp, -128, 127); - /* Deal with noise. For now, a circle around the key color with - radius of noise_level treated as exact key color. Introduces - sharp transitions. - */ - tmp = z * (short) (z) + (x - alpha->kg) * (short) (x - alpha->kg); - tmp = MIN (tmp, 0xffff); - if (tmp < alpha->noise_level * alpha->noise_level) { - /* Uncomment this if you want total suppression within the noise circle */ - b_alpha = 0; - } } u += 128; |