mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 10:41:04 +00:00
[440/906] sobel: implement sobel filter using separable kernels
Reimplement sobel in a multipass fully separated convolution: - calculate x gradient map convolving first horizontally with blurring kernel and then vertically with differentiating kernel - calculate y gradient map convolving first vertically with blurring kernel and then horizonally with differentiating kernel - calculate length of the gradient vector Particular care was needed with normalization of the blurring kernel and with grey level offset of the differentiating one to prevent overflow of rgb values from the [0.0,1.0] range in intermediate passes. Now works on i915.
This commit is contained in:
parent
002f069962
commit
49df4dca3c
4 changed files with 229 additions and 63 deletions
|
@ -308,8 +308,63 @@ const gchar *sobel_fragment_source =
|
|||
" gl_FragColor = vec4(vec3(g), 1.0);"
|
||||
"}";
|
||||
|
||||
const gchar *sobel_gradient_length_fragment_source =
|
||||
"#extension GL_ARB_texture_rectangle : enable\n"
|
||||
"uniform sampler2DRect gx;"
|
||||
"uniform sampler2DRect gy;"
|
||||
"void main () {"
|
||||
" vec4 dx = texture2DRect (gx, gl_TexCoord[0].st);"
|
||||
" vec4 dy = texture2DRect (gy, gl_TexCoord[0].st);"
|
||||
" dx = (dx - 0.5);"
|
||||
" dy = (dy - 0.5);"
|
||||
" gl_FragColor = vec4(sqrt(dx*dx + dy*dy));"
|
||||
"}";
|
||||
|
||||
/* horizontal convolution */
|
||||
/* horizontal convolution 3x3 */
|
||||
const gchar *hconv3_fragment_source =
|
||||
"#extension GL_ARB_texture_rectangle : enable\n"
|
||||
"uniform sampler2DRect tex;"
|
||||
"uniform float kernel[3];"
|
||||
"uniform float offset;"
|
||||
"void main () {"
|
||||
" vec2 texturecoord[3];"
|
||||
" float s = gl_TexCoord[0].s;"
|
||||
" float t = gl_TexCoord[0].t;"
|
||||
" texturecoord[0] = vec2(s-1.0, t);"
|
||||
" texturecoord[1] = vec2(s, t);"
|
||||
" texturecoord[2] = vec2(s+1.0, t);"
|
||||
" int i;"
|
||||
" vec4 sum = vec4 (0.0);"
|
||||
" for (i = 0; i < 3; i++) { "
|
||||
" vec4 neighbor = texture2DRect(tex, texturecoord[i]); "
|
||||
" sum += neighbor * kernel[i];"
|
||||
" }"
|
||||
" gl_FragColor = sum + offset;"
|
||||
"}";
|
||||
|
||||
/* vertical convolution 3x3 */
|
||||
const gchar *vconv3_fragment_source =
|
||||
"#extension GL_ARB_texture_rectangle : enable\n"
|
||||
"uniform sampler2DRect tex;"
|
||||
"uniform float kernel[3];"
|
||||
"uniform float offset;"
|
||||
"void main () {"
|
||||
" vec2 texturecoord[3];"
|
||||
" float s = gl_TexCoord[0].s;"
|
||||
" float t = gl_TexCoord[0].t;"
|
||||
" texturecoord[0] = vec2(s, t-1.0);"
|
||||
" texturecoord[1] = vec2(s, t);"
|
||||
" texturecoord[2] = vec2(s, t+1.0);"
|
||||
" int i;"
|
||||
" vec4 sum = vec4 (0.0);"
|
||||
" for (i = 0; i < 3; i++) { "
|
||||
" vec4 neighbor = texture2DRect(tex, texturecoord[i]);"
|
||||
" sum += neighbor * kernel[i]; "
|
||||
" }"
|
||||
" gl_FragColor = sum + offset;"
|
||||
"}";
|
||||
|
||||
/* horizontal convolution 9x9 */
|
||||
const gchar *hconv9_fragment_source =
|
||||
"#extension GL_ARB_texture_rectangle : enable\n"
|
||||
"uniform sampler2DRect tex;"
|
||||
|
@ -336,7 +391,7 @@ const gchar *hconv9_fragment_source =
|
|||
" gl_FragColor = sum;"
|
||||
"}";
|
||||
|
||||
/* vertical convolution */
|
||||
/* vertical convolution 9x9 */
|
||||
const gchar *vconv9_fragment_source =
|
||||
"#extension GL_ARB_texture_rectangle : enable\n"
|
||||
"uniform sampler2DRect tex;"
|
||||
|
|
|
@ -33,6 +33,9 @@ extern const gchar *bulge_fragment_source;
|
|||
extern const gchar *square_fragment_source;
|
||||
extern const gchar *luma_threshold_fragment_source;
|
||||
extern const gchar *sobel_fragment_source;
|
||||
extern const gchar *sobel_gradient_length_fragment_source;
|
||||
extern const gchar *hconv3_fragment_source;
|
||||
extern const gchar *vconv3_fragment_source;
|
||||
extern const gchar *hconv9_fragment_source;
|
||||
extern const gchar *vconv9_fragment_source;
|
||||
extern const gchar *sum_fragment_source;
|
||||
|
|
|
@ -65,32 +65,56 @@ static void gst_gl_filtersobel_draw_texture (GstGLFilterSobel * filtersobel,
|
|||
static void gst_gl_filtersobel_init_shader (GstGLFilter * filter);
|
||||
static gboolean gst_gl_filtersobel_filter (GstGLFilter * filter,
|
||||
GstGLBuffer * inbuf, GstGLBuffer * outbuf);
|
||||
static void gst_gl_filtersobel_callback (gint width, gint height, guint texture,
|
||||
static void gst_gl_filtersobel_step_one (gint width, gint height, guint texture,
|
||||
gpointer stuff);
|
||||
static void gst_gl_filtersobel_step_two (gint width, gint height, guint texture,
|
||||
gpointer stuff);
|
||||
static void gst_gl_filtersobel_step_three (gint width, gint height,
|
||||
guint texture, gpointer stuff);
|
||||
static void gst_gl_filtersobel_step_four (gint width, gint height,
|
||||
guint texture, gpointer stuff);
|
||||
static void gst_gl_filtersobel_step_five (gint width, gint height,
|
||||
guint texture, gpointer stuff);
|
||||
|
||||
static gfloat grad_kern[3] = {
|
||||
1.0, 0.0, -1.0,
|
||||
};
|
||||
|
||||
static gfloat blur_kern[3] = {
|
||||
1.0 / 4.0, 2.0 / 4.0, 1.0 / 4.0,
|
||||
};
|
||||
|
||||
static void
|
||||
gst_gl_filtersobel_init_resources (GstGLFilter * filter)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
|
||||
int i;
|
||||
|
||||
glGenTextures (1, &filtersobel->midtexture);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, filtersobel->midtexture);
|
||||
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
|
||||
filter->width, filter->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
for (i = 0; i < 5; i++) {
|
||||
glGenTextures (1, &filtersobel->midtexture[i]);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, filtersobel->midtexture[i]);
|
||||
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
|
||||
filter->width, filter->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
|
||||
GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_filtersobel_reset_resources (GstGLFilter * filter)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
|
||||
int i;
|
||||
|
||||
glDeleteTextures (1, &filtersobel->midtexture);
|
||||
for (i = 0; i < 5; i++) {
|
||||
glDeleteTextures (1, &filtersobel->midtexture[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -132,9 +156,13 @@ static void
|
|||
gst_gl_filtersobel_init (GstGLFilterSobel * filtersobel,
|
||||
GstGLFilterSobelClass * klass)
|
||||
{
|
||||
filtersobel->shader0 = NULL;
|
||||
filtersobel->midtexture = 0;
|
||||
int i;
|
||||
filtersobel->hconv = NULL;
|
||||
filtersobel->vconv = NULL;
|
||||
filtersobel->invert = FALSE;
|
||||
for (i = 0; i < 5; i++) {
|
||||
filtersobel->midtexture[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -143,7 +171,9 @@ gst_gl_filter_filtersobel_reset (GstGLFilter * filter)
|
|||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
|
||||
|
||||
//blocking call, wait the opengl thread has destroyed the shader
|
||||
gst_gl_display_del_shader (filter->display, filtersobel->shader0);
|
||||
gst_gl_display_del_shader (filter->display, filtersobel->hconv);
|
||||
gst_gl_display_del_shader (filter->display, filtersobel->vconv);
|
||||
gst_gl_display_del_shader (filter->display, filtersobel->len);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -184,8 +214,12 @@ gst_gl_filtersobel_init_shader (GstGLFilter * filter)
|
|||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
|
||||
|
||||
//blocking call, wait the opengl thread has compiled the shader
|
||||
gst_gl_display_gen_shader (filter->display, 0, sobel_fragment_source,
|
||||
&filtersobel->shader0);
|
||||
gst_gl_display_gen_shader (filter->display, 0, hconv3_fragment_source,
|
||||
&filtersobel->hconv);
|
||||
gst_gl_display_gen_shader (filter->display, 0, vconv3_fragment_source,
|
||||
&filtersobel->vconv);
|
||||
gst_gl_display_gen_shader (filter->display, 0,
|
||||
sobel_gradient_length_fragment_source, &filtersobel->len);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -211,71 +245,143 @@ gst_gl_filtersobel_draw_texture (GstGLFilterSobel * filtersobel, GLuint tex)
|
|||
glEnd ();
|
||||
}
|
||||
|
||||
/*static void
|
||||
change_view (GstGLDisplay *display, gpointer data)
|
||||
{
|
||||
// GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (data);
|
||||
|
||||
const double mirrormatrix[16] = {
|
||||
-1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
};
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadMatrixd (mirrormatrix);
|
||||
}*/
|
||||
|
||||
static gboolean
|
||||
gst_gl_filtersobel_filter (GstGLFilter * filter, GstGLBuffer * inbuf,
|
||||
GstGLBuffer * outbuf)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
|
||||
|
||||
// gst_gl_display_thread_add (filter->display, change_view, filtersobel);
|
||||
|
||||
gst_gl_filter_render_to_target (filter, inbuf->texture, outbuf->texture,
|
||||
gst_gl_filtersobel_callback, filtersobel);
|
||||
gst_gl_filter_render_to_target (filter, inbuf->texture,
|
||||
filtersobel->midtexture[0], gst_gl_filtersobel_step_one, filtersobel);
|
||||
gst_gl_filter_render_to_target (filter, filtersobel->midtexture[0],
|
||||
filtersobel->midtexture[1], gst_gl_filtersobel_step_two, filtersobel);
|
||||
gst_gl_filter_render_to_target (filter, inbuf->texture,
|
||||
filtersobel->midtexture[2], gst_gl_filtersobel_step_three, filtersobel);
|
||||
gst_gl_filter_render_to_target (filter, filtersobel->midtexture[2],
|
||||
filtersobel->midtexture[3], gst_gl_filtersobel_step_four, filtersobel);
|
||||
gst_gl_filter_render_to_target (filter, filtersobel->midtexture[3],
|
||||
outbuf->texture, gst_gl_filtersobel_step_five, filtersobel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_filtersobel_callback (gint width, gint height, guint texture,
|
||||
gst_gl_filtersobel_step_one (gint width, gint height, guint texture,
|
||||
gpointer stuff)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (stuff);
|
||||
|
||||
gfloat hkern[9] = {
|
||||
1.0, 0.0, -1.0,
|
||||
2.0, 0.0, -2.0,
|
||||
1.0, 0.0, -1.0
|
||||
};
|
||||
|
||||
gfloat vkern[9] = {
|
||||
1.0, 2.0, 1.0,
|
||||
0.0, 0.0, 0.0,
|
||||
-1.0, -2.0, -1.0
|
||||
};
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
|
||||
gst_gl_shader_use (filtersobel->shader0);
|
||||
gst_gl_shader_use (filtersobel->hconv);
|
||||
|
||||
glActiveTexture (GL_TEXTURE1);
|
||||
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->shader0, "tex", 1);
|
||||
|
||||
gst_gl_shader_set_uniform_1fv (filtersobel->shader0, "hkern", 9, hkern);
|
||||
gst_gl_shader_set_uniform_1fv (filtersobel->shader0, "vkern", 9, vkern);
|
||||
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->shader0, "invert",
|
||||
filtersobel->invert);
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->hconv, "tex", 1);
|
||||
gst_gl_shader_set_uniform_1fv (filtersobel->hconv, "kernel", 3, blur_kern);
|
||||
gst_gl_shader_set_uniform_1f (filtersobel->hconv, "offset", 0.0);
|
||||
|
||||
gst_gl_filtersobel_draw_texture (filtersobel, texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_filtersobel_step_two (gint width, gint height, guint texture,
|
||||
gpointer stuff)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (stuff);
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
|
||||
gst_gl_shader_use (filtersobel->vconv);
|
||||
|
||||
glActiveTexture (GL_TEXTURE1);
|
||||
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->vconv, "tex", 1);
|
||||
gst_gl_shader_set_uniform_1fv (filtersobel->vconv, "kernel", 3, grad_kern);
|
||||
gst_gl_shader_set_uniform_1f (filtersobel->vconv, "offset", 0.5);
|
||||
|
||||
gst_gl_filtersobel_draw_texture (filtersobel, texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_filtersobel_step_three (gint width, gint height, guint texture,
|
||||
gpointer stuff)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (stuff);
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
|
||||
gst_gl_shader_use (filtersobel->vconv);
|
||||
|
||||
glActiveTexture (GL_TEXTURE1);
|
||||
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->vconv, "tex", 1);
|
||||
gst_gl_shader_set_uniform_1fv (filtersobel->vconv, "kernel", 3, blur_kern);
|
||||
gst_gl_shader_set_uniform_1f (filtersobel->vconv, "offset", 0.0);
|
||||
|
||||
gst_gl_filtersobel_draw_texture (filtersobel, texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_filtersobel_step_four (gint width, gint height, guint texture,
|
||||
gpointer stuff)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (stuff);
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
|
||||
gst_gl_shader_use (filtersobel->hconv);
|
||||
|
||||
glActiveTexture (GL_TEXTURE1);
|
||||
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->hconv, "tex", 1);
|
||||
gst_gl_shader_set_uniform_1fv (filtersobel->hconv, "kernel", 3, grad_kern);
|
||||
gst_gl_shader_set_uniform_1f (filtersobel->vconv, "offset", 0.5);
|
||||
|
||||
gst_gl_filtersobel_draw_texture (filtersobel, texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gl_filtersobel_step_five (gint width, gint height, guint texture,
|
||||
gpointer stuff)
|
||||
{
|
||||
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (stuff);
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
|
||||
gst_gl_shader_use (filtersobel->len);
|
||||
|
||||
glActiveTexture (GL_TEXTURE1);
|
||||
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, filtersobel->midtexture[1]);
|
||||
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->len, "gx", 1);
|
||||
|
||||
glActiveTexture (GL_TEXTURE2);
|
||||
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, filtersobel->midtexture[3]);
|
||||
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
|
||||
gst_gl_shader_set_uniform_1i (filtersobel->len, "gy", 2);
|
||||
|
||||
|
||||
gst_gl_filtersobel_draw_texture (filtersobel, texture);
|
||||
}
|
||||
|
|
|
@ -36,11 +36,13 @@ typedef struct _GstGLFilterSobelClass GstGLFilterSobelClass;
|
|||
struct _GstGLFilterSobel
|
||||
{
|
||||
GstGLFilter filter;
|
||||
GstGLShader *shader0;
|
||||
GstGLShader *hconv;
|
||||
GstGLShader *vconv;
|
||||
GstGLShader *len;
|
||||
|
||||
GLuint midtexture[5];
|
||||
|
||||
gboolean invert;
|
||||
|
||||
GLuint midtexture;
|
||||
};
|
||||
|
||||
struct _GstGLFilterSobelClass
|
||||
|
|
Loading…
Reference in a new issue