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>
97 #include <opencv2/imgproc/imgproc_c.h>
99 GST_DEBUG_CATEGORY_STATIC (gst_segmentation_debug);
100 #define GST_CAT_DEFAULT gst_segmentation_debug
102 /* Filter signals and args */
121 } GstSegmentationMethod;
123 #define DEFAULT_TEST_MODE FALSE
124 #define DEFAULT_METHOD METHOD_MOG2
125 #define DEFAULT_LEARNING_RATE 0.01
127 #define GST_TYPE_SEGMENTATION_METHOD (gst_segmentation_method_get_type ())
129 gst_segmentation_method_get_type (void)
131 static GType etype = 0;
133 static const GEnumValue values[] = {
134 {METHOD_BOOK, "Codebook-based segmentation (Bradski2008)", "codebook"},
135 {METHOD_MOG, "Mixture-of-Gaussians segmentation (Bowden2001)", "mog"},
136 {METHOD_MOG2, "Mixture-of-Gaussians segmentation (Zivkovic2004)", "mog2"},
139 etype = g_enum_register_static ("GstSegmentationMethod", values);
144 G_DEFINE_TYPE (GstSegmentation, gst_segmentation, GST_TYPE_VIDEO_FILTER);
145 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
148 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGBA")));
150 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
153 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGBA")));
156 static void gst_segmentation_set_property (GObject * object, guint prop_id,
157 const GValue * value, GParamSpec * pspec);
158 static void gst_segmentation_get_property (GObject * object, guint prop_id,
159 GValue * value, GParamSpec * pspec);
161 static GstFlowReturn gst_segmentation_transform_ip (GstVideoFilter * btrans,
162 GstVideoFrame * frame);
164 static gboolean gst_segmentation_stop (GstBaseTransform * basesrc);
165 static gboolean gst_segmentation_set_info (GstVideoFilter * filter,
166 GstCaps * incaps, GstVideoInfo * in_info,
167 GstCaps * outcaps, GstVideoInfo * out_info);
168 static void gst_segmentation_release_all_pointers (GstSegmentation * filter);
170 /* Codebook algorithm + connected components functions*/
171 static int update_codebook (unsigned char *p, codeBook * c,
172 unsigned *cbBounds, int numChannels);
173 static int clear_stale_entries (codeBook * c);
174 static unsigned char background_diff (unsigned char *p, codeBook * c,
175 int numChannels, int *minMod, int *maxMod);
176 static void find_connected_components (IplImage * mask, int poly1_hull0,
177 float perimScale, CvMemStorage * mem_storage, CvSeq * contours);
179 /* MOG (Mixture-of-Gaussians functions */
180 static int initialise_mog (GstSegmentation * filter);
181 static int run_mog_iteration (GstSegmentation * filter);
182 static int run_mog2_iteration (GstSegmentation * filter);
183 static int finalise_mog (GstSegmentation * filter);
185 /* initialize the segmentation's class */
187 gst_segmentation_class_init (GstSegmentationClass * klass)
189 GObjectClass *gobject_class;
190 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
191 GstBaseTransformClass *basesrc_class = GST_BASE_TRANSFORM_CLASS (klass);
192 GstVideoFilterClass *video_class = (GstVideoFilterClass *) klass;
194 gobject_class = (GObjectClass *) klass;
196 gobject_class->set_property = gst_segmentation_set_property;
197 gobject_class->get_property = gst_segmentation_get_property;
199 basesrc_class->stop = gst_segmentation_stop;
201 video_class->transform_frame_ip = gst_segmentation_transform_ip;
202 video_class->set_info = gst_segmentation_set_info;
204 g_object_class_install_property (gobject_class, PROP_METHOD,
205 g_param_spec_enum ("method",
206 "Segmentation method to use",
207 "Segmentation method to use",
208 GST_TYPE_SEGMENTATION_METHOD, DEFAULT_METHOD,
209 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
211 g_object_class_install_property (gobject_class, PROP_TEST_MODE,
212 g_param_spec_boolean ("test-mode", "test-mode",
213 "If true, the output RGB is overwritten with the calculated foreground (white color)",
214 DEFAULT_TEST_MODE, (GParamFlags)
215 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
217 g_object_class_install_property (gobject_class, PROP_LEARNING_RATE,
218 g_param_spec_float ("learning-rate", "learning-rate",
219 "Speed with which a motionless foreground pixel would become background (inverse of number of frames)",
220 0, 1, DEFAULT_LEARNING_RATE, (GParamFlags) (G_PARAM_READWRITE)));
222 gst_element_class_set_static_metadata (element_class,
223 "Foreground/background video sequence segmentation",
224 "Filter/Effect/Video",
225 "Create a Foregound/Background mask applying a particular algorithm",
226 "Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>");
228 gst_element_class_add_pad_template (element_class,
229 gst_static_pad_template_get (&src_factory));
230 gst_element_class_add_pad_template (element_class,
231 gst_static_pad_template_get (&sink_factory));
235 /* initialize the new element
236 * instantiate pads and add them to element
237 * set pad calback functions
238 * initialize instance structure
241 gst_segmentation_init (GstSegmentation * filter)
243 filter->method = DEFAULT_METHOD;
244 filter->test_mode = DEFAULT_TEST_MODE;
245 filter->framecount = 0;
246 filter->learning_rate = DEFAULT_LEARNING_RATE;
247 gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
252 gst_segmentation_set_property (GObject * object, guint prop_id,
253 const GValue * value, GParamSpec * pspec)
255 GstSegmentation *filter = GST_SEGMENTATION (object);
259 filter->method = g_value_get_enum (value);
262 filter->test_mode = g_value_get_boolean (value);
264 case PROP_LEARNING_RATE:
265 filter->learning_rate = g_value_get_float (value);
268 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274 gst_segmentation_get_property (GObject * object, guint prop_id,
275 GValue * value, GParamSpec * pspec)
277 GstSegmentation *filter = GST_SEGMENTATION (object);
281 g_value_set_enum (value, filter->method);
284 g_value_set_boolean (value, filter->test_mode);
286 case PROP_LEARNING_RATE:
287 g_value_set_float (value, filter->learning_rate);
290 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
295 /* GstElement vmethod implementations */
296 /* this function handles the link with other elements */
298 gst_segmentation_set_info (GstVideoFilter * filter,
299 GstCaps * incaps, GstVideoInfo * in_info,
300 GstCaps * outcaps, GstVideoInfo * out_info)
302 GstSegmentation *segmentation = GST_SEGMENTATION (filter);
305 size = cvSize (in_info->width, in_info->height);
306 segmentation->width = in_info->width;
307 segmentation->height = in_info->height;
308 /* If cvRGB is already allocated, it means there's a cap modification, */
309 /* so release first all the images. */
310 if (NULL != segmentation->cvRGBA)
311 gst_segmentation_release_all_pointers (segmentation);
313 segmentation->cvRGBA = cvCreateImageHeader (size, IPL_DEPTH_8U, 4);
315 segmentation->cvRGB = cvCreateImage (size, IPL_DEPTH_8U, 3);
316 segmentation->cvYUV = cvCreateImage (size, IPL_DEPTH_8U, 3);
318 segmentation->cvFG = cvCreateImage (size, IPL_DEPTH_8U, 1);
319 cvZero (segmentation->cvFG);
321 segmentation->ch1 = cvCreateImage (size, IPL_DEPTH_8U, 1);
322 segmentation->ch2 = cvCreateImage (size, IPL_DEPTH_8U, 1);
323 segmentation->ch3 = cvCreateImage (size, IPL_DEPTH_8U, 1);
325 /* Codebook method */
326 segmentation->TcodeBook = (codeBook *)
327 g_malloc (sizeof (codeBook) *
328 (segmentation->width * segmentation->height + 1));
329 for (int j = 0; j < segmentation->width * segmentation->height; j++) {
330 segmentation->TcodeBook[j].numEntries = 0;
331 segmentation->TcodeBook[j].t = 0;
333 segmentation->learning_interval = (int) (1.0 / segmentation->learning_rate);
335 /* Mixture-of-Gaussians (mog) methods */
336 initialise_mog (segmentation);
343 gst_segmentation_stop (GstBaseTransform * basesrc)
345 GstSegmentation *filter = GST_SEGMENTATION (basesrc);
347 if (filter->cvRGBA != NULL)
348 gst_segmentation_release_all_pointers (filter);
354 gst_segmentation_release_all_pointers (GstSegmentation * filter)
356 cvReleaseImage (&filter->cvRGBA);
357 cvReleaseImage (&filter->cvRGB);
358 cvReleaseImage (&filter->cvYUV);
359 cvReleaseImage (&filter->cvFG);
360 cvReleaseImage (&filter->ch1);
361 cvReleaseImage (&filter->ch2);
362 cvReleaseImage (&filter->ch3);
364 cvReleaseMemStorage (&filter->mem_storage);
366 g_free (filter->TcodeBook);
367 finalise_mog (filter);
371 gst_segmentation_transform_ip (GstVideoFilter * btrans, GstVideoFrame * frame)
373 GstSegmentation *filter = GST_SEGMENTATION (btrans);
376 /* get image data from the input, which is RGBA */
377 filter->cvRGBA->imageData = (char *) GST_VIDEO_FRAME_COMP_DATA (frame, 0);
378 filter->cvRGBA->widthStep = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
379 filter->framecount++;
381 /* Image preprocessing: color space conversion etc */
382 cvCvtColor (filter->cvRGBA, filter->cvRGB, CV_RGBA2RGB);
383 cvCvtColor (filter->cvRGB, filter->cvYUV, CV_RGB2YCrCb);
385 /* Create and update a fg/bg model using a codebook approach following the
386 * opencv O'Reilly book [1] implementation of the algo described in [2].
388 * [1] Learning OpenCV: Computer Vision with the OpenCV Library by Gary
389 * Bradski and Adrian Kaehler, Published by O'Reilly Media, October 3, 2008
390 * [2] "Real-time Foreground-Background Segmentation using Codebook Model",
391 * Real-time Imaging, Volume 11, Issue 3, Pages 167-256, June 2005. */
392 if (METHOD_BOOK == filter->method) {
393 unsigned cbBounds[3] = { 10, 5, 5 };
394 int minMod[3] = { 20, 20, 20 }, maxMod[3] = {
397 if (filter->framecount < 30) {
398 /* Learning background phase: update_codebook on every frame */
399 for (j = 0; j < filter->width * filter->height; j++) {
400 update_codebook ((unsigned char *) filter->cvYUV->imageData + j * 3,
401 (codeBook *) & (filter->TcodeBook[j]), cbBounds, 3);
404 /* this updating is responsible for FG becoming BG again */
405 if (filter->framecount % filter->learning_interval == 0) {
406 for (j = 0; j < filter->width * filter->height; j++) {
407 update_codebook ((uchar *) filter->cvYUV->imageData + j * 3,
408 (codeBook *) & (filter->TcodeBook[j]), cbBounds, 3);
411 if (filter->framecount % 60 == 0) {
412 for (j = 0; j < filter->width * filter->height; j++)
413 clear_stale_entries ((codeBook *) & (filter->TcodeBook[j]));
416 for (j = 0; j < filter->width * filter->height; j++) {
418 ((uchar *) filter->cvYUV->imageData + j * 3,
419 (codeBook *) & (filter->TcodeBook[j]), 3, minMod, maxMod)) {
420 filter->cvFG->imageData[j] = 255;
422 filter->cvFG->imageData[j] = 0;
427 /* 3rd param is the smallest area to show: (w+h)/param , in pixels */
428 find_connected_components (filter->cvFG, 1, 10000,
429 filter->mem_storage, filter->contours);
432 /* Create the foreground and background masks using BackgroundSubtractorMOG [1],
433 * Gaussian Mixture-based Background/Foreground segmentation algorithm. OpenCV
434 * MOG implements the algorithm described in [2].
436 * [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
437 * [2] P. KadewTraKuPong and R. Bowden, "An improved adaptive background
438 * mixture model for real-time tracking with shadow detection", Proc. 2nd
439 * European Workshop on Advanced Video-Based Surveillance Systems, 2001
441 else if (METHOD_MOG == filter->method) {
442 run_mog_iteration (filter);
444 /* Create the foreground and background masks using BackgroundSubtractorMOG2
445 * [1], Gaussian Mixture-based Background/Foreground segmentation algorithm.
446 * OpenCV MOG2 implements the algorithm described in [2] and [3].
448 * [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
449 * [2] Z.Zivkovic, "Improved adaptive Gausian mixture model for background
450 * subtraction", International Conference Pattern Recognition, UK, Aug 2004.
451 * [3] Z.Zivkovic, F. van der Heijden, "Efficient Adaptive Density Estimation
452 * per Image Pixel for the Task of Background Subtraction", Pattern
453 * Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. */
454 else if (METHOD_MOG2 == filter->method) {
455 run_mog2_iteration (filter);
458 /* if we want to test_mode, just overwrite the output */
459 if (filter->test_mode) {
460 cvCvtColor (filter->cvFG, filter->cvRGB, CV_GRAY2RGB);
462 cvSplit (filter->cvRGB, filter->ch1, filter->ch2, filter->ch3, NULL);
464 cvSplit (filter->cvRGBA, filter->ch1, filter->ch2, filter->ch3, NULL);
466 /* copy anyhow the fg/bg to the alpha channel in the output image */
467 cvMerge (filter->ch1, filter->ch2, filter->ch3, filter->cvFG, filter->cvRGBA);
473 /* entry point to initialize the plug-in
474 * initialize the plug-in itself
475 * register the element factories and other features
478 gst_segmentation_plugin_init (GstPlugin * plugin)
480 GST_DEBUG_CATEGORY_INIT (gst_segmentation_debug, "segmentation",
481 0, "Performs Foreground/Background segmentation in video sequences");
483 return gst_element_register (plugin, "segmentation", GST_RANK_NONE,
484 GST_TYPE_SEGMENTATION);
489 #ifdef CODE_FROM_OREILLY_BOOK /* See license at the beginning of the page */
491 int update_codebook(uchar *p, codeBook &c, unsigned cbBounds)
492 Updates the codebook entry with a new data point
494 p Pointer to a YUV or HSI pixel
495 c Codebook for this pixel
496 cbBounds Learning bounds for codebook (Rule of thumb: 10)
497 numChannels Number of color channels we¡¯re learning
500 cvBounds must be of length equal to numChannels
506 update_codebook (unsigned char *p, codeBook * c, unsigned *cbBounds,
510 unsigned int high[3], low[3];
514 for (n = 0; n < numChannels; n++) {
515 high[n] = p[n] + cbBounds[n];
519 if (p[n] > cbBounds[n])
520 low[n] = p[n] - cbBounds[n];
525 /* SEE IF THIS FITS AN EXISTING CODEWORD */
526 for (i = 0; i < c->numEntries; i++) {
528 for (n = 0; n < numChannels; n++) {
529 if ((c->cb[i]->learnLow[n] <= *(p + n)) &&
530 /* Found an entry for this channel */
531 (*(p + n) <= c->cb[i]->learnHigh[n])) {
535 if (matchChannel == numChannels) { /* If an entry was found */
536 c->cb[i]->t_last_update = c->t;
537 /* adjust this codeword for the first channel */
538 for (n = 0; n < numChannels; n++) {
539 if (c->cb[i]->max[n] < *(p + n)) {
540 c->cb[i]->max[n] = *(p + n);
541 } else if (c->cb[i]->min[n] > *(p + n)) {
542 c->cb[i]->min[n] = *(p + n);
548 /* OVERHEAD TO TRACK POTENTIAL STALE ENTRIES */
549 for (int s = 0; s < c->numEntries; s++) {
550 /* Track which codebook entries are going stale: */
551 int negRun = c->t - c->cb[s]->t_last_update;
552 if (c->cb[s]->stale < negRun)
553 c->cb[s]->stale = negRun;
555 /* ENTER A NEW CODEWORD IF NEEDED */
556 if (i == c->numEntries) { /* if no existing codeword found, make one */
558 (code_element **) g_malloc (sizeof (code_element *) *
559 (c->numEntries + 1));
560 for (int ii = 0; ii < c->numEntries; ii++) {
561 foo[ii] = c->cb[ii]; /* copy all pointers */
563 foo[c->numEntries] = (code_element *) g_malloc (sizeof (code_element));
567 for (n = 0; n < numChannels; n++) {
568 c->cb[c->numEntries]->learnHigh[n] = high[n];
569 c->cb[c->numEntries]->learnLow[n] = low[n];
570 c->cb[c->numEntries]->max[n] = *(p + n);
571 c->cb[c->numEntries]->min[n] = *(p + n);
573 c->cb[c->numEntries]->t_last_update = c->t;
574 c->cb[c->numEntries]->stale = 0;
577 /* SLOWLY ADJUST LEARNING BOUNDS */
578 for (n = 0; n < numChannels; n++) {
579 if (c->cb[i]->learnHigh[n] < high[n])
580 c->cb[i]->learnHigh[n] += 1;
581 if (c->cb[i]->learnLow[n] > low[n])
582 c->cb[i]->learnLow[n] -= 1;
592 int clear_stale_entries(codeBook &c)
593 During learning, after you've learned for some period of time,
594 periodically call this to clear out stale codebook entries
596 c Codebook to clean up
599 number of entries cleared
602 clear_stale_entries (codeBook * c)
604 int staleThresh = c->t >> 1;
605 int *keep = (int *) g_malloc (sizeof (int) * (c->numEntries));
610 /* SEE WHICH CODEBOOK ENTRIES ARE TOO STALE */
611 for (int i = 0; i < c->numEntries; i++) {
612 if (c->cb[i]->stale > staleThresh)
613 keep[i] = 0; /* Mark for destruction */
615 keep[i] = 1; /* Mark to keep */
619 /* KEEP ONLY THE GOOD */
620 c->t = 0; /* Full reset on stale tracking */
621 foo = (code_element **) g_malloc (sizeof (code_element *) * keepCnt);
623 for (int ii = 0; ii < c->numEntries; ii++) {
626 /* We have to refresh these entries for next clearStale */
627 foo[k]->t_last_update = 0;
635 numCleared = c->numEntries - keepCnt;
636 c->numEntries = keepCnt;
643 uchar background_diff( uchar *p, codeBook &c,
644 int minMod, int maxMod)
645 Given a pixel and a codebook, determine if the pixel is
646 covered by the codebook
648 p Pixel pointer (YUV interleaved)
650 numChannels Number of channels we are testing
651 maxMod Add this (possibly negative) number onto
653 max level when determining if new pixel is foreground
654 minMod Subract this (possibly negative) number from
655 min level when determining if new pixel is foreground
658 minMod and maxMod must have length numChannels,
659 e.g. 3 channels => minMod[3], maxMod[3]. There is one min and
660 one max threshold per channel.
663 0 => background, 255 => foreground
666 background_diff (unsigned char *p, codeBook * c, int numChannels,
667 int *minMod, int *maxMod)
670 /* SEE IF THIS FITS AN EXISTING CODEWORD */
672 for (i = 0; i < c->numEntries; i++) {
674 for (int n = 0; n < numChannels; n++) {
675 if ((c->cb[i]->min[n] - minMod[n] <= *(p + n)) &&
676 (*(p + n) <= c->cb[i]->max[n] + maxMod[n])) {
677 matchChannel++; /* Found an entry for this channel */
682 if (matchChannel == numChannels) {
683 break; /* Found an entry that matched all channels */
686 if (i >= c->numEntries)
695 void find_connected_components(IplImage *mask, int poly1_hull0,
696 float perimScale, int *num,
697 CvRect *bbs, CvPoint *centers)
698 This cleans up the foreground segmentation mask derived from calls
701 mask Is a grayscale (8-bit depth) “rawâ€
\9d mask image that
705 poly1_hull0 If set, approximate connected component by
706 (DEFAULT) polygon, or else convex hull (0)
707 perimScale Len = image (width+height)/perimScale. If contour
708 len < this, delete that contour (DEFAULT: 4)
709 num Maximum number of rectangles and/or centers to
710 return; on return, will contain number filled
712 bbs Pointer to bounding box rectangle vector of
713 length num. (DEFAULT SETTING: NULL)
714 centers Pointer to contour centers vector of length
718 /* Approx.threshold - the bigger it is, the simpler is the boundary */
719 #define CVCONTOUR_APPROX_LEVEL 1
720 /* How many iterations of erosion and/or dilation there should be */
721 #define CVCLOSE_ITR 1
723 find_connected_components (IplImage * mask, int poly1_hull0, float perimScale,
724 CvMemStorage * mem_storage, CvSeq * contours)
726 CvContourScanner scanner;
729 /* Just some convenience variables */
730 const CvScalar CVX_WHITE = CV_RGB (0xff, 0xff, 0xff);
731 const CvScalar CVX_BLACK = CV_RGB (0x00, 0x00, 0x00);
733 /* CLEAN UP RAW MASK */
734 cvMorphologyEx (mask, mask, 0, 0, CV_MOP_OPEN, CVCLOSE_ITR);
735 cvMorphologyEx (mask, mask, 0, 0, CV_MOP_CLOSE, CVCLOSE_ITR);
736 /* FIND CONTOURS AROUND ONLY BIGGER REGIONS */
737 if (mem_storage == NULL) {
738 mem_storage = cvCreateMemStorage (0);
740 cvClearMemStorage (mem_storage);
743 scanner = cvStartFindContours (mask, mem_storage, sizeof (CvContour),
744 CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint (0, 0));
746 while ((c = cvFindNextContour (scanner)) != NULL) {
747 double len = cvContourArea (c, CV_WHOLE_SEQ, 0);
748 /* calculate perimeter len threshold: */
749 double q = (mask->height + mask->width) / perimScale;
750 /* Get rid of blob if its perimeter is too small: */
752 cvSubstituteContour (scanner, NULL);
754 /* Smooth its edges if its large enough */
757 /* Polygonal approximation */
759 cvApproxPoly (c, sizeof (CvContour), mem_storage, CV_POLY_APPROX_DP,
760 CVCONTOUR_APPROX_LEVEL, 0);
762 /* Convex Hull of the segmentation */
763 c_new = cvConvexHull2 (c, mem_storage, CV_CLOCKWISE, 1);
765 cvSubstituteContour (scanner, c_new);
769 contours = cvEndFindContours (&scanner);
771 /* PAINT THE FOUND REGIONS BACK INTO THE IMAGE */
773 /* DRAW PROCESSED CONTOURS INTO THE MASK */
774 for (c = contours; c != NULL; c = c->h_next)
775 cvDrawContours (mask, c, CVX_WHITE, CVX_BLACK, -1, CV_FILLED, 8, cvPoint (0,
778 #endif /*ifdef CODE_FROM_OREILLY_BOOK */
782 initialise_mog (GstSegmentation * filter)
784 filter->img_input_as_cvMat = (void *) new cv::Mat (filter->cvYUV, false);
785 filter->img_fg_as_cvMat = (void *) new cv::Mat (filter->cvFG, false);
787 filter->mog = (void *) new cv::BackgroundSubtractorMOG ();
788 filter->mog2 = (void *) new cv::BackgroundSubtractorMOG2 ();
794 run_mog_iteration (GstSegmentation * filter)
796 ((cv::Mat *) filter->img_input_as_cvMat)->data =
797 (uchar *) filter->cvYUV->imageData;
798 ((cv::Mat *) filter->img_fg_as_cvMat)->data =
799 (uchar *) filter->cvFG->imageData;
802 BackgroundSubtractorMOG [1], Gaussian Mixture-based Background/Foreground
803 Segmentation Algorithm. OpenCV MOG implements the algorithm described in [2].
805 [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
806 [2] P. KadewTraKuPong and R. Bowden, "An improved adaptive background
807 mixture model for real-time tracking with shadow detection", Proc. 2nd
808 European Workshop on Advanced Video-Based Surveillance Systems, 2001
811 (*((cv::BackgroundSubtractorMOG *) filter->mog)) (*((cv::Mat *) filter->
812 img_input_as_cvMat), *((cv::Mat *) filter->img_fg_as_cvMat),
813 filter->learning_rate);
819 run_mog2_iteration (GstSegmentation * filter)
821 ((cv::Mat *) filter->img_input_as_cvMat)->data =
822 (uchar *) filter->cvYUV->imageData;
823 ((cv::Mat *) filter->img_fg_as_cvMat)->data =
824 (uchar *) filter->cvFG->imageData;
827 BackgroundSubtractorMOG2 [1], Gaussian Mixture-based Background/Foreground
828 segmentation algorithm. OpenCV MOG2 implements the algorithm described in
831 [1] http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
832 [2] Z.Zivkovic, "Improved adaptive Gausian mixture model for background
833 subtraction", International Conference Pattern Recognition, UK, August, 2004.
834 [3] Z.Zivkovic, F. van der Heijden, "Efficient Adaptive Density Estimation per
835 Image Pixel for the Task of Background Subtraction", Pattern Recognition
836 Letters, vol. 27, no. 7, pages 773-780, 2006.
839 (*((cv::BackgroundSubtractorMOG *) filter->mog2)) (*((cv::Mat *) filter->
840 img_input_as_cvMat), *((cv::Mat *) filter->img_fg_as_cvMat),
841 filter->learning_rate);
847 finalise_mog (GstSegmentation * filter)
849 delete (cv::Mat *) filter->img_input_as_cvMat;
850 delete (cv::Mat *) filter->img_fg_as_cvMat;
851 delete (cv::BackgroundSubtractorMOG *) filter->mog;
852 delete (cv::BackgroundSubtractorMOG2 *) filter->mog2;