• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * GStreamer
3   * Copyright (C) 2013 Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>
4   *
5   * Permission is hereby granted, free of charge, to any person obtaining a
6   * copy of this software and associated documentation files (the "Software"),
7   * to deal in the Software without restriction, including without limitation
8   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9   * and/or sell copies of the Software, and to permit persons to whom the
10   * Software is furnished to do so, subject to the following conditions:
11   *
12   * The above copyright notice and this permission notice shall be included in
13   * all copies or substantial portions of the Software.
14   *
15   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21   * DEALINGS IN THE SOFTWARE.
22   *
23   * Alternatively, the contents of this file may be used under the
24   * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
25   * which case the following provisions apply instead of the ones
26   * mentioned above:
27   *
28   * This library is free software; you can redistribute it and/or
29   * modify it under the terms of the GNU Library General Public
30   * License as published by the Free Software Foundation; either
31   * version 2 of the License, or (at your option) any later version.
32   *
33   * This library is distributed in the hope that it will be useful,
34   * but WITHOUT ANY WARRANTY; without even the implied warranty of
35   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36   * Library General Public License for more details.
37   *
38   * You should have received a copy of the GNU Library General Public
39   * License along with this library; if not, write to the
40   * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
41   * Boston, MA 02110-1301, USA.
42   */
43 /*
44  * SECTION:element-disparity
45  *
46  * This element computes a disparity map from two stereo images, meaning each one coming from a
47  * different camera, both looking at the same scene and relatively close to each other - more on
48  * this below. The disparity map is a proxy of the depth of a scene as seen from the camera.
49  *
50  * Assumptions: Input images are stereo, rectified and aligned. If these conditions are not met,
51  * results can be poor. Both cameras should be looking parallel to maximize the overlapping
52  * stereo area, and should not have objects too close or too far. The algorithms implemented here
53  * run prefiltering stages to normalize brightness between the inputs, and to maximize texture.
54  *
55  * Note that in general is hard to find correspondences between soft textures, for instance a
56  * block of gloss blue colour. The output is a gray image with values close to white meaning
57  * closer to the cameras and darker far away. Black means that the pixels were not matched
58  * correctly (not found). The resulting depth map can be transformed into real world coordinates
59  * by means of OpenCV function (reprojectImageTo3D) but for this the camera matrixes need to
60  * be fully known.
61  *
62  * Algorithm 1 is the OpenCV Stereo Block Matching, similar to the one developed by Kurt Konolige
63  * [A] and that works by using small Sum-of-absolute-differenc (SAD) windows to find matching
64  * points between the left and right rectified images. This algorithm finds only strongly matching
65  * points between both images, this means normally strong textures. In soft textures, such as a
66  * single coloured wall (as opposed to, f.i. a hairy rug), not all pixels might have correspondence.
67  *
68  * Algorithm 2 is the Semi Global Matching (SGM) algorithm [B] which models the scene structure
69  * with a point-wise matching cost and an associated smoothness term. The energy minimization
70  * is then computed in a multitude of 1D lines. For each point, the disparity corresponding to
71  * the minimum aggregated cost is selected. In [B] the author proposes to use 8 or 16 different
72  * independent paths. The SGM approach works well near depth discontinuities, but produces less
73  * accurate results. Despite its relatively large memory footprint, this method is very fast and
74  * potentially robust to complicated textured regions.
75  *
76  * Algorithm 3 is the OpenCV implementation of a modification of the variational stereo
77  * correspondence algorithm, described in [C].
78  *
79  * Algorithm 4 is the Graph Cut stereo vision algorithm (GC) introduced in [D]; it is a global
80  * stereo vision method. It calculates depth discontinuities by minimizing an energy function
81  * combingin a point-wise matching cost and a smoothness term. The energy function is passed
82  * to graph and Graph Cut is used to find a lowest-energy cut. GC is computationally intensive due
83  * to its global nature and uses loads of memory, but it can deal with textureless regions and
84  * reflections better than other methods.
85  * Graphcut based technique is CPU intensive hence smaller framesizes are desired.
86  *
87  * Some test images can be found here: http://vision.stanford.edu/~birch/p2p/
88  *
89  * [A] K. Konolige. Small vision system. hardware and implementation. In Proc. International
90  * Symposium on Robotics Research, pages 111--116, Hayama, Japan, 1997.
91  * [B] H. Hirschmüller, “Accurate and efficient stereo processing by semi-global matching and
92  * mutual information,” in Proceedings of the IEEE Conference on Computer Vision and Pattern
93  * Recognition, 2005, pp. 807–814.
94  * [C] S. Kosov, T. Thormaehlen, H.-P. Seidel "Accurate Real-Time Disparity Estimation with
95  * Variational Methods" Proceedings of the 5th International Symposium on Visual Computing,
96  * Vegas, USA
97  * [D] Scharstein, D. & Szeliski, R. (2001). A taxonomy and evaluation of dense two-frame stereo
98  * correspondence algorithms, International Journal of Computer Vision 47: 7–42.
99  *
100  * ## Example launch line
101  *
102  * |[
103  * gst-launch-1.0 videotestsrc ! video/x-raw,width=320,height=240 ! videoconvert ! disp0.sink_right videotestsrc ! video/x-raw,width=320,height=240 ! videoconvert ! disp0.sink_left disparity name=disp0 ! videoconvert ! ximagesink
104  * ]|
105  * Another example, with two png files representing a classical stereo matching,
106  * downloadable from http://vision.middlebury.edu/stereo/submit/tsukuba/im4.png and
107  * im3.png. Note here they are downloaded in ~ (home).
108  * |[
109 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
110  * ]|
111  * Yet another example with two cameras, which should be the same model, aligned etc.
112  * |[
113  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
114  * ]|
115  */
116 
117 #ifdef HAVE_CONFIG_H
118 #include <config.h>
119 #endif
120 
121 #include "gstdisparity.h"
122 #include <opencv2/imgproc.hpp>
123 
124 GST_DEBUG_CATEGORY_STATIC (gst_disparity_debug);
125 #define GST_CAT_DEFAULT gst_disparity_debug
126 
127 using namespace cv;
128 /* Filter signals and args */
129 enum
130 {
131   /* FILL ME */
132   LAST_SIGNAL
133 };
134 
135 enum
136 {
137   PROP_0,
138   PROP_METHOD,
139 };
140 
141 typedef enum
142 {
143   METHOD_SBM,
144   METHOD_SGBM
145 } GstDisparityMethod;
146 
147 #define DEFAULT_METHOD METHOD_SGBM
148 
149 #define GST_TYPE_DISPARITY_METHOD (gst_disparity_method_get_type ())
150 static GType
gst_disparity_method_get_type(void)151 gst_disparity_method_get_type (void)
152 {
153   static GType etype = 0;
154   if (etype == 0) {
155     static const GEnumValue values[] = {
156       {METHOD_SBM, "Global block matching algorithm", "sbm"},
157       {METHOD_SGBM, "Semi-global block matching algorithm", "sgbm"},
158       {0, NULL, NULL},
159     };
160     etype = g_enum_register_static ("GstDisparityMethod", values);
161   }
162   return etype;
163 }
164 
165 /* the capabilities of the inputs and outputs.
166  */
167 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
168     GST_PAD_SINK,
169     GST_PAD_ALWAYS,
170     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB"))
171     );
172 
173 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
174     GST_PAD_SRC,
175     GST_PAD_ALWAYS,
176     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB"))
177     );
178 
179 G_DEFINE_TYPE_WITH_CODE (GstDisparity, gst_disparity, GST_TYPE_ELEMENT,
180     GST_DEBUG_CATEGORY_INIT (gst_disparity_debug, "disparity", 0,
181         "Stereo image disparity (depth) map calculation");
182     );
183 GST_ELEMENT_REGISTER_DEFINE (disparity, "disparity", GST_RANK_NONE,
184     GST_TYPE_DISPARITY);
185 
186 static void gst_disparity_finalize (GObject * object);
187 static void gst_disparity_set_property (GObject * object, guint prop_id,
188     const GValue * value, GParamSpec * pspec);
189 static void gst_disparity_get_property (GObject * object, guint prop_id,
190     GValue * value, GParamSpec * pspec);
191 static GstStateChangeReturn gst_disparity_change_state (GstElement * element,
192     GstStateChange transition);
193 
194 static gboolean gst_disparity_handle_sink_event (GstPad * pad,
195     GstObject * parent, GstEvent * event);
196 static gboolean gst_disparity_handle_query (GstPad * pad,
197     GstObject * parent, GstQuery * query);
198 static GstFlowReturn gst_disparity_chain_right (GstPad * pad,
199     GstObject * parent, GstBuffer * buffer);
200 static GstFlowReturn gst_disparity_chain_left (GstPad * pad, GstObject * parent,
201     GstBuffer * buffer);
202 
203 static void initialise_disparity (GstDisparity * fs, int width, int height,
204     int nchannels);
205 static int initialise_sbm (GstDisparity * filter);
206 static int run_sbm_iteration (GstDisparity * filter);
207 static int run_sgbm_iteration (GstDisparity * filter);
208 
209 /* initialize the disparity's class */
210 static void
gst_disparity_class_init(GstDisparityClass * klass)211 gst_disparity_class_init (GstDisparityClass * klass)
212 {
213   GObjectClass *gobject_class;
214   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
215 
216   gobject_class = (GObjectClass *) klass;
217 
218   gobject_class->finalize = gst_disparity_finalize;
219   gobject_class->set_property = gst_disparity_set_property;
220   gobject_class->get_property = gst_disparity_get_property;
221 
222 
223   g_object_class_install_property (gobject_class, PROP_METHOD,
224       g_param_spec_enum ("method",
225           "Stereo matching method to use",
226           "Stereo matching method to use",
227           GST_TYPE_DISPARITY_METHOD, DEFAULT_METHOD,
228           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
229 
230   element_class->change_state = gst_disparity_change_state;
231 
232   gst_element_class_set_static_metadata (element_class,
233       "Stereo image disparity (depth) map calculation",
234       "Filter/Effect/Video",
235       "Calculates the stereo disparity map from two (sequences of) rectified and aligned stereo images",
236       "Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>");
237 
238   gst_element_class_add_static_pad_template (element_class, &src_factory);
239   gst_element_class_add_static_pad_template (element_class, &sink_factory);
240 
241   gst_type_mark_as_plugin_api (GST_TYPE_DISPARITY_METHOD, (GstPluginAPIFlags) 0);
242 }
243 
244 /* initialize the new element
245  * instantiate pads and add them to element
246  * set pad callback functions
247  * initialize instance structure
248  */
249 static void
gst_disparity_init(GstDisparity * filter)250 gst_disparity_init (GstDisparity * filter)
251 {
252   filter->sinkpad_left =
253       gst_pad_new_from_static_template (&sink_factory, "sink_left");
254   gst_pad_set_event_function (filter->sinkpad_left,
255       GST_DEBUG_FUNCPTR (gst_disparity_handle_sink_event));
256   gst_pad_set_query_function (filter->sinkpad_left,
257       GST_DEBUG_FUNCPTR (gst_disparity_handle_query));
258   gst_pad_set_chain_function (filter->sinkpad_left,
259       GST_DEBUG_FUNCPTR (gst_disparity_chain_left));
260   GST_PAD_SET_PROXY_CAPS (filter->sinkpad_left);
261   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad_left);
262 
263   filter->sinkpad_right =
264       gst_pad_new_from_static_template (&sink_factory, "sink_right");
265   gst_pad_set_event_function (filter->sinkpad_right,
266       GST_DEBUG_FUNCPTR (gst_disparity_handle_sink_event));
267   gst_pad_set_query_function (filter->sinkpad_right,
268       GST_DEBUG_FUNCPTR (gst_disparity_handle_query));
269   gst_pad_set_chain_function (filter->sinkpad_right,
270       GST_DEBUG_FUNCPTR (gst_disparity_chain_right));
271   GST_PAD_SET_PROXY_CAPS (filter->sinkpad_right);
272   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad_right);
273 
274   filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
275   gst_pad_use_fixed_caps (filter->srcpad);
276   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
277 
278   g_mutex_init (&filter->lock);
279   g_cond_init (&filter->cond);
280 
281   filter->method = DEFAULT_METHOD;
282 }
283 
284 static void
gst_disparity_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)285 gst_disparity_set_property (GObject * object, guint prop_id,
286     const GValue * value, GParamSpec * pspec)
287 {
288   GstDisparity *filter = GST_DISPARITY (object);
289   switch (prop_id) {
290     case PROP_METHOD:
291       filter->method = g_value_get_enum (value);
292       break;
293     default:
294       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
295       break;
296   }
297 }
298 
299 static void
gst_disparity_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)300 gst_disparity_get_property (GObject * object, guint prop_id,
301     GValue * value, GParamSpec * pspec)
302 {
303   GstDisparity *filter = GST_DISPARITY (object);
304 
305   switch (prop_id) {
306     case PROP_METHOD:
307       g_value_set_enum (value, filter->method);
308       break;
309     default:
310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311       break;
312   }
313 }
314 
315 /* GstElement vmethod implementations */
316 static GstStateChangeReturn
gst_disparity_change_state(GstElement * element,GstStateChange transition)317 gst_disparity_change_state (GstElement * element, GstStateChange transition)
318 {
319   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
320   GstDisparity *fs = GST_DISPARITY (element);
321   switch (transition) {
322     case GST_STATE_CHANGE_PAUSED_TO_READY:
323       g_mutex_lock (&fs->lock);
324       fs->flushing = true;
325       g_cond_signal (&fs->cond);
326       g_mutex_unlock (&fs->lock);
327       break;
328     case GST_STATE_CHANGE_READY_TO_PAUSED:
329       g_mutex_lock (&fs->lock);
330       fs->flushing = false;
331       g_mutex_unlock (&fs->lock);
332       break;
333     default:
334       break;
335   }
336 
337   ret =
338       GST_ELEMENT_CLASS (gst_disparity_parent_class)->change_state (element,
339       transition);
340 
341   switch (transition) {
342     case GST_STATE_CHANGE_PAUSED_TO_READY:
343       g_mutex_lock (&fs->lock);
344       fs->flushing = true;
345       g_cond_signal (&fs->cond);
346       g_mutex_unlock (&fs->lock);
347       break;
348     case GST_STATE_CHANGE_READY_TO_PAUSED:
349       g_mutex_lock (&fs->lock);
350       fs->flushing = false;
351       g_mutex_unlock (&fs->lock);
352       break;
353     default:
354       break;
355   }
356   return ret;
357 }
358 
359 static gboolean
gst_disparity_handle_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)360 gst_disparity_handle_sink_event (GstPad * pad,
361     GstObject * parent, GstEvent * event)
362 {
363   gboolean ret = TRUE;
364   GstDisparity *fs = GST_DISPARITY (parent);
365 
366   switch (GST_EVENT_TYPE (event)) {
367     case GST_EVENT_CAPS:
368     {
369       GstCaps *caps;
370       GstVideoInfo info;
371       gst_event_parse_caps (event, &caps);
372 
373       /* Critical section since both pads handle event sinking simultaneously */
374       g_mutex_lock (&fs->lock);
375       gst_video_info_from_caps (&info, caps);
376 
377       GST_INFO_OBJECT (pad, " Negotiating caps via event %" GST_PTR_FORMAT,
378           caps);
379       if (!gst_pad_has_current_caps (fs->srcpad)) {
380         /* Init image info (width, height, etc) and all OpenCV matrices */
381         initialise_disparity (fs, info.width, info.height,
382             info.finfo->n_components);
383 
384         /* Initialise and keep the caps. Force them on src pad */
385         fs->caps = gst_video_info_to_caps (&info);
386         gst_pad_set_caps (fs->srcpad, fs->caps);
387 
388       } else if (!gst_caps_is_equal (fs->caps, caps)) {
389         ret = FALSE;
390       }
391       g_mutex_unlock (&fs->lock);
392 
393       GST_INFO_OBJECT (pad,
394           " Negotiated caps (result %d) via event: %" GST_PTR_FORMAT, ret,
395           caps);
396       break;
397     }
398     default:
399       ret = gst_pad_event_default (pad, parent, event);
400       break;
401   }
402   return ret;
403 }
404 
405 static gboolean
gst_disparity_handle_query(GstPad * pad,GstObject * parent,GstQuery * query)406 gst_disparity_handle_query (GstPad * pad, GstObject * parent, GstQuery * query)
407 {
408   GstDisparity *fs = GST_DISPARITY (parent);
409   gboolean ret = TRUE;
410   GstCaps *template_caps;
411   GstCaps *current_caps;
412 
413   switch (GST_QUERY_TYPE (query)) {
414     case GST_QUERY_CAPS:
415       g_mutex_lock (&fs->lock);
416       current_caps = gst_pad_get_current_caps (fs->srcpad);
417       if (current_caps == NULL) {
418         template_caps = gst_pad_get_pad_template_caps (pad);
419         gst_query_set_caps_result (query, template_caps);
420         gst_caps_unref (template_caps);
421       } else {
422         gst_query_set_caps_result (query, current_caps);
423         gst_caps_unref (current_caps);
424       }
425       g_mutex_unlock (&fs->lock);
426       ret = TRUE;
427       break;
428     case GST_QUERY_ALLOCATION:
429       if (pad == fs->sinkpad_right)
430         ret = gst_pad_peer_query (fs->srcpad, query);
431       else
432         ret = FALSE;
433       break;
434     default:
435       ret = gst_pad_query_default (pad, parent, query);
436       break;
437   }
438   return ret;
439 }
440 
441 static void
gst_disparity_finalize(GObject * object)442 gst_disparity_finalize (GObject * object)
443 {
444   GstDisparity *filter;
445 
446   filter = GST_DISPARITY (object);
447 
448   filter->cvRGB_right.release ();
449   filter->cvRGB_left.release ();
450   filter->cvGray_right.release ();
451   filter->cvGray_left.release ();
452   filter->cvGray_depth_map1.release ();
453   filter->cvGray_depth_map2.release ();
454   filter->cvGray_depth_map1_2.release ();
455   filter->img_right_as_cvMat_gray.release ();
456   filter->img_left_as_cvMat_gray.release ();
457   filter->depth_map_as_cvMat.release ();
458   filter->sbm.release ();
459   filter->sgbm.release ();
460 
461   gst_caps_replace (&filter->caps, NULL);
462 
463   g_cond_clear (&filter->cond);
464   g_mutex_clear (&filter->lock);
465   G_OBJECT_CLASS (gst_disparity_parent_class)->finalize (object);
466 }
467 
468 
469 
470 static GstFlowReturn
gst_disparity_chain_left(GstPad * pad,GstObject * parent,GstBuffer * buffer)471 gst_disparity_chain_left (GstPad * pad, GstObject * parent, GstBuffer * buffer)
472 {
473   GstDisparity *fs;
474   GstMapInfo info;
475 
476   fs = GST_DISPARITY (parent);
477   GST_DEBUG_OBJECT (pad, "processing frame from left");
478   g_mutex_lock (&fs->lock);
479   if (fs->flushing) {
480     g_mutex_unlock (&fs->lock);
481     return GST_FLOW_FLUSHING;
482   }
483   if (fs->buffer_left) {
484     GST_DEBUG_OBJECT (pad, " right is busy, wait and hold");
485     g_cond_wait (&fs->cond, &fs->lock);
486     GST_DEBUG_OBJECT (pad, " right is free, continuing");
487     if (fs->flushing) {
488       g_mutex_unlock (&fs->lock);
489       return GST_FLOW_FLUSHING;
490     }
491   }
492   fs->buffer_left = buffer;
493 
494   if (!gst_buffer_map (buffer, &info, (GstMapFlags) GST_MAP_READWRITE)) {
495     return GST_FLOW_ERROR;
496   }
497   fs->cvRGB_left.data = (unsigned char *) info.data;
498   fs->cvRGB_left.datastart = (unsigned char *) info.data;
499 
500   GST_DEBUG_OBJECT (pad, "signalled right");
501   g_cond_signal (&fs->cond);
502   g_mutex_unlock (&fs->lock);
503 
504   return GST_FLOW_OK;
505 }
506 
507 static GstFlowReturn
gst_disparity_chain_right(GstPad * pad,GstObject * parent,GstBuffer * buffer)508 gst_disparity_chain_right (GstPad * pad, GstObject * parent, GstBuffer * buffer)
509 {
510   GstDisparity *fs;
511   GstMapInfo info;
512   GstFlowReturn ret;
513 
514   fs = GST_DISPARITY (parent);
515   GST_DEBUG_OBJECT (pad, "processing frame from right");
516   g_mutex_lock (&fs->lock);
517   if (fs->flushing) {
518     g_mutex_unlock (&fs->lock);
519     return GST_FLOW_FLUSHING;
520   }
521   if (fs->buffer_left == NULL) {
522     GST_DEBUG_OBJECT (pad, " left has not provided another frame yet, waiting");
523     g_cond_wait (&fs->cond, &fs->lock);
524     GST_DEBUG_OBJECT (pad, " left has just provided a frame, continuing");
525     if (fs->flushing) {
526       g_mutex_unlock (&fs->lock);
527       return GST_FLOW_FLUSHING;
528     }
529   }
530   if (!gst_buffer_map (buffer, &info, (GstMapFlags) GST_MAP_READWRITE)) {
531     g_mutex_unlock (&fs->lock);
532     return GST_FLOW_ERROR;
533   }
534 
535   fs->cvRGB_right.data = (unsigned char *) info.data;
536   fs->cvRGB_right.datastart = (unsigned char *) info.data;
537 
538   /* Here do the business */
539   GST_INFO_OBJECT (pad,
540       "comparing frames, %dB (%dx%d) %d channels", (int) info.size,
541       fs->width, fs->height, fs->actualChannels);
542 
543   /* Stereo corresponding using semi-global block matching. According to OpenCV:
544      "" The class implements modified H. Hirschmuller algorithm HH08 . The main
545      differences between the implemented algorithm and the original one are:
546 
547      - by default the algorithm is single-pass, i.e. instead of 8 directions we
548      only consider 5. Set fullDP=true to run the full variant of the algorithm
549      (which could consume a lot of memory)
550      - the algorithm matches blocks, not individual pixels (though, by setting
551      SADWindowSize=1 the blocks are reduced to single pixels)
552      - mutual information cost function is not implemented. Instead, we use a
553      simpler Birchfield-Tomasi sub-pixel metric from BT96 , though the color
554      images are supported as well.
555      - we include some pre- and post- processing steps from K. Konolige
556      algorithm FindStereoCorrespondenceBM , such as pre-filtering
557      ( CV_STEREO_BM_XSOBEL type) and post-filtering (uniqueness check, quadratic
558      interpolation and speckle filtering) ""
559    */
560   if (METHOD_SGBM == fs->method) {
561     cvtColor (fs->cvRGB_left, fs->cvGray_left, COLOR_RGB2GRAY);
562     cvtColor (fs->cvRGB_right, fs->cvGray_right, COLOR_RGB2GRAY);
563     run_sgbm_iteration (fs);
564     normalize (fs->cvGray_depth_map1, fs->cvGray_depth_map2, 0, 255,
565         NORM_MINMAX, fs->cvGray_depth_map2.type ());
566     cvtColor (fs->cvGray_depth_map2, fs->cvRGB_right, COLOR_GRAY2RGB);
567   }
568   /* Algorithm 1 is the OpenCV Stereo Block Matching, similar to the one
569      developed by Kurt Konolige [A] and that works by using small Sum-of-absolute-
570      differences (SAD) window. See the comments on top of the file.
571    */
572   else if (METHOD_SBM == fs->method) {
573     cvtColor (fs->cvRGB_left, fs->cvGray_left, COLOR_RGB2GRAY);
574     cvtColor (fs->cvRGB_right, fs->cvGray_right, COLOR_RGB2GRAY);
575     run_sbm_iteration (fs);
576     normalize (fs->cvGray_depth_map1, fs->cvGray_depth_map2, 0, 255,
577         NORM_MINMAX, fs->cvGray_depth_map2.type ());
578     cvtColor (fs->cvGray_depth_map2, fs->cvRGB_right, COLOR_GRAY2RGB);
579   }
580 
581 
582   GST_DEBUG_OBJECT (pad, " right has finished");
583   gst_buffer_unmap (fs->buffer_left, &info);
584   gst_buffer_unref (fs->buffer_left);
585   fs->buffer_left = NULL;
586   g_cond_signal (&fs->cond);
587   g_mutex_unlock (&fs->lock);
588 
589   ret = gst_pad_push (fs->srcpad, buffer);
590   return ret;
591 }
592 
593 static void
initialise_disparity(GstDisparity * fs,int width,int height,int nchannels)594 initialise_disparity (GstDisparity * fs, int width, int height, int nchannels)
595 {
596   int cv_type = CV_8UC3;
597   fs->width = width;
598   fs->height = height;
599   fs->actualChannels = nchannels;
600 
601   fs->imgSize = Size (fs->width, fs->height);
602   if (fs->actualChannels == 1) {
603     cv_type = CV_8UC1;
604   } else if (fs->actualChannels == 2) {
605     cv_type = CV_8UC2;
606   }
607 
608   fs->cvRGB_right.create (fs->imgSize, cv_type);
609   fs->cvRGB_left.create (fs->imgSize, cv_type);
610   fs->cvGray_right.create (fs->imgSize, CV_8UC1);
611   fs->cvGray_left.create (fs->imgSize, CV_8UC1);
612 
613   fs->cvGray_depth_map1.create (fs->imgSize, CV_16SC1);
614   fs->cvGray_depth_map2.create (fs->imgSize, CV_8UC1);
615   fs->cvGray_depth_map1_2.create (fs->imgSize, CV_16SC1);
616 
617   /* Stereo Block Matching methods */
618   initialise_sbm (fs);
619 }
620 
621 int
initialise_sbm(GstDisparity * filter)622 initialise_sbm (GstDisparity * filter)
623 {
624   filter->img_right_as_cvMat_gray = Mat (filter->cvGray_right);
625   filter->img_left_as_cvMat_gray = Mat (filter->cvGray_left);
626   filter->depth_map_as_cvMat = Mat (filter->cvGray_depth_map1);
627 
628   filter->sbm = StereoBM::create ();
629   filter->sgbm = StereoSGBM::create (1, 64, 3);
630 
631   filter->sbm->setBlockSize (9);
632   filter->sbm->setNumDisparities (32);
633   filter->sbm->setPreFilterSize (9);
634   filter->sbm->setPreFilterCap (32);
635   filter->sbm->setMinDisparity (0);
636   filter->sbm->setTextureThreshold (0);
637   filter->sbm->setUniquenessRatio (0);
638   filter->sbm->setSpeckleWindowSize (0);
639   filter->sbm->setSpeckleRange (0);
640   filter->sbm->setDisp12MaxDiff (0);
641 
642   filter->sgbm->setMinDisparity (1);
643   filter->sgbm->setNumDisparities (64);
644   filter->sgbm->setBlockSize (3);
645   filter->sgbm->setP1 (200);
646   filter->sgbm->setP2 (255);
647   filter->sgbm->setDisp12MaxDiff (0);
648   filter->sgbm->setPreFilterCap (0);
649   filter->sgbm->setUniquenessRatio (0);
650   filter->sgbm->setSpeckleWindowSize (0);
651   filter->sgbm->setSpeckleRange (0);
652   filter->sgbm->setMode (StereoSGBM::MODE_HH);
653 
654   return (0);
655 }
656 
657 int
run_sbm_iteration(GstDisparity * filter)658 run_sbm_iteration (GstDisparity * filter)
659 {
660   ((StereoBM *) filter->sbm)->compute (filter->img_left_as_cvMat_gray,
661       filter->img_right_as_cvMat_gray, filter->depth_map_as_cvMat);
662 
663   return (0);
664 }
665 
666 int
run_sgbm_iteration(GstDisparity * filter)667 run_sgbm_iteration (GstDisparity * filter)
668 {
669   ((StereoSGBM *) filter->sgbm)->compute (filter->img_left_as_cvMat_gray,
670       filter->img_right_as_cvMat_gray, filter->depth_map_as_cvMat);
671 
672   return (0);
673 }
674