Commit c42d61e4 authored by Roman Donchenko's avatar Roman Donchenko Committed by OpenCV Buildbot

Merge pull request #1283 from melody-rain:new_mog_mog2

parents b3e73cf7 114f3266
......@@ -1698,6 +1698,155 @@ namespace cv
// keys = {1, 2, 3} (CV_8UC1)
// values = {6,2, 10,5, 4,3} (CV_8UC2)
void CV_EXPORTS sortByKey(oclMat& keys, oclMat& values, int method, bool isGreaterThan = false);
/*!Base class for MOG and MOG2!*/
class CV_EXPORTS BackgroundSubtractor
{
public:
//! the virtual destructor
virtual ~BackgroundSubtractor();
//! the update operator that takes the next video frame and returns the current foreground mask as 8-bit binary image.
virtual void operator()(const oclMat& image, oclMat& fgmask, float learningRate);
//! computes a background image
virtual void getBackgroundImage(oclMat& backgroundImage) const = 0;
};
/*!
Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm
The class implements the following algorithm:
"An improved adaptive background mixture model for real-time tracking with shadow detection"
P. KadewTraKuPong and R. Bowden,
Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001."
http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
*/
class CV_EXPORTS MOG: public cv::ocl::BackgroundSubtractor
{
public:
//! the default constructor
MOG(int nmixtures = -1);
//! re-initiaization method
void initialize(Size frameSize, int frameType);
//! the update operator
void operator()(const oclMat& frame, oclMat& fgmask, float learningRate = 0.f);
//! computes a background image which are the mean of all background gaussians
void getBackgroundImage(oclMat& backgroundImage) const;
//! releases all inner buffers
void release();
int history;
float varThreshold;
float backgroundRatio;
float noiseSigma;
private:
int nmixtures_;
Size frameSize_;
int frameType_;
int nframes_;
oclMat weight_;
oclMat sortKey_;
oclMat mean_;
oclMat var_;
};
/*!
The class implements the following algorithm:
"Improved adaptive Gausian mixture model for background subtraction"
Z.Zivkovic
International Conference Pattern Recognition, UK, August, 2004.
http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
*/
class CV_EXPORTS MOG2: public cv::ocl::BackgroundSubtractor
{
public:
//! the default constructor
MOG2(int nmixtures = -1);
//! re-initiaization method
void initialize(Size frameSize, int frameType);
//! the update operator
void operator()(const oclMat& frame, oclMat& fgmask, float learningRate = -1.0f);
//! computes a background image which are the mean of all background gaussians
void getBackgroundImage(oclMat& backgroundImage) const;
//! releases all inner buffers
void release();
// parameters
// you should call initialize after parameters changes
int history;
//! here it is the maximum allowed number of mixture components.
//! Actual number is determined dynamically per pixel
float varThreshold;
// threshold on the squared Mahalanobis distance to decide if it is well described
// by the background model or not. Related to Cthr from the paper.
// This does not influence the update of the background. A typical value could be 4 sigma
// and that is varThreshold=4*4=16; Corresponds to Tb in the paper.
/////////////////////////
// less important parameters - things you might change but be carefull
////////////////////////
float backgroundRatio;
// corresponds to fTB=1-cf from the paper
// TB - threshold when the component becomes significant enough to be included into
// the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
// For alpha=0.001 it means that the mode should exist for approximately 105 frames before
// it is considered foreground
// float noiseSigma;
float varThresholdGen;
//correspondts to Tg - threshold on the squared Mahalan. dist. to decide
//when a sample is close to the existing components. If it is not close
//to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
//Smaller Tg leads to more generated components and higher Tg might make
//lead to small number of components but they can grow too large
float fVarInit;
float fVarMin;
float fVarMax;
//initial variance for the newly generated components.
//It will will influence the speed of adaptation. A good guess should be made.
//A simple way is to estimate the typical standard deviation from the images.
//I used here 10 as a reasonable value
// min and max can be used to further control the variance
float fCT; //CT - complexity reduction prior
//this is related to the number of samples needed to accept that a component
//actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
//the standard Stauffer&Grimson algorithm (maybe not exact but very similar)
//shadow detection parameters
bool bShadowDetection; //default 1 - do shadow detection
unsigned char nShadowDetection; //do shadow detection - insert this value as the detection result - 127 default value
float fTau;
// Tau - shadow threshold. The shadow is detected if the pixel is darker
//version of the background. Tau is a threshold on how much darker the shadow can be.
//Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
//See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
private:
int nmixtures_;
Size frameSize_;
int frameType_;
int nframes_;
oclMat weight_;
oclMat variance_;
oclMat mean_;
oclMat bgmodelUsedModes_; //keep track of number of modes per pixel
};
}
}
#if defined _MSC_VER && _MSC_VER >= 1200
......
This diff is collapsed.
This diff is collapsed.
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2013, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Jin Ma, jin@multicorewareinc.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other oclMaterials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_OPENCL
using namespace cv;
using namespace cv::ocl;
using namespace cvtest;
using namespace testing;
using namespace std;
extern string workdir;
//////////////////////////////////////////////////////
// MOG
namespace
{
IMPLEMENT_PARAM_CLASS(UseGray, bool)
IMPLEMENT_PARAM_CLASS(LearningRate, double)
}
PARAM_TEST_CASE(mog, UseGray, LearningRate, bool)
{
bool useGray;
double learningRate;
bool useRoi;
virtual void SetUp()
{
useGray = GET_PARAM(0);
learningRate = GET_PARAM(1);
useRoi = GET_PARAM(2);
}
};
TEST_P(mog, Update)
{
std::string inputFile = string(cvtest::TS::ptr()->get_data_path()) + "gpu/768x576.avi";
cv::VideoCapture cap(inputFile);
ASSERT_TRUE(cap.isOpened());
cv::Mat frame;
cap >> frame;
ASSERT_FALSE(frame.empty());
cv::ocl::MOG mog;
cv::ocl::oclMat foreground = createMat_ocl(frame.size(), CV_8UC1, useRoi);
cv::BackgroundSubtractorMOG mog_gold;
cv::Mat foreground_gold;
for (int i = 0; i < 10; ++i)
{
cap >> frame;
ASSERT_FALSE(frame.empty());
if (useGray)
{
cv::Mat temp;
cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY);
cv::swap(temp, frame);
}
mog(loadMat_ocl(frame, useRoi), foreground, (float)learningRate);
mog_gold(frame, foreground_gold, learningRate);
EXPECT_MAT_NEAR(foreground_gold, foreground, 0.0);
}
}
INSTANTIATE_TEST_CASE_P(OCL_Video, mog, testing::Combine(
testing::Values(UseGray(false), UseGray(true)),
testing::Values(LearningRate(0.0), LearningRate(0.01)),
Values(true, false)));
//////////////////////////////////////////////////////
// MOG2
namespace
{
IMPLEMENT_PARAM_CLASS(DetectShadow, bool)
}
PARAM_TEST_CASE(mog2, UseGray, DetectShadow, bool)
{
bool useGray;
bool detectShadow;
bool useRoi;
virtual void SetUp()
{
useGray = GET_PARAM(0);
detectShadow = GET_PARAM(1);
useRoi = GET_PARAM(2);
}
};
TEST_P(mog2, Update)
{
std::string inputFile = string(cvtest::TS::ptr()->get_data_path()) + "gpu/768x576.avi";
cv::VideoCapture cap(inputFile);
ASSERT_TRUE(cap.isOpened());
cv::Mat frame;
cap >> frame;
ASSERT_FALSE(frame.empty());
cv::ocl::MOG2 mog2;
mog2.bShadowDetection = detectShadow;
cv::ocl::oclMat foreground = createMat_ocl(frame.size(), CV_8UC1, useRoi);
cv::BackgroundSubtractorMOG2 mog2_gold;
mog2_gold.set("detectShadows", detectShadow);
cv::Mat foreground_gold;
for (int i = 0; i < 10; ++i)
{
cap >> frame;
ASSERT_FALSE(frame.empty());
if (useGray)
{
cv::Mat temp;
cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY);
cv::swap(temp, frame);
}
mog2(loadMat_ocl(frame, useRoi), foreground);
mog2_gold(frame, foreground_gold);
if (detectShadow)
{
EXPECT_MAT_SIMILAR(foreground_gold, foreground, 1e-2);
}
else
{
EXPECT_MAT_NEAR(foreground_gold, foreground, 0);
}
}
}
TEST_P(mog2, getBackgroundImage)
{
if (useGray)
return;
std::string inputFile = string(cvtest::TS::ptr()->get_data_path()) + "video/768x576.avi";
cv::VideoCapture cap(inputFile);
ASSERT_TRUE(cap.isOpened());
cv::Mat frame;
cv::ocl::MOG2 mog2;
mog2.bShadowDetection = detectShadow;
cv::ocl::oclMat foreground;
cv::BackgroundSubtractorMOG2 mog2_gold;
mog2_gold.set("detectShadows", detectShadow);
cv::Mat foreground_gold;
for (int i = 0; i < 10; ++i)
{
cap >> frame;
ASSERT_FALSE(frame.empty());
mog2(loadMat_ocl(frame, useRoi), foreground);
mog2_gold(frame, foreground_gold);
}
cv::ocl::oclMat background = createMat_ocl(frame.size(), frame.type(), useRoi);
mog2.getBackgroundImage(background);
cv::Mat background_gold;
mog2_gold.getBackgroundImage(background_gold);
EXPECT_MAT_NEAR(background_gold, background, 1.0);
}
INSTANTIATE_TEST_CASE_P(OCL_Video, mog2, testing::Combine(
testing::Values(UseGray(true), UseGray(false)),
testing::Values(DetectShadow(true), DetectShadow(false)),
Values(true, false)));
#endif
\ No newline at end of file
......@@ -146,10 +146,10 @@ PARAM_TEST_CASE(TVL1, bool)
TEST_P(TVL1, Accuracy)
{
cv::Mat frame0 = readImage("gpu/opticalflow/rubberwhale1.png", cv::IMREAD_GRAYSCALE);
cv::Mat frame0 = readImage("F:/mcw/opencv/opencv/samples/gpu/rubberwhale1.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame0.empty());
cv::Mat frame1 = readImage("gpu/opticalflow/rubberwhale2.png", cv::IMREAD_GRAYSCALE);
cv::Mat frame1 = readImage("../../../opencv/samples/gpu/rubberwhale2.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame1.empty());
cv::ocl::OpticalFlowDual_TVL1_OCL d_alg;
......@@ -168,7 +168,7 @@ TEST_P(TVL1, Accuracy)
EXPECT_MAT_SIMILAR(gold[0], d_flowx, 3e-3);
EXPECT_MAT_SIMILAR(gold[1], d_flowy, 3e-3);
}
INSTANTIATE_TEST_CASE_P(OCL_Video, TVL1, Values(true, false));
INSTANTIATE_TEST_CASE_P(OCL_Video, TVL1, Values(false, true));
/////////////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -100,6 +100,44 @@ Mat randomMat(Size size, int type, double minVal, double maxVal)
return randomMat(TS::ptr()->get_rng(), size, type, minVal, maxVal, false);
}
cv::ocl::oclMat createMat_ocl(Size size, int type, bool useRoi)
{
Size size0 = size;
if (useRoi)
{
size0.width += randomInt(5, 15);
size0.height += randomInt(5, 15);
}
cv::ocl::oclMat d_m(size0, type);
if (size0 != size)
d_m = d_m(Rect((size0.width - size.width) / 2, (size0.height - size.height) / 2, size.width, size.height));
return d_m;
}
cv::ocl::oclMat loadMat_ocl(const Mat& m, bool useRoi)
{
CV_Assert(m.type() == CV_8UC1 || m.type() == CV_8UC3);
cv::ocl::oclMat d_m;
d_m = createMat_ocl(m.size(), m.type(), useRoi);
Size ls;
Point pt;
d_m.locateROI(ls, pt);
Rect roi(pt.x, pt.y, d_m.size().width, d_m.size().height);
cv::ocl::oclMat m_ocl(m);
cv::ocl::oclMat d_m_roi(d_m, roi);
m_ocl.copyTo(d_m);
return d_m;
}
/*
void showDiff(InputArray gold_, InputArray actual_, double eps)
{
......
......@@ -70,6 +70,9 @@ double checkNorm(const cv::Mat &m);
double checkNorm(const cv::Mat &m1, const cv::Mat &m2);
double checkSimilarity(const cv::Mat &m1, const cv::Mat &m2);
//oclMat create
cv::ocl::oclMat createMat_ocl(cv::Size size, int type, bool useRoi = false);
cv::ocl::oclMat loadMat_ocl(const cv::Mat& m, bool useRoi = false);
#define EXPECT_MAT_NORM(mat, eps) \
{ \
EXPECT_LE(checkNorm(cv::Mat(mat)), eps) \
......
#include <iostream>
#include <string>
#include "opencv2/core/core.hpp"
#include "opencv2/ocl/ocl.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
using namespace cv::ocl;
#define M_MOG 1
#define M_MOG2 2
int main(int argc, const char** argv)
{
cv::CommandLineParser cmd(argc, argv,
"{ c | camera | false | use camera }"
"{ f | file | 768x576.avi | input video file }"
"{ m | method | mog | method (mog, mog2) }"
"{ h | help | false | print help message }");
if (cmd.get<bool>("help"))
{
cout << "Usage : bgfg_segm [options]" << endl;
cout << "Avaible options:" << endl;
cmd.printParams();
return 0;
}
bool useCamera = cmd.get<bool>("camera");
string file = cmd.get<string>("file");
string method = cmd.get<string>("method");
if (method != "mog" && method != "mog2")
{
cerr << "Incorrect method" << endl;
return -1;
}
int m = method == "mog" ? M_MOG : M_MOG2;
VideoCapture cap;
if (useCamera)
cap.open(0);
else
cap.open(file);
if (!cap.isOpened())
{
cerr << "can not open camera or video file" << endl;
return -1;
}
std::vector<cv::ocl::Info>info;
cv::ocl::getDevice(info);
Mat frame;
cap >> frame;
oclMat d_frame(frame);
cv::ocl::MOG mog;
cv::ocl::MOG2 mog2;
oclMat d_fgmask;
oclMat d_fgimg;
oclMat d_bgimg;
d_fgimg.create(d_frame.size(), d_frame.type());
Mat fgmask;
Mat fgimg;
Mat bgimg;
switch (m)
{
case M_MOG:
mog(d_frame, d_fgmask, 0.01f);
break;
case M_MOG2:
mog2(d_frame, d_fgmask);
break;
}
for(;;)
{
cap >> frame;
if (frame.empty())
break;
d_frame.upload(frame);
int64 start = cv::getTickCount();
//update the model
switch (m)
{
case M_MOG:
mog(d_frame, d_fgmask, 0.01f);
mog.getBackgroundImage(d_bgimg);
break;
case M_MOG2:
mog2(d_frame, d_fgmask);
mog2.getBackgroundImage(d_bgimg);
break;
}
double fps = cv::getTickFrequency() / (cv::getTickCount() - start);
std::cout << "FPS : " << fps << std::endl;
d_fgimg.setTo(Scalar::all(0));
d_frame.copyTo(d_fgimg, d_fgmask);
d_fgmask.download(fgmask);
d_fgimg.download(fgimg);
if (!d_bgimg.empty())
d_bgimg.download(bgimg);
imshow("image", frame);
imshow("foreground mask", fgmask);
imshow("foreground image", fgimg);
if (!bgimg.empty())
imshow("mean background image", bgimg);
int key = waitKey(30);
if (key == 27)
break;
}
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment