3 * Copyright (C) 2013 Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>
4 * Except: Parts of code inside the preprocessor define CODE_FROM_OREILLY_BOOK,
5 * which are downloaded from O'Reilly website
6 * [http://examples.oreilly.com/9780596516130/]
7 * and adapted. Its license reads:
9 * Right to use this code in any way you want without warrenty, support or
10 * any guarentee of it working. "
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
31 * Alternatively, the contents of this file may be used under the
32 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
33 * which case the following provisions apply instead of the ones
36 * This library is free software; you can redistribute it and/or
37 * modify it under the terms of the GNU Library General Public
38 * License as published by the Free Software Foundation; either
39 * version 2 of the License, or (at your option) any later version.
41 * This library is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * Library General Public License for more details.
46 * You should have received a copy of the GNU Library General Public
47 * License along with this library; if not, write to the
48 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
49 * Boston, MA 02110-1301, USA.
51 #define CODE_FROM_OREILLY_BOOK
54 * SECTION:element-segmentation
56 * This element creates and updates a fg/bg model using one of several approaches.
57 * The one called "codebook" refers to the codebook approach following the opencv
58 * O'Reilly book [1] implementation of the algorithm described in K. Kim,
59 * T. H. Chalidabhongse, D. Harwood and L. Davis [2]. BackgroundSubtractorMOG [3],
60 * or MOG for shorts, refers to a Gaussian Mixture-based Background/Foreground
61 * Segmentation Algorithm. OpenCV MOG implements the algorithm described in [4].
62 * BackgroundSubtractorMOG2 [5], refers to another Gaussian Mixture-based
63 * Background/Foreground segmentation algorithm. OpenCV MOG2 implements the
64 * algorithm described in [6] and [7].
66 * [1] Learning OpenCV: Computer Vision with the OpenCV Library by Gary Bradski
67 * and Adrian Kaehler, Published by O'Reilly Media, October 3, 2008
68 * [2] "Real-time Foreground-Background Segmentation using Codebook Model",
69 * Real-time Imaging, Volume 11, Issue 3, Pages 167-256, June 2005.
70 * [3] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
71 * [4] P. KadewTraKuPong and R. Bowden, "An improved adaptive background
72 * mixture model for real-time tracking with shadow detection", Proc. 2nd
73 * European Workshop on Advanced Video-Based Surveillance Systems, 2001
74 * [5] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
75 * [6] Z.Zivkovic, "Improved adaptive Gausian mixture model for background
76 * subtraction", International Conference Pattern Recognition, UK, August, 2004.
77 * [7] Z.Zivkovic, F. van der Heijden, "Efficient Adaptive Density Estimation
78 * per Image Pixel for the Task of Background Subtraction", Pattern Recognition
79 * Letters, vol. 27, no. 7, pages 773-780, 2006.
82 * <title>Example launch line</title>
84 * gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! video/x-raw,width=320,height=240 ! videoconvert ! segmentation test-mode=true method=2 ! videoconvert ! ximagesink
95 #include "gstsegmentation.h"
96 #include <opencv2/video/background_segm.hpp>
98 GST_DEBUG_CATEGORY_STATIC (gst_segmentation_debug);
99 #define GST_CAT_DEFAULT gst_segmentation_debug
101 /* Filter signals and args */
120 } GstSegmentationMethod;
122 #define DEFAULT_TEST_MODE FALSE
123 #define DEFAULT_METHOD METHOD_MOG2
124 #define DEFAULT_LEARNING_RATE 0.01
126 #define GST_TYPE_SEGMENTATION_METHOD (gst_segmentation_method_get_type ())
128 gst_segmentation_method_get_type (void)
130 static GType etype = 0;
132 static const GEnumValue values[] = {
133 {METHOD_BOOK, "Codebook-based segmentation (Bradski2008)", "codebook"},
134 {METHOD_MOG, "Mixture-of-Gaussians segmentation (Bowden2001)", "mog"},
135 {METHOD_MOG2, "Mixture-of-Gaussians segmentation (Zivkovic2004)", "mog2"},
138 etype = g_enum_register_static ("GstSegmentationMethod", values);
143 G_DEFINE_TYPE (GstSegmentation, gst_segmentation, GST_TYPE_VIDEO_FILTER);
144 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
147 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGBA")));
149 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
152 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGBA")));
155 static void gst_segmentation_set_property (GObject * object, guint prop_id,
156 const GValue * value, GParamSpec * pspec);
157 static void gst_segmentation_get_property (GObject * object, guint prop_id,
158 GValue * value, GParamSpec * pspec);
160 static GstFlowReturn gst_segmentation_transform_ip (GstVideoFilter * btrans,
161 GstVideoFrame * frame);
163 static gboolean gst_segmentation_stop (GstBaseTransform * basesrc);
164 static gboolean gst_segmentation_set_info (GstVideoFilter * filter,
165 GstCaps * incaps, GstVideoInfo * in_info,
166 GstCaps * outcaps, GstVideoInfo * out_info);
167 static void gst_segmentation_release_all_pointers (GstSegmentation * filter);
169 /* Codebook algorithm + connected components functions*/
170 static int update_codebook (unsigned char *p, codeBook * c,
171 unsigned *cbBounds, int numChannels);
172 static int clear_stale_entries (codeBook * c);
173 static unsigned char background_diff (unsigned char *p, codeBook * c,
174 int numChannels, int *minMod, int *maxMod);
175 static void find_connected_components (IplImage * mask, int poly1_hull0,
176 float perimScale, CvMemStorage * mem_storage, CvSeq * contours);
178 /* MOG (Mixture-of-Gaussians functions */
179 static int initialise_mog (GstSegmentation * filter);
180 static int run_mog_iteration (GstSegmentation * filter);
181 static int run_mog2_iteration (GstSegmentation * filter);
182 static int finalise_mog (GstSegmentation * filter);
184 /* initialize the segmentation's class */
186 gst_segmentation_class_init (GstSegmentationClass * klass)
188 GObjectClass *gobject_class;
189 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
190 GstBaseTransformClass *basesrc_class = GST_BASE_TRANSFORM_CLASS (klass);
191 GstVideoFilterClass *video_class = (GstVideoFilterClass *) klass;
193 gobject_class = (GObjectClass *) klass;
195 gobject_class->set_property = gst_segmentation_set_property;
196 gobject_class->get_property = gst_segmentation_get_property;
198 basesrc_class->stop = gst_segmentation_stop;
200 video_class->transform_frame_ip = gst_segmentation_transform_ip;
201 video_class->set_info = gst_segmentation_set_info;
203 g_object_class_install_property (gobject_class, PROP_METHOD,
204 g_param_spec_enum ("method",
205 "Segmentation method to use",
206 "Segmentation method to use",
207 GST_TYPE_SEGMENTATION_METHOD, DEFAULT_METHOD,
208 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
210 g_object_class_install_property (gobject_class, PROP_TEST_MODE,
211 g_param_spec_boolean ("test-mode", "test-mode",
212 "If true, the output RGB is overwritten with the calculated foreground (white color)",
213 DEFAULT_TEST_MODE, (GParamFlags)
214 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
216 g_object_class_install_property (gobject_class, PROP_LEARNING_RATE,
217 g_param_spec_float ("learning-rate", "learning-rate",
218 "Speed with which a motionless foreground pixel would become background (inverse of number of frames)",
219 0, 1, DEFAULT_LEARNING_RATE, (GParamFlags) (G_PARAM_READWRITE)));
221 gst_element_class_set_static_metadata (element_class,
222 "Foreground/background video sequence segmentation",
223 "Filter/Effect/Video",
224 "Create a Foregound/Background mask applying a particular algorithm",
225 "Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>");
227 gst_element_class_add_pad_template (element_class,
228 gst_static_pad_template_get (&src_factory));
229 gst_element_class_add_pad_template (element_class,
230 gst_static_pad_template_get (&sink_factory));
234 /* initialize the new element
235 * instantiate pads and add them to element
236 * set pad calback functions
237 * initialize instance structure
240 gst_segmentation_init (GstSegmentation * filter)
242 filter->method = DEFAULT_METHOD;
243 filter->test_mode = DEFAULT_TEST_MODE;
244 filter->framecount = 0;
245 filter->learning_rate = DEFAULT_LEARNING_RATE;
246 gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
251 gst_segmentation_set_property (GObject * object, guint prop_id,
252 const GValue * value, GParamSpec * pspec)
254 GstSegmentation *filter = GST_SEGMENTATION (object);
258 filter->method = g_value_get_enum (value);
261 filter->test_mode = g_value_get_boolean (value);
263 case PROP_LEARNING_RATE:
264 filter->learning_rate = g_value_get_float (value);
267 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273 gst_segmentation_get_property (GObject * object, guint prop_id,
274 GValue * value, GParamSpec * pspec)
276 GstSegmentation *filter = GST_SEGMENTATION (object);
280 g_value_set_enum (value, filter->method);
283 g_value_set_boolean (value, filter->test_mode);
285 case PROP_LEARNING_RATE:
286 g_value_set_float (value, filter->learning_rate);
289 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
294 /* GstElement vmethod implementations */
295 /* this function handles the link with other elements */
297 gst_segmentation_set_info (GstVideoFilter * filter,
298 GstCaps * incaps, GstVideoInfo * in_info,
299 GstCaps * outcaps, GstVideoInfo * out_info)
301 GstSegmentation *segmentation = GST_SEGMENTATION (filter);
304 size = cvSize (in_info->width, in_info->height);
305 segmentation->width = in_info->width;
306 segmentation->height = in_info->height;
307 /* If cvRGB is already allocated, it means there's a cap modification, */
308 /* so release first all the images. */
309 if (NULL != segmentation->cvRGBA)
310 gst_segmentation_release_all_pointers (segmentation);
312 segmentation->cvRGBA = cvCreateImageHeader (size, IPL_DEPTH_8U, 4);
314 segmentation->cvRGB = cvCreateImage (size, IPL_DEPTH_8U, 3);
315 segmentation->cvYUV = cvCreateImage (size, IPL_DEPTH_8U, 3);
317 segmentation->cvFG = cvCreateImage (size, IPL_DEPTH_8U, 1);
318 cvZero (segmentation->cvFG);
320 segmentation->ch1 = cvCreateImage (size, IPL_DEPTH_8U, 1);
321 segmentation->ch2 = cvCreateImage (size, IPL_DEPTH_8U, 1);
322 segmentation->ch3 = cvCreateImage (size, IPL_DEPTH_8U, 1);
324 /* Codebook method */
325 segmentation->TcodeBook = (codeBook *)
326 g_malloc (sizeof (codeBook) *
327 (segmentation->width * segmentation->height + 1));
328 for (int j = 0; j < segmentation->width * segmentation->height; j++) {
329 segmentation->TcodeBook[j].numEntries = 0;
330 segmentation->TcodeBook[j].t = 0;
332 segmentation->learning_interval = (int) (1.0 / segmentation->learning_rate);
334 /* Mixture-of-Gaussians (mog) methods */
335 initialise_mog (segmentation);
342 gst_segmentation_stop (GstBaseTransform * basesrc)
344 GstSegmentation *filter = GST_SEGMENTATION (basesrc);
346 if (filter->cvRGBA != NULL)
347 gst_segmentation_release_all_pointers (filter);
353 gst_segmentation_release_all_pointers (GstSegmentation * filter)
355 cvReleaseImage (&filter->cvRGBA);
356 cvReleaseImage (&filter->cvRGB);
357 cvReleaseImage (&filter->cvYUV);
358 cvReleaseImage (&filter->cvFG);
359 cvReleaseImage (&filter->ch1);
360 cvReleaseImage (&filter->ch2);
361 cvReleaseImage (&filter->ch3);
363 cvReleaseMemStorage (&filter->mem_storage);
365 g_free (filter->TcodeBook);
366 finalise_mog (filter);
370 gst_segmentation_transform_ip (GstVideoFilter * btrans, GstVideoFrame * frame)
372 GstSegmentation *filter = GST_SEGMENTATION (btrans);
375 /* get image data from the input, which is RGBA */
376 filter->cvRGBA->imageData = (char *) GST_VIDEO_FRAME_COMP_DATA (frame, 0);
377 filter->cvRGBA->widthStep = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
378 filter->framecount++;
380 /* Image preprocessing: color space conversion etc */
381 cvCvtColor (filter->cvRGBA, filter->cvRGB, CV_RGBA2RGB);
382 cvCvtColor (filter->cvRGB, filter->cvYUV, CV_RGB2YCrCb);
384 /* Create and update a fg/bg model using a codebook approach following the
385 * opencv O'Reilly book [1] implementation of the algo described in [2].
387 * [1] Learning OpenCV: Computer Vision with the OpenCV Library by Gary
388 * Bradski and Adrian Kaehler, Published by O'Reilly Media, October 3, 2008
389 * [2] "Real-time Foreground-Background Segmentation using Codebook Model",
390 * Real-time Imaging, Volume 11, Issue 3, Pages 167-256, June 2005. */
391 if (METHOD_BOOK == filter->method) {
392 unsigned cbBounds[3] = { 10, 5, 5 };
393 int minMod[3] = { 20, 20, 20 }, maxMod[3] = {
396 if (filter->framecount < 30) {
397 /* Learning background phase: update_codebook on every frame */
398 for (j = 0; j < filter->width * filter->height; j++) {
399 update_codebook ((unsigned char *) filter->cvYUV->imageData + j * 3,
400 (codeBook *) & (filter->TcodeBook[j]), cbBounds, 3);
403 /* this updating is responsible for FG becoming BG again */
404 if (filter->framecount % filter->learning_interval == 0) {
405 for (j = 0; j < filter->width * filter->height; j++) {
406 update_codebook ((uchar *) filter->cvYUV->imageData + j * 3,
407 (codeBook *) & (filter->TcodeBook[j]), cbBounds, 3);
410 if (filter->framecount % 60 == 0) {
411 for (j = 0; j < filter->width * filter->height; j++)
412 clear_stale_entries ((codeBook *) & (filter->TcodeBook[j]));
415 for (j = 0; j < filter->width * filter->height; j++) {
417 ((uchar *) filter->cvYUV->imageData + j * 3,
418 (codeBook *) & (filter->TcodeBook[j]), 3, minMod, maxMod)) {
419 filter->cvFG->imageData[j] = 255;
421 filter->cvFG->imageData[j] = 0;
426 /* 3rd param is the smallest area to show: (w+h)/param , in pixels */
427 find_connected_components (filter->cvFG, 1, 10000,
428 filter->mem_storage, filter->contours);
431 /* Create the foreground and background masks using BackgroundSubtractorMOG [1],
432 * Gaussian Mixture-based Background/Foreground segmentation algorithm. OpenCV
433 * MOG implements the algorithm described in [2].
435 * [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
436 * [2] P. KadewTraKuPong and R. Bowden, "An improved adaptive background
437 * mixture model for real-time tracking with shadow detection", Proc. 2nd
438 * European Workshop on Advanced Video-Based Surveillance Systems, 2001
440 else if (METHOD_MOG == filter->method) {
441 run_mog_iteration (filter);
443 /* Create the foreground and background masks using BackgroundSubtractorMOG2
444 * [1], Gaussian Mixture-based Background/Foreground segmentation algorithm.
445 * OpenCV MOG2 implements the algorithm described in [2] and [3].
447 * [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
448 * [2] Z.Zivkovic, "Improved adaptive Gausian mixture model for background
449 * subtraction", International Conference Pattern Recognition, UK, Aug 2004.
450 * [3] Z.Zivkovic, F. van der Heijden, "Efficient Adaptive Density Estimation
451 * per Image Pixel for the Task of Background Subtraction", Pattern
452 * Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. */
453 else if (METHOD_MOG2 == filter->method) {
454 run_mog2_iteration (filter);
457 /* if we want to test_mode, just overwrite the output */
458 if (filter->test_mode) {
459 cvCvtColor (filter->cvFG, filter->cvRGB, CV_GRAY2RGB);
461 cvSplit (filter->cvRGB, filter->ch1, filter->ch2, filter->ch3, NULL);
463 cvSplit (filter->cvRGBA, filter->ch1, filter->ch2, filter->ch3, NULL);
465 /* copy anyhow the fg/bg to the alpha channel in the output image */
466 cvMerge (filter->ch1, filter->ch2, filter->ch3, filter->cvFG, filter->cvRGBA);
472 /* entry point to initialize the plug-in
473 * initialize the plug-in itself
474 * register the element factories and other features
477 gst_segmentation_plugin_init (GstPlugin * plugin)
479 GST_DEBUG_CATEGORY_INIT (gst_segmentation_debug, "segmentation",
480 0, "Performs Foreground/Background segmentation in video sequences");
482 return gst_element_register (plugin, "segmentation", GST_RANK_NONE,
483 GST_TYPE_SEGMENTATION);
488 #ifdef CODE_FROM_OREILLY_BOOK /* See license at the beginning of the page */
490 int update_codebook(uchar *p, codeBook &c, unsigned cbBounds)
491 Updates the codebook entry with a new data point
493 p Pointer to a YUV or HSI pixel
494 c Codebook for this pixel
495 cbBounds Learning bounds for codebook (Rule of thumb: 10)
496 numChannels Number of color channels we¡¯re learning
499 cvBounds must be of length equal to numChannels
505 update_codebook (unsigned char *p, codeBook * c, unsigned *cbBounds,
509 unsigned int high[3], low[3];
513 for (n = 0; n < numChannels; n++) {
514 high[n] = p[n] + cbBounds[n];
518 if (p[n] > cbBounds[n])
519 low[n] = p[n] - cbBounds[n];
524 /* SEE IF THIS FITS AN EXISTING CODEWORD */
525 for (i = 0; i < c->numEntries; i++) {
527 for (n = 0; n < numChannels; n++) {
528 if ((c->cb[i]->learnLow[n] <= *(p + n)) &&
529 /* Found an entry for this channel */
530 (*(p + n) <= c->cb[i]->learnHigh[n])) {
534 if (matchChannel == numChannels) { /* If an entry was found */
535 c->cb[i]->t_last_update = c->t;
536 /* adjust this codeword for the first channel */
537 for (n = 0; n < numChannels; n++) {
538 if (c->cb[i]->max[n] < *(p + n)) {
539 c->cb[i]->max[n] = *(p + n);
540 } else if (c->cb[i]->min[n] > *(p + n)) {
541 c->cb[i]->min[n] = *(p + n);
547 /* OVERHEAD TO TRACK POTENTIAL STALE ENTRIES */
548 for (int s = 0; s < c->numEntries; s++) {
549 /* Track which codebook entries are going stale: */
550 int negRun = c->t - c->cb[s]->t_last_update;
551 if (c->cb[s]->stale < negRun)
552 c->cb[s]->stale = negRun;
554 /* ENTER A NEW CODEWORD IF NEEDED */
555 if (i == c->numEntries) { /* if no existing codeword found, make one */
557 (code_element **) g_malloc (sizeof (code_element *) *
558 (c->numEntries + 1));
559 for (int ii = 0; ii < c->numEntries; ii++) {
560 foo[ii] = c->cb[ii]; /* copy all pointers */
562 foo[c->numEntries] = (code_element *) g_malloc (sizeof (code_element));
566 for (n = 0; n < numChannels; n++) {
567 c->cb[c->numEntries]->learnHigh[n] = high[n];
568 c->cb[c->numEntries]->learnLow[n] = low[n];
569 c->cb[c->numEntries]->max[n] = *(p + n);
570 c->cb[c->numEntries]->min[n] = *(p + n);
572 c->cb[c->numEntries]->t_last_update = c->t;
573 c->cb[c->numEntries]->stale = 0;
576 /* SLOWLY ADJUST LEARNING BOUNDS */
577 for (n = 0; n < numChannels; n++) {
578 if (c->cb[i]->learnHigh[n] < high[n])
579 c->cb[i]->learnHigh[n] += 1;
580 if (c->cb[i]->learnLow[n] > low[n])
581 c->cb[i]->learnLow[n] -= 1;
591 int clear_stale_entries(codeBook &c)
592 During learning, after you've learned for some period of time,
593 periodically call this to clear out stale codebook entries
595 c Codebook to clean up
598 number of entries cleared
601 clear_stale_entries (codeBook * c)
603 int staleThresh = c->t >> 1;
604 int *keep = (int *) g_malloc (sizeof (int) * (c->numEntries));
609 /* SEE WHICH CODEBOOK ENTRIES ARE TOO STALE */
610 for (int i = 0; i < c->numEntries; i++) {
611 if (c->cb[i]->stale > staleThresh)
612 keep[i] = 0; /* Mark for destruction */
614 keep[i] = 1; /* Mark to keep */
618 /* KEEP ONLY THE GOOD */
619 c->t = 0; /* Full reset on stale tracking */
620 foo = (code_element **) g_malloc (sizeof (code_element *) * keepCnt);
622 for (int ii = 0; ii < c->numEntries; ii++) {
625 /* We have to refresh these entries for next clearStale */
626 foo[k]->t_last_update = 0;
634 numCleared = c->numEntries - keepCnt;
635 c->numEntries = keepCnt;
642 uchar background_diff( uchar *p, codeBook &c,
643 int minMod, int maxMod)
644 Given a pixel and a codebook, determine if the pixel is
645 covered by the codebook
647 p Pixel pointer (YUV interleaved)
649 numChannels Number of channels we are testing
650 maxMod Add this (possibly negative) number onto
652 max level when determining if new pixel is foreground
653 minMod Subract this (possibly negative) number from
654 min level when determining if new pixel is foreground
657 minMod and maxMod must have length numChannels,
658 e.g. 3 channels => minMod[3], maxMod[3]. There is one min and
659 one max threshold per channel.
662 0 => background, 255 => foreground
665 background_diff (unsigned char *p, codeBook * c, int numChannels,
666 int *minMod, int *maxMod)
669 /* SEE IF THIS FITS AN EXISTING CODEWORD */
671 for (i = 0; i < c->numEntries; i++) {
673 for (int n = 0; n < numChannels; n++) {
674 if ((c->cb[i]->min[n] - minMod[n] <= *(p + n)) &&
675 (*(p + n) <= c->cb[i]->max[n] + maxMod[n])) {
676 matchChannel++; /* Found an entry for this channel */
681 if (matchChannel == numChannels) {
682 break; /* Found an entry that matched all channels */
685 if (i >= c->numEntries)
694 void find_connected_components(IplImage *mask, int poly1_hull0,
695 float perimScale, int *num,
696 CvRect *bbs, CvPoint *centers)
697 This cleans up the foreground segmentation mask derived from calls
700 mask Is a grayscale (8-bit depth) “rawâ€
\9d mask image that
704 poly1_hull0 If set, approximate connected component by
705 (DEFAULT) polygon, or else convex hull (0)
706 perimScale Len = image (width+height)/perimScale. If contour
707 len < this, delete that contour (DEFAULT: 4)
708 num Maximum number of rectangles and/or centers to
709 return; on return, will contain number filled
711 bbs Pointer to bounding box rectangle vector of
712 length num. (DEFAULT SETTING: NULL)
713 centers Pointer to contour centers vector of length
717 /* Approx.threshold - the bigger it is, the simpler is the boundary */
718 #define CVCONTOUR_APPROX_LEVEL 1
719 /* How many iterations of erosion and/or dilation there should be */
720 #define CVCLOSE_ITR 1
722 find_connected_components (IplImage * mask, int poly1_hull0, float perimScale,
723 CvMemStorage * mem_storage, CvSeq * contours)
725 CvContourScanner scanner;
728 /* Just some convenience variables */
729 const CvScalar CVX_WHITE = CV_RGB (0xff, 0xff, 0xff);
730 const CvScalar CVX_BLACK = CV_RGB (0x00, 0x00, 0x00);
732 /* CLEAN UP RAW MASK */
733 cvMorphologyEx (mask, mask, 0, 0, CV_MOP_OPEN, CVCLOSE_ITR);
734 cvMorphologyEx (mask, mask, 0, 0, CV_MOP_CLOSE, CVCLOSE_ITR);
735 /* FIND CONTOURS AROUND ONLY BIGGER REGIONS */
736 if (mem_storage == NULL) {
737 mem_storage = cvCreateMemStorage (0);
739 cvClearMemStorage (mem_storage);
742 scanner = cvStartFindContours (mask, mem_storage, sizeof (CvContour),
743 CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint (0, 0));
745 while ((c = cvFindNextContour (scanner)) != NULL) {
746 double len = cvContourArea (c, CV_WHOLE_SEQ, 0);
747 /* calculate perimeter len threshold: */
748 double q = (mask->height + mask->width) / perimScale;
749 /* Get rid of blob if its perimeter is too small: */
751 cvSubstituteContour (scanner, NULL);
753 /* Smooth its edges if its large enough */
756 /* Polygonal approximation */
758 cvApproxPoly (c, sizeof (CvContour), mem_storage, CV_POLY_APPROX_DP,
759 CVCONTOUR_APPROX_LEVEL, 0);
761 /* Convex Hull of the segmentation */
762 c_new = cvConvexHull2 (c, mem_storage, CV_CLOCKWISE, 1);
764 cvSubstituteContour (scanner, c_new);
768 contours = cvEndFindContours (&scanner);
770 /* PAINT THE FOUND REGIONS BACK INTO THE IMAGE */
772 /* DRAW PROCESSED CONTOURS INTO THE MASK */
773 for (c = contours; c != NULL; c = c->h_next)
774 cvDrawContours (mask, c, CVX_WHITE, CVX_BLACK, -1, CV_FILLED, 8, cvPoint (0,
777 #endif /*ifdef CODE_FROM_OREILLY_BOOK */
781 initialise_mog (GstSegmentation * filter)
783 filter->img_input_as_cvMat = (void *) new cv::Mat (filter->cvYUV, false);
784 filter->img_fg_as_cvMat = (void *) new cv::Mat (filter->cvFG, false);
786 filter->mog = (void *) new cv::BackgroundSubtractorMOG ();
787 filter->mog2 = (void *) new cv::BackgroundSubtractorMOG2 ();
793 run_mog_iteration (GstSegmentation * filter)
795 ((cv::Mat *) filter->img_input_as_cvMat)->data =
796 (uchar *) filter->cvYUV->imageData;
797 ((cv::Mat *) filter->img_fg_as_cvMat)->data =
798 (uchar *) filter->cvFG->imageData;
801 BackgroundSubtractorMOG [1], Gaussian Mixture-based Background/Foreground
802 Segmentation Algorithm. OpenCV MOG implements the algorithm described in [2].
804 [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
805 [2] P. KadewTraKuPong and R. Bowden, "An improved adaptive background
806 mixture model for real-time tracking with shadow detection", Proc. 2nd
807 European Workshop on Advanced Video-Based Surveillance Systems, 2001
810 (*((cv::BackgroundSubtractorMOG *) filter->mog)) (*((cv::Mat *) filter->
811 img_input_as_cvMat), *((cv::Mat *) filter->img_fg_as_cvMat),
812 filter->learning_rate);
818 run_mog2_iteration (GstSegmentation * filter)
820 ((cv::Mat *) filter->img_input_as_cvMat)->data =
821 (uchar *) filter->cvYUV->imageData;
822 ((cv::Mat *) filter->img_fg_as_cvMat)->data =
823 (uchar *) filter->cvFG->imageData;
826 BackgroundSubtractorMOG2 [1], Gaussian Mixture-based Background/Foreground
827 segmentation algorithm. OpenCV MOG2 implements the algorithm described in
830 [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
831 [2] Z.Zivkovic, "Improved adaptive Gausian mixture model for background
832 subtraction", International Conference Pattern Recognition, UK, August, 2004.
833 [3] Z.Zivkovic, F. van der Heijden, "Efficient Adaptive Density Estimation per
834 Image Pixel for the Task of Background Subtraction", Pattern Recognition
835 Letters, vol. 27, no. 7, pages 773-780, 2006.
838 (*((cv::BackgroundSubtractorMOG *) filter->mog2)) (*((cv::Mat *) filter->
839 img_input_as_cvMat), *((cv::Mat *) filter->img_fg_as_cvMat),
840 filter->learning_rate);
846 finalise_mog (GstSegmentation * filter)
848 delete (cv::Mat *) filter->img_input_as_cvMat;
849 delete (cv::Mat *) filter->img_fg_as_cvMat;
850 delete (cv::BackgroundSubtractorMOG *) filter->mog;
851 delete (cv::BackgroundSubtractorMOG2 *) filter->mog2;