mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
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.
This commit is contained in:
parent
c77808055d
commit
b608767288
1 changed files with 38 additions and 16 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue