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
93 #include "gstsegmentation.h"
94 #include <opencv2/video/background_segm.hpp>
95 #include <opencv2/imgproc/imgproc_c.h>
97 GST_DEBUG_CATEGORY_STATIC (gst_segmentation_debug);
98 #define GST_CAT_DEFAULT gst_segmentation_debug
100 /* Filter signals and args */
119 } GstSegmentationMethod;
121 #define DEFAULT_TEST_MODE FALSE
122 #define DEFAULT_METHOD METHOD_MOG2
123 #define DEFAULT_LEARNING_RATE 0.01
125 #define GST_TYPE_SEGMENTATION_METHOD (gst_segmentation_method_get_type ())
127 gst_segmentation_method_get_type (void)
129 static GType etype = 0;
131 static const GEnumValue values[] = {
132 {METHOD_BOOK, "Codebook-based segmentation (Bradski2008)", "codebook"},
133 {METHOD_MOG, "Mixture-of-Gaussians segmentation (Bowden2001)", "mog"},
134 {METHOD_MOG2, "Mixture-of-Gaussians segmentation (Zivkovic2004)", "mog2"},
137 etype = g_enum_register_static ("GstSegmentationMethod", values);
142 G_DEFINE_TYPE (GstSegmentation, gst_segmentation, GST_TYPE_VIDEO_FILTER);
143 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
146 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGBA")));
148 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
151 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGBA")));
154 static void gst_segmentation_set_property (GObject * object, guint prop_id,
155 const GValue * value, GParamSpec * pspec);
156 static void gst_segmentation_get_property (GObject * object, guint prop_id,
157 GValue * value, GParamSpec * pspec);
159 static GstFlowReturn gst_segmentation_transform_ip (GstVideoFilter * btrans,
160 GstVideoFrame * frame);
162 static gboolean gst_segmentation_stop (GstBaseTransform * basesrc);
163 static gboolean gst_segmentation_set_info (GstVideoFilter * filter,
164 GstCaps * incaps, GstVideoInfo * in_info,
165 GstCaps * outcaps, GstVideoInfo * out_info);
166 static void gst_segmentation_release_all_pointers (GstSegmentation * filter);
168 /* Codebook algorithm + connected components functions*/
169 static int update_codebook (unsigned char *p, codeBook * c,
170 unsigned *cbBounds, int numChannels);
171 static int clear_stale_entries (codeBook * c);
172 static unsigned char background_diff (unsigned char *p, codeBook * c,
173 int numChannels, int *minMod, int *maxMod);
174 static void find_connected_components (IplImage * mask, int poly1_hull0,
175 float perimScale, CvMemStorage * mem_storage, CvSeq * contours);
177 /* MOG (Mixture-of-Gaussians functions */
178 static int initialise_mog (GstSegmentation * filter);
179 static int run_mog_iteration (GstSegmentation * filter);
180 static int run_mog2_iteration (GstSegmentation * filter);
181 static int finalise_mog (GstSegmentation * filter);
183 /* initialize the segmentation's class */
185 gst_segmentation_class_init (GstSegmentationClass * klass)
187 GObjectClass *gobject_class;
188 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
189 GstBaseTransformClass *basesrc_class = GST_BASE_TRANSFORM_CLASS (klass);
190 GstVideoFilterClass *video_class = (GstVideoFilterClass *) klass;
192 gobject_class = (GObjectClass *) klass;
194 gobject_class->set_property = gst_segmentation_set_property;
195 gobject_class->get_property = gst_segmentation_get_property;
197 basesrc_class->stop = gst_segmentation_stop;
199 video_class->transform_frame_ip = gst_segmentation_transform_ip;
200 video_class->set_info = gst_segmentation_set_info;
202 g_object_class_install_property (gobject_class, PROP_METHOD,
203 g_param_spec_enum ("method",
204 "Segmentation method to use",
205 "Segmentation method to use",
206 GST_TYPE_SEGMENTATION_METHOD, DEFAULT_METHOD,
207 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
209 g_object_class_install_property (gobject_class, PROP_TEST_MODE,
210 g_param_spec_boolean ("test-mode", "test-mode",
211 "If true, the output RGB is overwritten with the calculated foreground (white color)",
212 DEFAULT_TEST_MODE, (GParamFlags)
213 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
215 g_object_class_install_property (gobject_class, PROP_LEARNING_RATE,
216 g_param_spec_float ("learning-rate", "learning-rate",
217 "Speed with which a motionless foreground pixel would become background (inverse of number of frames)",
218 0, 1, DEFAULT_LEARNING_RATE, (GParamFlags) (G_PARAM_READWRITE)));
220 gst_element_class_set_static_metadata (element_class,
221 "Foreground/background video sequence segmentation",
222 "Filter/Effect/Video",
223 "Create a Foregound/Background mask applying a particular algorithm",
224 "Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>");
226 gst_element_class_add_pad_template (element_class,
227 gst_static_pad_template_get (&src_factory));
228 gst_element_class_add_pad_template (element_class,
229 gst_static_pad_template_get (&sink_factory));
233 /* initialize the new element
234 * instantiate pads and add them to element
235 * set pad calback functions
236 * initialize instance structure
239 gst_segmentation_init (GstSegmentation * filter)
241 filter->method = DEFAULT_METHOD;
242 filter->test_mode = DEFAULT_TEST_MODE;
243 filter->framecount = 0;
244 filter->learning_rate = DEFAULT_LEARNING_RATE;
245 gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
250 gst_segmentation_set_property (GObject * object, guint prop_id,
251 const GValue * value, GParamSpec * pspec)
253 GstSegmentation *filter = GST_SEGMENTATION (object);
257 filter->method = g_value_get_enum (value);
260 filter->test_mode = g_value_get_boolean (value);
262 case PROP_LEARNING_RATE:
263 filter->learning_rate = g_value_get_float (value);
266 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
272 gst_segmentation_get_property (GObject * object, guint prop_id,
273 GValue * value, GParamSpec * pspec)
275 GstSegmentation *filter = GST_SEGMENTATION (object);
279 g_value_set_enum (value, filter->method);
282 g_value_set_boolean (value, filter->test_mode);
284 case PROP_LEARNING_RATE:
285 g_value_set_float (value, filter->learning_rate);
288 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293 /* GstElement vmethod implementations */
294 /* this function handles the link with other elements */
296 gst_segmentation_set_info (GstVideoFilter * filter,
297 GstCaps * incaps, GstVideoInfo * in_info,
298 GstCaps * outcaps, GstVideoInfo * out_info)
300 GstSegmentation *segmentation = GST_SEGMENTATION (filter);
303 size = cvSize (in_info->width, in_info->height);
304 segmentation->width = in_info->width;
305 segmentation->height = in_info->height;
306 /* If cvRGB is already allocated, it means there's a cap modification, */
307 /* so release first all the images. */
308 if (NULL != segmentation->cvRGBA)
309 gst_segmentation_release_all_pointers (segmentation);
311 segmentation->cvRGBA = cvCreateImageHeader (size, IPL_DEPTH_8U, 4);
313 segmentation->cvRGB = cvCreateImage (size, IPL_DEPTH_8U, 3);
314 segmentation->cvYUV = cvCreateImage (size, IPL_DEPTH_8U, 3);
316 segmentation->cvFG = cvCreateImage (size, IPL_DEPTH_8U, 1);
317 cvZero (segmentation->cvFG);
319 segmentation->ch1 = cvCreateImage (size, IPL_DEPTH_8U, 1);
320 segmentation->ch2 = cvCreateImage (size, IPL_DEPTH_8U, 1);
321 segmentation->ch3 = cvCreateImage (size, IPL_DEPTH_8U, 1);
323 /* Codebook method */
324 segmentation->TcodeBook = (codeBook *)
325 g_malloc (sizeof (codeBook) *
326 (segmentation->width * segmentation->height + 1));
327 for (int j = 0; j < segmentation->width * segmentation->height; j++) {
328 segmentation->TcodeBook[j].numEntries = 0;
329 segmentation->TcodeBook[j].t = 0;
331 segmentation->learning_interval = (int) (1.0 / segmentation->learning_rate);
333 /* Mixture-of-Gaussians (mog) methods */
334 initialise_mog (segmentation);
341 gst_segmentation_stop (GstBaseTransform * basesrc)
343 GstSegmentation *filter = GST_SEGMENTATION (basesrc);
345 if (filter->cvRGBA != NULL)
346 gst_segmentation_release_all_pointers (filter);
352 gst_segmentation_release_all_pointers (GstSegmentation * filter)
354 cvReleaseImage (&filter->cvRGBA);
355 cvReleaseImage (&filter->cvRGB);
356 cvReleaseImage (&filter->cvYUV);
357 cvReleaseImage (&filter->cvFG);
358 cvReleaseImage (&filter->ch1);
359 cvReleaseImage (&filter->ch2);
360 cvReleaseImage (&filter->ch3);
362 cvReleaseMemStorage (&filter->mem_storage);
364 g_free (filter->TcodeBook);
365 finalise_mog (filter);
369 gst_segmentation_transform_ip (GstVideoFilter * btrans, GstVideoFrame * frame)
371 GstSegmentation *filter = GST_SEGMENTATION (btrans);
374 /* get image data from the input, which is RGBA */
375 filter->cvRGBA->imageData = (char *) GST_VIDEO_FRAME_COMP_DATA (frame, 0);
376 filter->cvRGBA->widthStep = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
377 filter->framecount++;
379 /* Image preprocessing: color space conversion etc */
380 cvCvtColor (filter->cvRGBA, filter->cvRGB, CV_RGBA2RGB);
381 cvCvtColor (filter->cvRGB, filter->cvYUV, CV_RGB2YCrCb);
383 /* Create and update a fg/bg model using a codebook approach following the
384 * opencv O'Reilly book [1] implementation of the algo described in [2].
386 * [1] Learning OpenCV: Computer Vision with the OpenCV Library by Gary
387 * Bradski and Adrian Kaehler, Published by O'Reilly Media, October 3, 2008
388 * [2] "Real-time Foreground-Background Segmentation using Codebook Model",
389 * Real-time Imaging, Volume 11, Issue 3, Pages 167-256, June 2005. */
390 if (METHOD_BOOK == filter->method) {
391 unsigned cbBounds[3] = { 10, 5, 5 };
392 int minMod[3] = { 20, 20, 20 }, maxMod[3] = {
395 if (filter->framecount < 30) {
396 /* Learning background phase: update_codebook on every frame */
397 for (j = 0; j < filter->width * filter->height; j++) {
398 update_codebook ((unsigned char *) filter->cvYUV->imageData + j * 3,
399 (codeBook *) & (filter->TcodeBook[j]), cbBounds, 3);
402 /* this updating is responsible for FG becoming BG again */
403 if (filter->framecount % filter->learning_interval == 0) {
404 for (j = 0; j < filter->width * filter->height; j++) {
405 update_codebook ((uchar *) filter->cvYUV->imageData + j * 3,
406 (codeBook *) & (filter->TcodeBook[j]), cbBounds, 3);
409 if (filter->framecount % 60 == 0) {
410 for (j = 0; j < filter->width * filter->height; j++)
411 clear_stale_entries ((codeBook *) & (filter->TcodeBook[j]));
414 for (j = 0; j < filter->width * filter->height; j++) {
416 ((uchar *) filter->cvYUV->imageData + j * 3,
417 (codeBook *) & (filter->TcodeBook[j]), 3, minMod, maxMod)) {
418 filter->cvFG->imageData[j] = 255;
420 filter->cvFG->imageData[j] = 0;
425 /* 3rd param is the smallest area to show: (w+h)/param , in pixels */
426 find_connected_components (filter->cvFG, 1, 10000,
427 filter->mem_storage, filter->contours);
430 /* Create the foreground and background masks using BackgroundSubtractorMOG [1],
431 * Gaussian Mixture-based Background/Foreground segmentation algorithm. OpenCV
432 * MOG implements the algorithm described in [2].
434 * [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
435 * [2] P. KadewTraKuPong and R. Bowden, "An improved adaptive background
436 * mixture model for real-time tracking with shadow detection", Proc. 2nd
437 * European Workshop on Advanced Video-Based Surveillance Systems, 2001
439 else if (METHOD_MOG == filter->method) {
440 run_mog_iteration (filter);
442 /* Create the foreground and background masks using BackgroundSubtractorMOG2
443 * [1], Gaussian Mixture-based Background/Foreground segmentation algorithm.
444 * OpenCV MOG2 implements the algorithm described in [2] and [3].
446 * [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
447 * [2] Z.Zivkovic, "Improved adaptive Gausian mixture model for background
448 * subtraction", International Conference Pattern Recognition, UK, Aug 2004.
449 * [3] Z.Zivkovic, F. van der Heijden, "Efficient Adaptive Density Estimation
450 * per Image Pixel for the Task of Background Subtraction", Pattern
451 * Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. */
452 else if (METHOD_MOG2 == filter->method) {
453 run_mog2_iteration (filter);
456 /* if we want to test_mode, just overwrite the output */
457 if (filter->test_mode) {
458 cvCvtColor (filter->cvFG, filter->cvRGB, CV_GRAY2RGB);
460 cvSplit (filter->cvRGB, filter->ch1, filter->ch2, filter->ch3, NULL);
462 cvSplit (filter->cvRGBA, filter->ch1, filter->ch2, filter->ch3, NULL);
464 /* copy anyhow the fg/bg to the alpha channel in the output image */
465 cvMerge (filter->ch1, filter->ch2, filter->ch3, filter->cvFG, filter->cvRGBA);
471 /* entry point to initialize the plug-in
472 * initialize the plug-in itself
473 * register the element factories and other features
476 gst_segmentation_plugin_init (GstPlugin * plugin)
478 GST_DEBUG_CATEGORY_INIT (gst_segmentation_debug, "segmentation",
479 0, "Performs Foreground/Background segmentation in video sequences");
481 return gst_element_register (plugin, "segmentation", GST_RANK_NONE,
482 GST_TYPE_SEGMENTATION);
487 #ifdef CODE_FROM_OREILLY_BOOK /* See license at the beginning of the page */
489 int update_codebook(uchar *p, codeBook &c, unsigned cbBounds)
490 Updates the codebook entry with a new data point
492 p Pointer to a YUV or HSI pixel
493 c Codebook for this pixel
494 cbBounds Learning bounds for codebook (Rule of thumb: 10)
495 numChannels Number of color channels we¡¯re learning
498 cvBounds must be of length equal to numChannels
504 update_codebook (unsigned char *p, codeBook * c, unsigned *cbBounds,
508 unsigned int high[3], low[3];
512 for (n = 0; n < numChannels; n++) {
513 high[n] = p[n] + cbBounds[n];
517 if (p[n] > cbBounds[n])
518 low[n] = p[n] - cbBounds[n];
523 /* SEE IF THIS FITS AN EXISTING CODEWORD */
524 for (i = 0; i < c->numEntries; i++) {
526 for (n = 0; n < numChannels; n++) {
527 if ((c->cb[i]->learnLow[n] <= *(p + n)) &&
528 /* Found an entry for this channel */
529 (*(p + n) <= c->cb[i]->learnHigh[n])) {
533 if (matchChannel == numChannels) { /* If an entry was found */
534 c->cb[i]->t_last_update = c->t;
535 /* adjust this codeword for the first channel */
536 for (n = 0; n < numChannels; n++) {
537 if (c->cb[i]->max[n] < *(p + n)) {
538 c->cb[i]->max[n] = *(p + n);
539 } else if (c->cb[i]->min[n] > *(p + n)) {
540 c->cb[i]->min[n] = *(p + n);
546 /* OVERHEAD TO TRACK POTENTIAL STALE ENTRIES */
547 for (int s = 0; s < c->numEntries; s++) {
548 /* Track which codebook entries are going stale: */
549 int negRun = c->t - c->cb[s]->t_last_update;
550 if (c->cb[s]->stale < negRun)
551 c->cb[s]->stale = negRun;
553 /* ENTER A NEW CODEWORD IF NEEDED */
554 if (i == c->numEntries) { /* if no existing codeword found, make one */
556 (code_element **) g_malloc (sizeof (code_element *) *
557 (c->numEntries + 1));
558 for (int ii = 0; ii < c->numEntries; ii++) {
559 foo[ii] = c->cb[ii]; /* copy all pointers */
561 foo[c->numEntries] = (code_element *) g_malloc (sizeof (code_element));
565 for (n = 0; n < numChannels; n++) {
566 c->cb[c->numEntries]->learnHigh[n] = high[n];
567 c->cb[c->numEntries]->learnLow[n] = low[n];
568 c->cb[c->numEntries]->max[n] = *(p + n);
569 c->cb[c->numEntries]->min[n] = *(p + n);
571 c->cb[c->numEntries]->t_last_update = c->t;
572 c->cb[c->numEntries]->stale = 0;
575 /* SLOWLY ADJUST LEARNING BOUNDS */
576 for (n = 0; n < numChannels; n++) {
577 if (c->cb[i]->learnHigh[n] < high[n])
578 c->cb[i]->learnHigh[n] += 1;
579 if (c->cb[i]->learnLow[n] > low[n])
580 c->cb[i]->learnLow[n] -= 1;
590 int clear_stale_entries(codeBook &c)
591 During learning, after you've learned for some period of time,
592 periodically call this to clear out stale codebook entries
594 c Codebook to clean up
597 number of entries cleared
600 clear_stale_entries (codeBook * c)
602 int staleThresh = c->t >> 1;
603 int *keep = (int *) g_malloc (sizeof (int) * (c->numEntries));
608 /* SEE WHICH CODEBOOK ENTRIES ARE TOO STALE */
609 for (int i = 0; i < c->numEntries; i++) {
610 if (c->cb[i]->stale > staleThresh)
611 keep[i] = 0; /* Mark for destruction */
613 keep[i] = 1; /* Mark to keep */
617 /* KEEP ONLY THE GOOD */
618 c->t = 0; /* Full reset on stale tracking */
619 foo = (code_element **) g_malloc (sizeof (code_element *) * keepCnt);
621 for (int ii = 0; ii < c->numEntries; ii++) {
624 /* We have to refresh these entries for next clearStale */
625 foo[k]->t_last_update = 0;
633 numCleared = c->numEntries - keepCnt;
634 c->numEntries = keepCnt;
641 uchar background_diff( uchar *p, codeBook &c,
642 int minMod, int maxMod)
643 Given a pixel and a codebook, determine if the pixel is
644 covered by the codebook
646 p Pixel pointer (YUV interleaved)
648 numChannels Number of channels we are testing
649 maxMod Add this (possibly negative) number onto
651 max level when determining if new pixel is foreground
652 minMod Subract this (possibly negative) number from
653 min level when determining if new pixel is foreground
656 minMod and maxMod must have length numChannels,
657 e.g. 3 channels => minMod[3], maxMod[3]. There is one min and
658 one max threshold per channel.
661 0 => background, 255 => foreground
664 background_diff (unsigned char *p, codeBook * c, int numChannels,
665 int *minMod, int *maxMod)
668 /* SEE IF THIS FITS AN EXISTING CODEWORD */
670 for (i = 0; i < c->numEntries; i++) {
672 for (int n = 0; n < numChannels; n++) {
673 if ((c->cb[i]->min[n] - minMod[n] <= *(p + n)) &&
674 (*(p + n) <= c->cb[i]->max[n] + maxMod[n])) {
675 matchChannel++; /* Found an entry for this channel */
680 if (matchChannel == numChannels) {
681 break; /* Found an entry that matched all channels */
684 if (i >= c->numEntries)
693 void find_connected_components(IplImage *mask, int poly1_hull0,
694 float perimScale, int *num,
695 CvRect *bbs, CvPoint *centers)
696 This cleans up the foreground segmentation mask derived from calls
699 mask Is a grayscale (8-bit depth) “rawâ€
\9d mask image that
703 poly1_hull0 If set, approximate connected component by
704 (DEFAULT) polygon, or else convex hull (0)
705 perimScale Len = image (width+height)/perimScale. If contour
706 len < this, delete that contour (DEFAULT: 4)
707 num Maximum number of rectangles and/or centers to
708 return; on return, will contain number filled
710 bbs Pointer to bounding box rectangle vector of
711 length num. (DEFAULT SETTING: NULL)
712 centers Pointer to contour centers vector of length
716 /* Approx.threshold - the bigger it is, the simpler is the boundary */
717 #define CVCONTOUR_APPROX_LEVEL 1
718 /* How many iterations of erosion and/or dilation there should be */
719 #define CVCLOSE_ITR 1
721 find_connected_components (IplImage * mask, int poly1_hull0, float perimScale,
722 CvMemStorage * mem_storage, CvSeq * contours)
724 CvContourScanner scanner;
727 /* Just some convenience variables */
728 const CvScalar CVX_WHITE = CV_RGB (0xff, 0xff, 0xff);
729 const CvScalar CVX_BLACK = CV_RGB (0x00, 0x00, 0x00);
731 /* CLEAN UP RAW MASK */
732 cvMorphologyEx (mask, mask, 0, 0, CV_MOP_OPEN, CVCLOSE_ITR);
733 cvMorphologyEx (mask, mask, 0, 0, CV_MOP_CLOSE, CVCLOSE_ITR);
734 /* FIND CONTOURS AROUND ONLY BIGGER REGIONS */
735 if (mem_storage == NULL) {
736 mem_storage = cvCreateMemStorage (0);
738 cvClearMemStorage (mem_storage);
741 scanner = cvStartFindContours (mask, mem_storage, sizeof (CvContour),
742 CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint (0, 0));
744 while ((c = cvFindNextContour (scanner)) != NULL) {
745 double len = cvContourArea (c, CV_WHOLE_SEQ, 0);
746 /* calculate perimeter len threshold: */
747 double q = (mask->height + mask->width) / perimScale;
748 /* Get rid of blob if its perimeter is too small: */
750 cvSubstituteContour (scanner, NULL);
752 /* Smooth its edges if its large enough */
755 /* Polygonal approximation */
757 cvApproxPoly (c, sizeof (CvContour), mem_storage, CV_POLY_APPROX_DP,
758 CVCONTOUR_APPROX_LEVEL, 0);
760 /* Convex Hull of the segmentation */
761 c_new = cvConvexHull2 (c, mem_storage, CV_CLOCKWISE, 1);
763 cvSubstituteContour (scanner, c_new);
767 contours = cvEndFindContours (&scanner);
769 /* PAINT THE FOUND REGIONS BACK INTO THE IMAGE */
771 /* DRAW PROCESSED CONTOURS INTO THE MASK */
772 for (c = contours; c != NULL; c = c->h_next)
773 cvDrawContours (mask, c, CVX_WHITE, CVX_BLACK, -1, CV_FILLED, 8, cvPoint (0,
776 #endif /*ifdef CODE_FROM_OREILLY_BOOK */
780 initialise_mog (GstSegmentation * filter)
782 filter->img_input_as_cvMat = (void *) new cv::Mat (filter->cvYUV, false);
783 filter->img_fg_as_cvMat = (void *) new cv::Mat (filter->cvFG, false);
785 filter->mog = (void *) new cv::BackgroundSubtractorMOG ();
786 filter->mog2 = (void *) new cv::BackgroundSubtractorMOG2 ();
792 run_mog_iteration (GstSegmentation * filter)
794 ((cv::Mat *) filter->img_input_as_cvMat)->data =
795 (uchar *) filter->cvYUV->imageData;
796 ((cv::Mat *) filter->img_fg_as_cvMat)->data =
797 (uchar *) filter->cvFG->imageData;
800 BackgroundSubtractorMOG [1], Gaussian Mixture-based Background/Foreground
801 Segmentation Algorithm. OpenCV MOG implements the algorithm described in [2].
803 [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
804 [2] P. KadewTraKuPong and R. Bowden, "An improved adaptive background
805 mixture model for real-time tracking with shadow detection", Proc. 2nd
806 European Workshop on Advanced Video-Based Surveillance Systems, 2001
809 (*((cv::BackgroundSubtractorMOG *) filter->mog)) (*((cv::Mat *) filter->
810 img_input_as_cvMat), *((cv::Mat *) filter->img_fg_as_cvMat),
811 filter->learning_rate);
817 run_mog2_iteration (GstSegmentation * filter)
819 ((cv::Mat *) filter->img_input_as_cvMat)->data =
820 (uchar *) filter->cvYUV->imageData;
821 ((cv::Mat *) filter->img_fg_as_cvMat)->data =
822 (uchar *) filter->cvFG->imageData;
825 BackgroundSubtractorMOG2 [1], Gaussian Mixture-based Background/Foreground
826 segmentation algorithm. OpenCV MOG2 implements the algorithm described in
829 [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
830 [2] Z.Zivkovic, "Improved adaptive Gausian mixture model for background
831 subtraction", International Conference Pattern Recognition, UK, August, 2004.
832 [3] Z.Zivkovic, F. van der Heijden, "Efficient Adaptive Density Estimation per
833 Image Pixel for the Task of Background Subtraction", Pattern Recognition
834 Letters, vol. 27, no. 7, pages 773-780, 2006.
837 (*((cv::BackgroundSubtractorMOG *) filter->mog2)) (*((cv::Mat *) filter->
838 img_input_as_cvMat), *((cv::Mat *) filter->img_fg_as_cvMat),
839 filter->learning_rate);
845 finalise_mog (GstSegmentation * filter)
847 delete (cv::Mat *) filter->img_input_as_cvMat;
848 delete (cv::Mat *) filter->img_fg_as_cvMat;
849 delete (cv::BackgroundSubtractorMOG *) filter->mog;
850 delete (cv::BackgroundSubtractorMOG2 *) filter->mog2;