From b608767288b738889b4afaf6141fa92c72bb5645 Mon Sep 17 00:00:00 2001 From: William Manley Date: Wed, 20 Jun 2012 15:05:40 +0100 Subject: [PATCH] templatematch: Allow changing template property on the fly Previously changing the template property resulted in an exception thrown from cvMatchTemplate, because "dist_image" (the intermediate match-certainty-distribution) was the wrong size (because the template image size had changed). Locking has also been added to allow changing the properties (e.g. the pattern to match) while the pipeline is playing. * gst_element_post_message is moved outside of the lock, because it will call into arbitrary user code (otherwise, if that user code calls into gst_templatematch_set_property on this same thread it would deadlock). * gst_template_match_load_template: If we fail to load the new template we still unload the previous template, so this element becomes a no-op in the pipeline. The alternative would be to keep the previous template; I believe unloading the previous template is a better choice, because it is consistent with the state this element would be in if it fails to load the very first template at start-up. Thanks to Will Manley for the bulk of this work; any errors are probably mine. --- ext/opencv/gsttemplatematch.c | 54 ++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/ext/opencv/gsttemplatematch.c b/ext/opencv/gsttemplatematch.c index aea85d660d..7123bdbf27 100644 --- a/ext/opencv/gsttemplatematch.c +++ b/ext/opencv/gsttemplatematch.c @@ -113,7 +113,8 @@ static gboolean gst_template_match_handle_sink_event (GstPad * pad, static GstFlowReturn gst_template_match_chain (GstPad * pad, GstObject * parent, GstBuffer * buf); -static void gst_template_match_load_template (GstTemplateMatch * filter); +static void gst_template_match_load_template (GstTemplateMatch * filter, + gchar * template); static void gst_template_match_match (IplImage * input, IplImage * template, IplImage * dist_image, double *best_res, CvPoint * best_pos, int method); @@ -190,6 +191,7 @@ gst_template_match_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_METHOD: + GST_OBJECT_LOCK (filter); switch (g_value_get_int (value)) { case 0: filter->method = CV_TM_SQDIFF; @@ -210,13 +212,15 @@ gst_template_match_set_property (GObject * object, guint prop_id, filter->method = CV_TM_CCOEFF_NORMED; break; } + GST_OBJECT_UNLOCK (filter); break; case PROP_TEMPLATE: - filter->template = (char *) g_value_get_string (value); - gst_template_match_load_template (filter); + gst_template_match_load_template (filter, g_value_dup_string (value)); break; case PROP_DISPLAY: + GST_OBJECT_LOCK (filter); filter->display = g_value_get_boolean (value); + GST_OBJECT_UNLOCK (filter); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -290,6 +294,7 @@ gst_template_match_finalize (GObject * object) GstTemplateMatch *filter; filter = GST_TEMPLATE_MATCH (object); + g_free (filter->template); if (filter->cvImage) { cvReleaseImageHeader (&filter->cvImage); } @@ -313,6 +318,7 @@ gst_template_match_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) CvPoint best_pos; double best_res; GstMapInfo info; + GstMessage *m = NULL; filter = GST_TEMPLATE_MATCH (parent); @@ -325,6 +331,7 @@ gst_template_match_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) gst_buffer_map (buf, &info, GST_MAP_READWRITE); filter->cvImage->imageData = (char *) info.data; + GST_OBJECT_LOCK (filter); if (filter->cvTemplateImage && !filter->cvDistImage) { if (filter->cvTemplateImage->width > filter->cvImage->width) { GST_WARNING ("Template Image is wider than input image"); @@ -348,7 +355,6 @@ gst_template_match_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) } if (filter->cvTemplateImage && filter->cvImage && filter->cvDistImage) { GstStructure *s; - GstMessage *m; gst_template_match_match (filter->cvImage, filter->cvTemplateImage, filter->cvDistImage, &best_res, &best_pos, filter->method); @@ -361,7 +367,6 @@ gst_template_match_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) "result", G_TYPE_DOUBLE, best_res, NULL); m = gst_message_new_element (GST_OBJECT (filter), s); - gst_element_post_message (GST_ELEMENT (filter), m); if (filter->display) { CvPoint corner = best_pos; @@ -375,7 +380,11 @@ gst_template_match_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) } } + GST_OBJECT_UNLOCK (filter); + if (m) { + gst_element_post_message (GST_ELEMENT (filter), m); + } return gst_pad_push (filter->srcpad, buf); } @@ -402,22 +411,35 @@ gst_template_match_match (IplImage * input, IplImage * template, } +/* We take ownership of template here */ static void -gst_template_match_load_template (GstTemplateMatch * filter) +gst_template_match_load_template (GstTemplateMatch * filter, gchar * template) { - if (filter->template) { + gchar *oldTemplateFilename = NULL; + IplImage *oldTemplateImage = NULL, *newTemplateImage = NULL, *oldDistImage = + NULL; - if (filter->cvTemplateImage) { - cvReleaseImage (&filter->cvTemplateImage); - } - filter->cvTemplateImage = - cvLoadImage (filter->template, CV_LOAD_IMAGE_COLOR); - - if (!filter->cvTemplateImage) { - GST_WARNING ("Couldn't load template image: %s. error: %s", - filter->template, g_strerror (errno)); + if (template) { + newTemplateImage = cvLoadImage (template, CV_LOAD_IMAGE_COLOR); + if (!newTemplateImage) { + GST_WARNING ("Couldn't load template image: %s. error: %s", + template, g_strerror (errno)); } } + + GST_OBJECT_LOCK (filter); + oldTemplateFilename = filter->template; + filter->template = template; + oldTemplateImage = filter->cvTemplateImage; + filter->cvTemplateImage = newTemplateImage; + oldDistImage = filter->cvDistImage; + /* This will be recreated in the chain function as required: */ + filter->cvDistImage = NULL; + GST_OBJECT_UNLOCK (filter); + + cvReleaseImage (&oldDistImage); + cvReleaseImage (&oldTemplateImage); + g_free (oldTemplateFilename); }