mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
opencv: Add disparity-map calculation element
https://bugzilla.gnome.org/show_bug.cgi?id=704760
This commit is contained in:
parent
6f4f84fea0
commit
fbb5dd38c7
4 changed files with 914 additions and 0 deletions
|
@ -23,6 +23,7 @@ libgstopencv_la_SOURCES = gstopencv.c \
|
|||
gstretinex.c \
|
||||
gstsegmentation.cpp \
|
||||
gstgrabcut.cpp \
|
||||
gstdisparity.cpp \
|
||||
motioncells_wrapper.cpp \
|
||||
MotionCells.cpp
|
||||
|
||||
|
@ -65,6 +66,7 @@ noinst_HEADERS = gstopencvvideofilter.h gstopencvutils.h \
|
|||
gstretinex.h \
|
||||
gstsegmentation.h \
|
||||
gstgrabcut.h \
|
||||
gstdisparity.h \
|
||||
gstmotioncells.h \
|
||||
motioncells_wrapper.h \
|
||||
MotionCells.h
|
||||
|
|
792
ext/opencv/gstdisparity.cpp
Normal file
792
ext/opencv/gstdisparity.cpp
Normal file
|
@ -0,0 +1,792 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2013 Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
|
||||
* which case the following provisions apply instead of the ones
|
||||
* mentioned above:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/*
|
||||
* SECTION:element-disparity
|
||||
*
|
||||
* This element computes a disparity map from two stereo images, meaning each one coming from a
|
||||
* different camera, both looking at the same scene and relatively close to each other - more on
|
||||
* this below. The disparity map is a proxy of the depth of a scene as seen from the camera.
|
||||
*
|
||||
* Assumptions: Input images are stereo, rectified and aligned. If these conditions are not met,
|
||||
* results can be poor. Both cameras should be looking parallel to maximize the overlapping
|
||||
* stereo area, and should not have objects too close or too far. The algorithms implemented here
|
||||
* run prefiltering stages to normalize brightness between the inputs, and to maximize texture.
|
||||
*
|
||||
* Note that in general is hard to find correspondences between soft textures, for instance a
|
||||
* block of gloss blue colour. The output is a gray image with values close to white meaning
|
||||
* closer to the cameras and darker far away. Black means that the pixels were not matched
|
||||
* correctly (not found). The resulting depth map can be transformed into real world coordinates
|
||||
* by means of OpenCV function (reprojectImageTo3D) but for this the camera matrixes need to
|
||||
* be fully known.
|
||||
*
|
||||
* Algorithm 1 is the OpenCV Stereo Block Matching, similar to the one developed by Kurt Konolige
|
||||
* [A] and that works by using small Sum-of-absolute-differenc (SAD) windows to find matching
|
||||
* points between the left and right rectified images. This algorithm finds only strongly matching
|
||||
* points between both images, this means normally strong textures. In soft textures, such as a
|
||||
* single coloured wall (as opposed to, f.i. a hairy rug), not all pixels might have correspondence.
|
||||
*
|
||||
* Algorithm 2 is the Semi Global Matching (SGM) algorithm [B] which models the scene structure
|
||||
* with a point-wise matching cost and an associated smoothness term. The energy minimization
|
||||
* is then computed in a multitude of 1D lines. For each point, the disparity corresponding to
|
||||
* the minimum aggregated cost is selected. In [B] the author proposes to use 8 or 16 different
|
||||
* independent paths. The SGM approach works well near depth discontinuities, but produces less
|
||||
* accurate results. Despite its relatively large memory footprint, this method is very fast and
|
||||
* potentially robust to complicated textured regions.
|
||||
*
|
||||
* Algorithm 3 is the OpenCV implementation of a modification of the variational stereo
|
||||
* correspondence algorithm, described in [C].
|
||||
*
|
||||
* Algorithm 4 is the Graph Cut stereo vision algorithm (GC) introduced in [D]; it is a global
|
||||
* stereo vision method. It calculates depth discontinuities by minimizing an energy function
|
||||
* combingin a point-wise matching cost and a smoothness term. The energy function is passed
|
||||
* to graph and Graph Cut is used to find a lowest-energy cut. GC is computationally intensive due
|
||||
* to its global nature and uses loads of memory, but it can deal with textureless regions and
|
||||
* reflections better than other methods.
|
||||
* Graphcut based technique is CPU intensive hence smaller framesizes are desired.
|
||||
*
|
||||
* Some test images can be found here: http://vision.stanford.edu/~birch/p2p/
|
||||
*
|
||||
* [A] K. Konolige. Small vision system. hardware and implementation. In Proc. International
|
||||
* Symposium on Robotics Research, pages 111--116, Hayama, Japan, 1997.
|
||||
* [B] H. Hirschmüller, “Accurate and efficient stereo processing by semi-global matching and
|
||||
* mutual information,” in Proceedings of the IEEE Conference on Computer Vision and Pattern
|
||||
* Recognition, 2005, pp. 807–814.
|
||||
* [C] S. Kosov, T. Thormaehlen, H.-P. Seidel "Accurate Real-Time Disparity Estimation with
|
||||
* Variational Methods" Proceedings of the 5th International Symposium on Visual Computing,
|
||||
* Vegas, USA
|
||||
* [D] Scharstein, D. & Szeliski, R. (2001). A taxonomy and evaluation of dense two-frame stereo
|
||||
* correspondence algorithms, International Journal of Computer Vision 47: 7–42.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example launch line</title>
|
||||
* |[
|
||||
* gst-launch-1.0 videotestsrc ! video/x-raw,width=320,height=240 ! disp0.sink_right videotestsrc ! video/x-raw,width=320,height=240 ! disp0.sink_left disparity name=disp0 ! videoconvert ! ximagesink
|
||||
* ]|
|
||||
* Another example, with two png files representing a classical stereo matching,
|
||||
* downloadable from http://vision.middlebury.edu/stereo/submit/tsukuba/im4.png and
|
||||
* im3.png. Note here they are downloaded in ~ (home).
|
||||
* |[
|
||||
gst-launch-1.0 multifilesrc location=~/im3.png ! pngdec ! videoconvert ! disp0.sink_right multifilesrc location=~/im4.png ! pngdec ! videoconvert ! disp0.sink_left disparity name=disp0 method=sbm disp0.src ! videoconvert ! ximagesink
|
||||
* ]|
|
||||
* Yet another example with two cameras, which should be the same model, aligned etc.
|
||||
* |[
|
||||
gst-launch-1.0 v4l2src device=/dev/video1 ! video/x-raw,width=320,height=240 ! videoconvert ! disp0.sink_right v4l2src device=/dev/video0 ! video/x-raw,width=320,height=240 ! videoconvert ! disp0.sink_left disparity name=disp0 method=sgbm disp0.src ! videoconvert ! ximagesink
|
||||
* ]|
|
||||
* </refsect2>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <opencv2/contrib/contrib.hpp>
|
||||
#include "gstdisparity.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_disparity_debug);
|
||||
#define GST_CAT_DEFAULT gst_disparity_debug
|
||||
|
||||
/* Filter signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_METHOD,
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
METHOD_SBM,
|
||||
METHOD_SGBM,
|
||||
METHOD_VAR,
|
||||
METHOD_GC
|
||||
} GstDisparityMethod;
|
||||
|
||||
#define DEFAULT_METHOD METHOD_SGBM
|
||||
|
||||
#define GST_TYPE_DISPARITY_METHOD (gst_disparity_method_get_type ())
|
||||
static GType
|
||||
gst_disparity_method_get_type (void)
|
||||
{
|
||||
static GType etype = 0;
|
||||
if (etype == 0) {
|
||||
static const GEnumValue values[] = {
|
||||
{METHOD_SBM, "Global block matching algorithm", "sbm"},
|
||||
{METHOD_SGBM, "Semi-global block matching algorithm", "sgbm"},
|
||||
{METHOD_VAR, "Variational matching algorithm", "svar"},
|
||||
{METHOD_GC, "Graph-cut based matching algorithm", "sgc"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
etype = g_enum_register_static ("GstDisparityMethod", values);
|
||||
}
|
||||
return etype;
|
||||
}
|
||||
|
||||
/* the capabilities of the inputs and outputs.
|
||||
*/
|
||||
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB"))
|
||||
);
|
||||
|
||||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB"))
|
||||
);
|
||||
|
||||
G_DEFINE_TYPE (GstDisparity, gst_disparity, GST_TYPE_ELEMENT);
|
||||
|
||||
static void gst_disparity_finalize (GObject * object);
|
||||
static void gst_disparity_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_disparity_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static GstStateChangeReturn gst_disparity_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static gboolean gst_disparity_handle_sink_event (GstPad * pad,
|
||||
GstObject * parent, GstEvent * event);
|
||||
static gboolean gst_disparity_handle_query (GstPad * pad,
|
||||
GstObject * parent, GstQuery * query);
|
||||
static GstFlowReturn gst_disparity_chain_right (GstPad * pad,
|
||||
GstObject * parent, GstBuffer * buffer);
|
||||
static GstFlowReturn gst_disparity_chain_left (GstPad * pad, GstObject * parent,
|
||||
GstBuffer * buffer);
|
||||
static void gst_disparity_release_all_pointers (GstDisparity * filter);
|
||||
|
||||
static void initialise_disparity (GstDisparity * fs, int width, int height,
|
||||
int nchannels);
|
||||
static int initialise_sbm (GstDisparity * filter);
|
||||
static int run_sbm_iteration (GstDisparity * filter);
|
||||
static int run_sgbm_iteration (GstDisparity * filter);
|
||||
static int run_svar_iteration (GstDisparity * filter);
|
||||
static int run_sgc_iteration (GstDisparity * filter);
|
||||
static int finalise_sbm (GstDisparity * filter);
|
||||
|
||||
/* initialize the disparity's class */
|
||||
static void
|
||||
gst_disparity_class_init (GstDisparityClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->finalize = gst_disparity_finalize;
|
||||
gobject_class->set_property = gst_disparity_set_property;
|
||||
gobject_class->get_property = gst_disparity_get_property;
|
||||
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_METHOD,
|
||||
g_param_spec_enum ("method",
|
||||
"Stereo matching method to use",
|
||||
"Stereo matching method to use",
|
||||
GST_TYPE_DISPARITY_METHOD, DEFAULT_METHOD,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
element_class->change_state = gst_disparity_change_state;
|
||||
|
||||
gst_element_class_set_static_metadata (element_class,
|
||||
"Stereo image disparity (depth) map calculation",
|
||||
"Filter/Effect/Video",
|
||||
"Calculates the stereo disparity map from two (sequences of) rectified and aligned stereo images",
|
||||
"Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>");
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_factory));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sink_factory));
|
||||
}
|
||||
|
||||
/* initialize the new element
|
||||
* instantiate pads and add them to element
|
||||
* set pad callback functions
|
||||
* initialize instance structure
|
||||
*/
|
||||
static void
|
||||
gst_disparity_init (GstDisparity * filter)
|
||||
{
|
||||
filter->sinkpad_left =
|
||||
gst_pad_new_from_static_template (&sink_factory, "sink_left");
|
||||
gst_pad_set_event_function (filter->sinkpad_left,
|
||||
GST_DEBUG_FUNCPTR (gst_disparity_handle_sink_event));
|
||||
gst_pad_set_query_function (filter->sinkpad_left,
|
||||
GST_DEBUG_FUNCPTR (gst_disparity_handle_query));
|
||||
gst_pad_set_chain_function (filter->sinkpad_left,
|
||||
GST_DEBUG_FUNCPTR (gst_disparity_chain_left));
|
||||
GST_PAD_SET_PROXY_CAPS (filter->sinkpad_left);
|
||||
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad_left);
|
||||
|
||||
filter->sinkpad_right =
|
||||
gst_pad_new_from_static_template (&sink_factory, "sink_right");
|
||||
gst_pad_set_event_function (filter->sinkpad_right,
|
||||
GST_DEBUG_FUNCPTR (gst_disparity_handle_sink_event));
|
||||
gst_pad_set_query_function (filter->sinkpad_right,
|
||||
GST_DEBUG_FUNCPTR (gst_disparity_handle_query));
|
||||
gst_pad_set_chain_function (filter->sinkpad_right,
|
||||
GST_DEBUG_FUNCPTR (gst_disparity_chain_right));
|
||||
GST_PAD_SET_PROXY_CAPS (filter->sinkpad_right);
|
||||
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad_right);
|
||||
|
||||
filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
|
||||
gst_pad_use_fixed_caps (filter->srcpad);
|
||||
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
|
||||
|
||||
filter->lock = g_mutex_new ();
|
||||
filter->cond = g_cond_new ();
|
||||
|
||||
filter->method = DEFAULT_METHOD;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_disparity_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstDisparity *filter = GST_DISPARITY (object);
|
||||
switch (prop_id) {
|
||||
case PROP_METHOD:
|
||||
filter->method = g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_disparity_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstDisparity *filter = GST_DISPARITY (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_METHOD:
|
||||
g_value_set_enum (value, filter->method);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* GstElement vmethod implementations */
|
||||
static GstStateChangeReturn
|
||||
gst_disparity_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
GstDisparity *fs = GST_DISPARITY (element);
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
g_mutex_lock (fs->lock);
|
||||
fs->flushing = true;
|
||||
g_cond_signal (fs->cond);
|
||||
g_mutex_unlock (fs->lock);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
g_mutex_lock (fs->lock);
|
||||
fs->flushing = false;
|
||||
g_mutex_unlock (fs->lock);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret =
|
||||
GST_ELEMENT_CLASS (gst_disparity_parent_class)->change_state (element,
|
||||
transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
g_mutex_lock (fs->lock);
|
||||
fs->flushing = true;
|
||||
g_cond_signal (fs->cond);
|
||||
g_mutex_unlock (fs->lock);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
g_mutex_lock (fs->lock);
|
||||
fs->flushing = false;
|
||||
g_mutex_unlock (fs->lock);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_disparity_handle_sink_event (GstPad * pad,
|
||||
GstObject * parent, GstEvent * event)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
GstDisparity *fs = GST_DISPARITY (parent);
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_CAPS:
|
||||
{
|
||||
GstCaps *caps;
|
||||
GstVideoInfo info;
|
||||
gst_event_parse_caps (event, &caps);
|
||||
|
||||
/* Critical section since both pads handle event sinking simultaneously */
|
||||
g_mutex_lock (fs->lock);
|
||||
gst_video_info_from_caps (&info, caps);
|
||||
|
||||
GST_INFO_OBJECT (pad, " Negotiating caps via event %" GST_PTR_FORMAT,
|
||||
caps);
|
||||
if (!gst_pad_has_current_caps (fs->srcpad)) {
|
||||
/* Init image info (widht, height, etc) and all OpenCV matrices */
|
||||
initialise_disparity (fs, info.width, info.height,
|
||||
info.finfo->n_components);
|
||||
|
||||
/* Initialise and keep the caps. Force them on src pad */
|
||||
fs->caps = gst_video_info_to_caps (&info);
|
||||
gst_pad_set_caps (fs->srcpad, fs->caps);
|
||||
|
||||
} else if (!gst_caps_is_equal (fs->caps, caps)) {
|
||||
ret = FALSE;
|
||||
}
|
||||
g_mutex_unlock (fs->lock);
|
||||
|
||||
GST_INFO_OBJECT (pad,
|
||||
" Negotiated caps (result %d) via event: %" GST_PTR_FORMAT, ret,
|
||||
caps);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = gst_pad_event_default (pad, parent, event);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_disparity_handle_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||
{
|
||||
GstDisparity *fs = GST_DISPARITY (parent);
|
||||
gboolean ret = TRUE;
|
||||
GstCaps *template_caps;
|
||||
GstCaps *current_caps;
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_CAPS:
|
||||
g_mutex_lock (fs->lock);
|
||||
if (!gst_pad_has_current_caps (fs->srcpad)) {
|
||||
template_caps = gst_pad_get_pad_template_caps (pad);
|
||||
gst_query_set_caps_result (query, template_caps);
|
||||
gst_caps_unref (template_caps);
|
||||
} else {
|
||||
current_caps = gst_pad_get_current_caps (fs->srcpad);
|
||||
gst_query_set_caps_result (query, current_caps);
|
||||
gst_caps_unref (current_caps);
|
||||
}
|
||||
g_mutex_unlock (fs->lock);
|
||||
ret = TRUE;
|
||||
break;
|
||||
case GST_QUERY_ALLOCATION:
|
||||
if (pad == fs->sinkpad_right)
|
||||
ret = gst_pad_peer_query (fs->srcpad, query);
|
||||
else
|
||||
ret = FALSE;
|
||||
break;
|
||||
default:
|
||||
ret = gst_pad_query_default (pad, parent, query);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_disparity_release_all_pointers (GstDisparity * filter)
|
||||
{
|
||||
cvReleaseImage (&filter->cvRGB_right);
|
||||
cvReleaseImage (&filter->cvRGB_left);
|
||||
cvReleaseImage (&filter->cvGray_depth_map1);
|
||||
cvReleaseImage (&filter->cvGray_right);
|
||||
cvReleaseImage (&filter->cvGray_left);
|
||||
cvReleaseImage (&filter->cvGray_depth_map2);
|
||||
cvReleaseImage (&filter->cvGray_depth_map1_2);
|
||||
|
||||
finalise_sbm (filter);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_disparity_finalize (GObject * object)
|
||||
{
|
||||
GstDisparity *filter;
|
||||
filter = GST_DISPARITY (object);
|
||||
gst_disparity_release_all_pointers (filter);
|
||||
|
||||
gst_caps_unref (filter->caps);
|
||||
filter->caps = NULL;
|
||||
|
||||
g_cond_free (filter->cond);
|
||||
g_mutex_free (filter->lock);
|
||||
G_OBJECT_CLASS (gst_disparity_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GstFlowReturn
|
||||
gst_disparity_chain_left (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||
{
|
||||
GstDisparity *fs;
|
||||
GstMapInfo info;
|
||||
|
||||
fs = GST_DISPARITY (parent);
|
||||
GST_DEBUG_OBJECT (pad, "processing frame from left");
|
||||
g_mutex_lock (fs->lock);
|
||||
if (fs->flushing) {
|
||||
g_mutex_unlock (fs->lock);
|
||||
return GST_FLOW_FLUSHING;
|
||||
}
|
||||
if (fs->buffer_left) {
|
||||
GST_DEBUG_OBJECT (pad, " right is busy, wait and hold");
|
||||
g_cond_wait (fs->cond, fs->lock);
|
||||
GST_DEBUG_OBJECT (pad, " right is free, continuing");
|
||||
if (fs->flushing) {
|
||||
g_mutex_unlock (fs->lock);
|
||||
return GST_FLOW_FLUSHING;
|
||||
}
|
||||
}
|
||||
fs->buffer_left = buffer;
|
||||
|
||||
if (!gst_buffer_map (buffer, &info, (GstMapFlags) GST_MAP_READWRITE)) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
if (fs->cvRGB_left)
|
||||
fs->cvRGB_left->imageData = (char *) info.data;
|
||||
|
||||
GST_DEBUG_OBJECT (pad, "signalled right");
|
||||
g_cond_signal (fs->cond);
|
||||
g_mutex_unlock (fs->lock);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_disparity_chain_right (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||
{
|
||||
GstDisparity *fs;
|
||||
GstMapInfo info;
|
||||
GstFlowReturn ret;
|
||||
|
||||
fs = GST_DISPARITY (parent);
|
||||
GST_DEBUG_OBJECT (pad, "processing frame from right");
|
||||
g_mutex_lock (fs->lock);
|
||||
if (fs->flushing) {
|
||||
g_mutex_unlock (fs->lock);
|
||||
return GST_FLOW_FLUSHING;
|
||||
}
|
||||
if (fs->buffer_left == NULL) {
|
||||
GST_DEBUG_OBJECT (pad, " left has not provided another frame yet, waiting");
|
||||
g_cond_wait (fs->cond, fs->lock);
|
||||
GST_DEBUG_OBJECT (pad, " left has just provided a frame, continuing");
|
||||
if (fs->flushing) {
|
||||
g_mutex_unlock (fs->lock);
|
||||
return GST_FLOW_FLUSHING;
|
||||
}
|
||||
}
|
||||
if (!gst_buffer_map (buffer, &info, (GstMapFlags) GST_MAP_READWRITE)) {
|
||||
g_mutex_unlock (fs->lock);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
if (fs->cvRGB_right)
|
||||
fs->cvRGB_right->imageData = (char *) info.data;
|
||||
|
||||
|
||||
/* Here do the business */
|
||||
GST_INFO_OBJECT (pad,
|
||||
"comparing frames, %dB (%dx%d) %d channels", (int) info.size,
|
||||
fs->width, fs->height, fs->actualChannels);
|
||||
|
||||
/* Stereo corresponding using semi-global block matching. According to OpenCV:
|
||||
"" The class implements modified H. Hirschmuller algorithm HH08 . The main
|
||||
differences between the implemented algorithm and the original one are:
|
||||
|
||||
- by default the algorithm is single-pass, i.e. instead of 8 directions we
|
||||
only consider 5. Set fullDP=true to run the full variant of the algorithm
|
||||
(which could consume a lot of memory)
|
||||
- the algorithm matches blocks, not individual pixels (though, by setting
|
||||
SADWindowSize=1 the blocks are reduced to single pixels)
|
||||
- mutual information cost function is not implemented. Instead, we use a
|
||||
simpler Birchfield-Tomasi sub-pixel metric from BT96 , though the color
|
||||
images are supported as well.
|
||||
- we include some pre- and post- processing steps from K. Konolige
|
||||
algorithm FindStereoCorrespondenceBM , such as pre-filtering
|
||||
( CV_STEREO_BM_XSOBEL type) and post-filtering (uniqueness check, quadratic
|
||||
interpolation and speckle filtering) ""
|
||||
*/
|
||||
if (METHOD_SGBM == fs->method) {
|
||||
cvCvtColor (fs->cvRGB_left, fs->cvGray_left, CV_RGB2GRAY);
|
||||
cvCvtColor (fs->cvRGB_right, fs->cvGray_right, CV_RGB2GRAY);
|
||||
run_sgbm_iteration (fs);
|
||||
cvNormalize (fs->cvGray_depth_map1, fs->cvGray_depth_map2, 0, 255,
|
||||
CV_MINMAX, NULL);
|
||||
cvCvtColor (fs->cvGray_depth_map2, fs->cvRGB_right, CV_GRAY2RGB);
|
||||
}
|
||||
/* Algorithm 1 is the OpenCV Stereo Block Matching, similar to the one
|
||||
developed by Kurt Konolige [A] and that works by using small Sum-of-absolute-
|
||||
differences (SAD) window. See the comments on top of the file.
|
||||
*/
|
||||
else if (METHOD_SBM == fs->method) {
|
||||
cvCvtColor (fs->cvRGB_left, fs->cvGray_left, CV_RGB2GRAY);
|
||||
cvCvtColor (fs->cvRGB_right, fs->cvGray_right, CV_RGB2GRAY);
|
||||
run_sbm_iteration (fs);
|
||||
cvNormalize (fs->cvGray_depth_map1, fs->cvGray_depth_map2, 0, 255,
|
||||
CV_MINMAX, NULL);
|
||||
cvCvtColor (fs->cvGray_depth_map2, fs->cvRGB_right, CV_GRAY2RGB);
|
||||
}
|
||||
/* The class implements the modified S. G. Kosov algorithm
|
||||
See the comments on top of the file.
|
||||
*/
|
||||
else if (METHOD_VAR == fs->method) {
|
||||
cvCvtColor (fs->cvRGB_left, fs->cvGray_left, CV_RGB2GRAY);
|
||||
cvCvtColor (fs->cvRGB_right, fs->cvGray_right, CV_RGB2GRAY);
|
||||
run_svar_iteration (fs);
|
||||
cvCvtColor (fs->cvGray_depth_map2, fs->cvRGB_right, CV_GRAY2RGB);
|
||||
}
|
||||
/* The Graph Cut stereo vision algorithm (GC) introduced in [D] is a global
|
||||
stereo vision method. It calculates depth discontinuities by minimizing an
|
||||
energy function combingin a point-wise matching cost and a smoothness term.
|
||||
See the comments on top of the file.
|
||||
*/
|
||||
else if (METHOD_GC == fs->method) {
|
||||
cvCvtColor (fs->cvRGB_left, fs->cvGray_left, CV_RGB2GRAY);
|
||||
cvCvtColor (fs->cvRGB_right, fs->cvGray_right, CV_RGB2GRAY);
|
||||
run_sgc_iteration (fs);
|
||||
cvConvertScale (fs->cvGray_depth_map1, fs->cvGray_depth_map2, -16.0, 0.0);
|
||||
cvCvtColor (fs->cvGray_depth_map2, fs->cvRGB_right, CV_GRAY2RGB);
|
||||
}
|
||||
|
||||
|
||||
GST_DEBUG_OBJECT (pad, " right has finished");
|
||||
gst_buffer_unmap (fs->buffer_left, &info);
|
||||
gst_buffer_unref (fs->buffer_left);
|
||||
fs->buffer_left = NULL;
|
||||
g_cond_signal (fs->cond);
|
||||
g_mutex_unlock (fs->lock);
|
||||
|
||||
ret = gst_pad_push (fs->srcpad, buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* entry point to initialize the plug-in
|
||||
* initialize the plug-in itself
|
||||
* register the element factories and other features
|
||||
*/
|
||||
gboolean
|
||||
gst_disparity_plugin_init (GstPlugin * disparity)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (gst_disparity_debug, "disparity", 0,
|
||||
"Stereo image disparity (depth) map calculation");
|
||||
return gst_element_register (disparity, "disparity", GST_RANK_NONE,
|
||||
GST_TYPE_DISPARITY);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
initialise_disparity (GstDisparity * fs, int width, int height, int nchannels)
|
||||
{
|
||||
fs->width = width;
|
||||
fs->height = height;
|
||||
fs->actualChannels = nchannels;
|
||||
|
||||
fs->imgSize = cvSize (fs->width, fs->height);
|
||||
if (fs->cvRGB_right)
|
||||
gst_disparity_release_all_pointers (fs);
|
||||
|
||||
fs->cvRGB_right = cvCreateImageHeader (fs->imgSize, IPL_DEPTH_8U,
|
||||
fs->actualChannels);
|
||||
fs->cvRGB_left = cvCreateImageHeader (fs->imgSize, IPL_DEPTH_8U,
|
||||
fs->actualChannels);
|
||||
fs->cvGray_right = cvCreateImage (fs->imgSize, IPL_DEPTH_8U, 1);
|
||||
fs->cvGray_left = cvCreateImage (fs->imgSize, IPL_DEPTH_8U, 1);
|
||||
|
||||
fs->cvGray_depth_map1 = cvCreateImage (fs->imgSize, IPL_DEPTH_16S, 1);
|
||||
fs->cvGray_depth_map2 = cvCreateImage (fs->imgSize, IPL_DEPTH_8U, 1);
|
||||
fs->cvGray_depth_map1_2 = cvCreateImage (fs->imgSize, IPL_DEPTH_16S, 1);
|
||||
|
||||
/* Stereo Block Matching methods */
|
||||
if ((NULL != fs->cvRGB_right) && (NULL != fs->cvRGB_left)
|
||||
&& (NULL != fs->cvGray_depth_map2))
|
||||
initialise_sbm (fs);
|
||||
}
|
||||
|
||||
int
|
||||
initialise_sbm (GstDisparity * filter)
|
||||
{
|
||||
filter->img_right_as_cvMat_rgb =
|
||||
(void *) new cv::Mat (filter->cvRGB_right, false);
|
||||
filter->img_left_as_cvMat_rgb =
|
||||
(void *) new cv::Mat (filter->cvRGB_left, false);
|
||||
filter->img_right_as_cvMat_gray =
|
||||
(void *) new cv::Mat (filter->cvGray_right, false);
|
||||
filter->img_left_as_cvMat_gray =
|
||||
(void *) new cv::Mat (filter->cvGray_left, false);
|
||||
filter->depth_map_as_cvMat =
|
||||
(void *) new cv::Mat (filter->cvGray_depth_map1, false);
|
||||
filter->depth_map_as_cvMat2 =
|
||||
(void *) new cv::Mat (filter->cvGray_depth_map2, false);
|
||||
|
||||
filter->sbm = (void *) new cv::StereoBM ();
|
||||
filter->sgbm = (void *) new cv::StereoSGBM ();
|
||||
filter->svar = (void *) new cv::StereoVar ();
|
||||
/* SGC has only two parameters on creation: NumerOfDisparities and MaxIters */
|
||||
filter->sgc = cvCreateStereoGCState (16, 2);
|
||||
|
||||
((cv::StereoBM *) filter->sbm)->state->SADWindowSize = 9;
|
||||
((cv::StereoBM *) filter->sbm)->state->numberOfDisparities = 32;
|
||||
((cv::StereoBM *) filter->sbm)->state->preFilterSize = 9;
|
||||
((cv::StereoBM *) filter->sbm)->state->preFilterCap = 32;
|
||||
((cv::StereoBM *) filter->sbm)->state->minDisparity = 0;
|
||||
((cv::StereoBM *) filter->sbm)->state->textureThreshold = 0;
|
||||
((cv::StereoBM *) filter->sbm)->state->uniquenessRatio = 0;
|
||||
((cv::StereoBM *) filter->sbm)->state->speckleWindowSize = 0;
|
||||
((cv::StereoBM *) filter->sbm)->state->speckleRange = 0;
|
||||
((cv::StereoBM *) filter->sbm)->state->disp12MaxDiff = 0;
|
||||
|
||||
((cv::StereoSGBM *) filter->sgbm)->minDisparity = 1;
|
||||
((cv::StereoSGBM *) filter->sgbm)->numberOfDisparities = 64;
|
||||
((cv::StereoSGBM *) filter->sgbm)->SADWindowSize = 3;
|
||||
((cv::StereoSGBM *) filter->sgbm)->P1 = 200;;
|
||||
((cv::StereoSGBM *) filter->sgbm)->P2 = 255;
|
||||
((cv::StereoSGBM *) filter->sgbm)->disp12MaxDiff = 0;
|
||||
((cv::StereoSGBM *) filter->sgbm)->preFilterCap = 0;
|
||||
((cv::StereoSGBM *) filter->sgbm)->uniquenessRatio = 0;
|
||||
((cv::StereoSGBM *) filter->sgbm)->speckleWindowSize = 0;
|
||||
((cv::StereoSGBM *) filter->sgbm)->speckleRange = 0;
|
||||
((cv::StereoSGBM *) filter->sgbm)->fullDP = true;
|
||||
|
||||
/* From Opencv samples/cpp/stereo_match.cpp */
|
||||
((cv::StereoVar *) filter->svar)->levels = 3;
|
||||
((cv::StereoVar *) filter->svar)->pyrScale = 0.5;
|
||||
((cv::StereoVar *) filter->svar)->nIt = 25;
|
||||
((cv::StereoVar *) filter->svar)->minDisp = -64;
|
||||
((cv::StereoVar *) filter->svar)->maxDisp = 0;
|
||||
((cv::StereoVar *) filter->svar)->poly_n = 3;
|
||||
((cv::StereoVar *) filter->svar)->poly_sigma = 0.0;
|
||||
((cv::StereoVar *) filter->svar)->fi = 15.0f;
|
||||
((cv::StereoVar *) filter->svar)->lambda = 0.03f;
|
||||
((cv::StereoVar *) filter->svar)->penalization =
|
||||
cv::StereoVar::PENALIZATION_TICHONOV;
|
||||
((cv::StereoVar *) filter->svar)->cycle = cv::StereoVar::CYCLE_V;
|
||||
((cv::StereoVar *) filter->svar)->flags = cv::StereoVar::USE_SMART_ID |
|
||||
cv::StereoVar::USE_AUTO_PARAMS |
|
||||
cv::StereoVar::USE_INITIAL_DISPARITY |
|
||||
cv::StereoVar::USE_MEDIAN_FILTERING;
|
||||
|
||||
filter->sgc->Ithreshold = 5;
|
||||
filter->sgc->interactionRadius = 1;
|
||||
filter->sgc->occlusionCost = 10000;
|
||||
filter->sgc->minDisparity = 0;
|
||||
filter->sgc->numberOfDisparities = 16; /* Coming from constructor too */
|
||||
filter->sgc->maxIters = 1; /* Coming from constructor too */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
run_sbm_iteration (GstDisparity * filter)
|
||||
{
|
||||
(*((cv::StereoBM *) filter->
|
||||
sbm)) (*((cv::Mat *) filter->img_left_as_cvMat_gray),
|
||||
*((cv::Mat *) filter->img_right_as_cvMat_gray),
|
||||
*((cv::Mat *) filter->depth_map_as_cvMat));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
run_sgbm_iteration (GstDisparity * filter)
|
||||
{
|
||||
(*((cv::StereoSGBM *) filter->
|
||||
sgbm)) (*((cv::Mat *) filter->img_left_as_cvMat_gray),
|
||||
*((cv::Mat *) filter->img_right_as_cvMat_gray),
|
||||
*((cv::Mat *) filter->depth_map_as_cvMat));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
run_svar_iteration (GstDisparity * filter)
|
||||
{
|
||||
(*((cv::StereoVar *) filter->
|
||||
svar)) (*((cv::Mat *) filter->img_left_as_cvMat_gray),
|
||||
*((cv::Mat *) filter->img_right_as_cvMat_gray),
|
||||
*((cv::Mat *) filter->depth_map_as_cvMat2));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
run_sgc_iteration (GstDisparity * filter)
|
||||
{
|
||||
cvFindStereoCorrespondenceGC (filter->cvGray_left,
|
||||
filter->cvGray_right, filter->cvGray_depth_map1,
|
||||
filter->cvGray_depth_map1_2, filter->sgc, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
finalise_sbm (GstDisparity * filter)
|
||||
{
|
||||
delete (cv::Mat *) filter->img_left_as_cvMat_rgb;
|
||||
delete (cv::Mat *) filter->img_right_as_cvMat_rgb;
|
||||
delete (cv::Mat *) filter->depth_map_as_cvMat;
|
||||
delete (cv::Mat *) filter->depth_map_as_cvMat2;
|
||||
delete (cv::Mat *) filter->img_left_as_cvMat_gray;
|
||||
delete (cv::Mat *) filter->img_right_as_cvMat_gray;
|
||||
delete (cv::StereoBM *) filter->sbm;
|
||||
delete (cv::StereoSGBM *) filter->sgbm;
|
||||
delete (cv::StereoVar *) filter->svar;
|
||||
return (0);
|
||||
}
|
116
ext/opencv/gstdisparity.h
Normal file
116
ext/opencv/gstdisparity.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2013 Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
|
||||
* which case the following provisions apply instead of the ones
|
||||
* mentioned above:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_DISPARITY_H__
|
||||
#define __GST_DISPARITY_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <cv.h>
|
||||
#include <opencv2/legacy/legacy.hpp>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
/* #defines don't like whitespacey bits */
|
||||
#define GST_TYPE_DISPARITY \
|
||||
(gst_disparity_get_type())
|
||||
#define GST_DISPARITY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DISPARITY,GstDisparity))
|
||||
#define GST_DISPARITY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DISPARITY,GstDisparityClass))
|
||||
#define GST_IS_DISPARITY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DISPARITY))
|
||||
#define GST_IS_DISPARITY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DISPARITY))
|
||||
typedef struct _GstDisparity GstDisparity;
|
||||
typedef struct _GstDisparityClass GstDisparityClass;
|
||||
|
||||
struct _GstDisparity
|
||||
{
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad_left, *sinkpad_right, *srcpad;
|
||||
GstCaps *caps;
|
||||
|
||||
gint method;
|
||||
gboolean display;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int actualChannels;
|
||||
|
||||
GstBuffer *buffer_left;
|
||||
GMutex *lock;
|
||||
GCond *cond;
|
||||
gboolean flushing;
|
||||
|
||||
CvSize imgSize;
|
||||
IplImage *cvRGB_right;
|
||||
IplImage *cvRGB_left;
|
||||
IplImage *cvGray_right;
|
||||
IplImage *cvGray_left;
|
||||
IplImage *cvGray_depth_map1; /*IPL_DEPTH_16S */
|
||||
IplImage *cvGray_depth_map2; /*IPL_DEPTH_8U */
|
||||
IplImage *cvGray_depth_map1_2; /*IPL_DEPTH_16S */
|
||||
|
||||
void *sbm; /* cv::StereoBM */
|
||||
void *sgbm; /* cv::StereoSGBM */
|
||||
void *svar; /* cv::StereoVar */
|
||||
CvStereoGCState *sgc; /* This is a C implementation */
|
||||
void *img_right_as_cvMat_rgb; /* cv::Mat */
|
||||
void *img_left_as_cvMat_rgb; /* cv::Mat */
|
||||
void *depth_map_as_cvMat; /* cv::Mat */
|
||||
void *depth_map_as_cvMat2; /* cv::Mat */
|
||||
void *img_right_as_cvMat_gray; /* cv::Mat */
|
||||
void *img_left_as_cvMat_gray; /* cv::Mat */
|
||||
};
|
||||
|
||||
struct _GstDisparityClass
|
||||
{
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_disparity_get_type (void);
|
||||
|
||||
gboolean gst_disparity_plugin_init (GstPlugin * disparity);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GST_DISPARITY_H__ */
|
|
@ -41,6 +41,7 @@
|
|||
#include "gstretinex.h"
|
||||
#include "gstsegmentation.h"
|
||||
#include "gstgrabcut.h"
|
||||
#include "gstdisparity.h"
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
|
@ -99,6 +100,9 @@ plugin_init (GstPlugin * plugin)
|
|||
if (!gst_grabcut_plugin_init (plugin))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_disparity_plugin_init (plugin))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue