fix: bg substraction for float images with OpenCL

This commit is contained in:
Matthieu FT 2016-02-01 16:24:28 +01:00
parent 9ebbfc7bdb
commit 78475a47a5
3 changed files with 98 additions and 40 deletions

View File

@ -196,7 +196,9 @@ public:
if (ocl::useOpenCL() && opencl_ON) if (ocl::useOpenCL() && opencl_ON)
{ {
create_ocl_apply_kernel(); create_ocl_apply_kernel();
kernel_getBg.create("getBackgroundImage2_kernel", ocl::video::bgfg_mog2_oclsrc, format( "-D CN=%d -D NMIXTURES=%d", nchannels, nmixtures));
bool isFloat = CV_MAKETYPE(CV_32F,nchannels) == frameType;
kernel_getBg.create("getBackgroundImage2_kernel", ocl::video::bgfg_mog2_oclsrc, format( "-D CN=%d -D FL=%d -D NMIXTURES=%d", nchannels, isFloat, nmixtures));
if (kernel_apply.empty() || kernel_getBg.empty()) if (kernel_apply.empty() || kernel_getBg.empty())
opencl_ON = false; opencl_ON = false;
@ -387,6 +389,9 @@ protected:
String name_; String name_;
template <typename T, int CN>
void getBackgroundImage_intern(OutputArray backgroundImage) const;
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
bool ocl_getBackgroundImage(OutputArray backgroundImage) const; bool ocl_getBackgroundImage(OutputArray backgroundImage) const;
bool ocl_apply(InputArray _image, OutputArray _fgmask, double learningRate=-1); bool ocl_apply(InputArray _image, OutputArray _fgmask, double learningRate=-1);
@ -803,8 +808,6 @@ bool BackgroundSubtractorMOG2Impl::ocl_apply(InputArray _image, OutputArray _fgm
bool BackgroundSubtractorMOG2Impl::ocl_getBackgroundImage(OutputArray _backgroundImage) const bool BackgroundSubtractorMOG2Impl::ocl_getBackgroundImage(OutputArray _backgroundImage) const
{ {
CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3);
_backgroundImage.create(frameSize, frameType); _backgroundImage.create(frameSize, frameType);
UMat dst = _backgroundImage.getUMat(); UMat dst = _backgroundImage.getUMat();
@ -823,7 +826,8 @@ bool BackgroundSubtractorMOG2Impl::ocl_getBackgroundImage(OutputArray _backgroun
void BackgroundSubtractorMOG2Impl::create_ocl_apply_kernel() void BackgroundSubtractorMOG2Impl::create_ocl_apply_kernel()
{ {
int nchannels = CV_MAT_CN(frameType); int nchannels = CV_MAT_CN(frameType);
String opts = format("-D CN=%d -D NMIXTURES=%d%s", nchannels, nmixtures, bShadowDetection ? " -D SHADOW_DETECT" : ""); bool isFloat = CV_MAKETYPE(CV_32F,nchannels) == frameType;
String opts = format("-D CN=%d -D FL=%d -D NMIXTURES=%d%s", nchannels, isFloat, nmixtures, bShadowDetection ? " -D SHADOW_DETECT" : "");
kernel_apply.create("mog2_kernel", ocl::video::bgfg_mog2_oclsrc, opts); kernel_apply.create("mog2_kernel", ocl::video::bgfg_mog2_oclsrc, opts);
} }
@ -866,25 +870,14 @@ void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask,
image.total()/(double)(1 << 16)); image.total()/(double)(1 << 16));
} }
void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImage) const template <typename T, int CN>
void BackgroundSubtractorMOG2Impl::getBackgroundImage_intern(OutputArray backgroundImage) const
{ {
#ifdef HAVE_OPENCL Mat meanBackground(frameSize, frameType, Scalar::all(0));
if (opencl_ON)
{
CV_OCL_RUN(opencl_ON, ocl_getBackgroundImage(backgroundImage))
opencl_ON = false;
return;
}
#endif
int nchannels = CV_MAT_CN(frameType);
CV_Assert(nchannels == 1 || nchannels == 3);
Mat meanBackground(frameSize, CV_MAKETYPE(CV_8U, nchannels), Scalar::all(0));
int firstGaussianIdx = 0; int firstGaussianIdx = 0;
const GMM* gmm = bgmodel.ptr<GMM>(); const GMM* gmm = bgmodel.ptr<GMM>();
const float* mean = reinterpret_cast<const float*>(gmm + frameSize.width*frameSize.height*nmixtures); const float* mean = reinterpret_cast<const float*>(gmm + frameSize.width*frameSize.height*nmixtures);
std::vector<float> meanVal(nchannels, 0.f); Vec<float,CN> meanVal(0.f);
for(int row=0; row<meanBackground.rows; row++) for(int row=0; row<meanBackground.rows; row++)
{ {
for(int col=0; col<meanBackground.cols; col++) for(int col=0; col<meanBackground.cols; col++)
@ -894,10 +887,10 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImag
for(int gaussianIdx = firstGaussianIdx; gaussianIdx < firstGaussianIdx + nmodes; gaussianIdx++) for(int gaussianIdx = firstGaussianIdx; gaussianIdx < firstGaussianIdx + nmodes; gaussianIdx++)
{ {
GMM gaussian = gmm[gaussianIdx]; GMM gaussian = gmm[gaussianIdx];
size_t meanPosition = gaussianIdx*nchannels; size_t meanPosition = gaussianIdx*CN;
for(int chn = 0; chn < nchannels; chn++) for(int chn = 0; chn < CN; chn++)
{ {
meanVal[chn] += gaussian.weight * mean[meanPosition + chn]; meanVal(chn) += gaussian.weight * mean[meanPosition + chn];
} }
totalWeight += gaussian.weight; totalWeight += gaussian.weight;
@ -905,24 +898,46 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImag
break; break;
} }
float invWeight = 1.f/totalWeight; float invWeight = 1.f/totalWeight;
switch(nchannels)
{ meanBackground.at<Vec<T,CN> >(row, col) = Vec<T,CN>(meanVal * invWeight);
case 1: meanVal = 0.f;
meanBackground.at<uchar>(row, col) = (uchar)(meanVal[0] * invWeight);
meanVal[0] = 0.f;
break;
case 3:
Vec3f& meanVec = *reinterpret_cast<Vec3f*>(&meanVal[0]);
meanBackground.at<Vec3b>(row, col) = Vec3b(meanVec * invWeight);
meanVec = 0.f;
break;
}
firstGaussianIdx += nmixtures; firstGaussianIdx += nmixtures;
} }
} }
meanBackground.copyTo(backgroundImage); meanBackground.copyTo(backgroundImage);
} }
void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
{
CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_32FC1 || frameType == CV_32FC3);
#ifdef HAVE_OPENCL
if (opencl_ON)
{
CV_OCL_RUN(opencl_ON, ocl_getBackgroundImage(backgroundImage))
opencl_ON = false;
}
#endif
switch(frameType)
{
case CV_8UC1:
getBackgroundImage_intern<uchar,1>(backgroundImage);
break;
case CV_8UC3:
getBackgroundImage_intern<uchar,3>(backgroundImage);
break;
case CV_32FC1:
getBackgroundImage_intern<float,1>(backgroundImage);
break;
case CV_32FC3:
getBackgroundImage_intern<float,3>(backgroundImage);
break;
}
}
Ptr<BackgroundSubtractorMOG2> createBackgroundSubtractorMOG2(int _history, double _varThreshold, Ptr<BackgroundSubtractorMOG2> createBackgroundSubtractorMOG2(int _history, double _varThreshold,
bool _bShadowDetection) bool _bShadowDetection)
{ {

View File

@ -5,7 +5,11 @@
#define cnMode 1 #define cnMode 1
#define frameToMean(a, b) (b) = *(a); #define frameToMean(a, b) (b) = *(a);
#if FL==0
#define meanToFrame(a, b) *b = convert_uchar_sat(a); #define meanToFrame(a, b) *b = convert_uchar_sat(a);
#else
#define meanToFrame(a, b) *b = (float)a;
#endif
inline float sum(float val) inline float sum(float val)
{ {
@ -18,10 +22,17 @@ inline float sum(float val)
#define F_ZERO (0.0f, 0.0f, 0.0f, 0.0f) #define F_ZERO (0.0f, 0.0f, 0.0f, 0.0f)
#define cnMode 4 #define cnMode 4
#if FL == 0
#define meanToFrame(a, b)\ #define meanToFrame(a, b)\
b[0] = convert_uchar_sat(a.x); \ b[0] = convert_uchar_sat(a.x); \
b[1] = convert_uchar_sat(a.y); \ b[1] = convert_uchar_sat(a.y); \
b[2] = convert_uchar_sat(a.z); b[2] = convert_uchar_sat(a.z);
#else
#define meanToFrame(a, b)\
b[0] = a.x; \
b[1] = a.y; \
b[2] = a.z;
#endif
#define frameToMean(a, b)\ #define frameToMean(a, b)\
b.x = a[0]; \ b.x = a[0]; \
@ -55,7 +66,11 @@ __kernel void mog2_kernel(__global const uchar* frame, int frame_step, int frame
if( x < frame_col && y < frame_row) if( x < frame_col && y < frame_row)
{ {
#if FL==0
__global const uchar* _frame = (frame + mad24(y, frame_step, mad24(x, CN, frame_offset))); __global const uchar* _frame = (frame + mad24(y, frame_step, mad24(x, CN, frame_offset)));
#else
__global const float* _frame = ((__global const float*)( frame + mad24(y, frame_step, frame_offset)) + mad24(x, CN, 0));
#endif
T_MEAN pix; T_MEAN pix;
frameToMean(_frame, pix); frameToMean(_frame, pix);
@ -267,7 +282,13 @@ __kernel void getBackgroundImage2_kernel(__global const uchar* modesUsed,
meanVal = meanVal / totalWeight; meanVal = meanVal / totalWeight;
else else
meanVal = (T_MEAN)(0.f); meanVal = (T_MEAN)(0.f);
#if FL==0
__global uchar* _dst = dst + mad24(y, dst_step, mad24(x, CN, dst_offset)); __global uchar* _dst = dst + mad24(y, dst_step, mad24(x, CN, dst_offset));
meanToFrame(meanVal, _dst); meanToFrame(meanVal, _dst);
#else
__global float* _dst = ((__global float*)( dst + mad24(y, dst_step, dst_offset)) + mad24(x, CN, 0));
meanToFrame(meanVal, _dst);
#endif
} }
} }

View File

@ -26,16 +26,19 @@ namespace
{ {
IMPLEMENT_PARAM_CLASS(UseGray, bool) IMPLEMENT_PARAM_CLASS(UseGray, bool)
IMPLEMENT_PARAM_CLASS(DetectShadow, bool) IMPLEMENT_PARAM_CLASS(DetectShadow, bool)
IMPLEMENT_PARAM_CLASS(UseFloat, bool)
} }
PARAM_TEST_CASE(Mog2_Update, UseGray, DetectShadow) PARAM_TEST_CASE(Mog2_Update, UseGray, DetectShadow,UseFloat)
{ {
bool useGray; bool useGray;
bool detectShadow; bool detectShadow;
bool useFloat;
virtual void SetUp() virtual void SetUp()
{ {
useGray = GET_PARAM(0); useGray = GET_PARAM(0);
detectShadow = GET_PARAM(1); detectShadow = GET_PARAM(1);
useFloat = GET_PARAM(2);
} }
}; };
@ -66,6 +69,13 @@ OCL_TEST_P(Mog2_Update, Accuracy)
swap(temp, frame); swap(temp, frame);
} }
if(useFloat)
{
Mat temp;
frame.convertTo(temp,CV_32F);
swap(temp,frame);
}
OCL_OFF(mog2_cpu->apply(frame, foreground)); OCL_OFF(mog2_cpu->apply(frame, foreground));
OCL_ON (mog2_ocl->apply(frame, u_foreground)); OCL_ON (mog2_ocl->apply(frame, u_foreground));
@ -78,12 +88,14 @@ OCL_TEST_P(Mog2_Update, Accuracy)
//////////////////////////Mog2_getBackgroundImage/////////////////////////////////// //////////////////////////Mog2_getBackgroundImage///////////////////////////////////
PARAM_TEST_CASE(Mog2_getBackgroundImage, DetectShadow) PARAM_TEST_CASE(Mog2_getBackgroundImage, DetectShadow, UseFloat)
{ {
bool detectShadow; bool detectShadow;
bool useFloat;
virtual void SetUp() virtual void SetUp()
{ {
detectShadow = GET_PARAM(0); detectShadow = GET_PARAM(0);
useFloat = GET_PARAM(1);
} }
}; };
@ -107,6 +119,13 @@ OCL_TEST_P(Mog2_getBackgroundImage, Accuracy)
cap >> frame; cap >> frame;
ASSERT_FALSE(frame.empty()); ASSERT_FALSE(frame.empty());
if(useFloat)
{
Mat temp;
frame.convertTo(temp,CV_32F);
swap(temp,frame);
}
OCL_OFF(mog2_cpu->apply(frame, foreground)); OCL_OFF(mog2_cpu->apply(frame, foreground));
OCL_ON (mog2_ocl->apply(frame, u_foreground)); OCL_ON (mog2_ocl->apply(frame, u_foreground));
} }
@ -123,11 +142,14 @@ OCL_TEST_P(Mog2_getBackgroundImage, Accuracy)
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_Update, Combine( OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_Update, Combine(
Values(UseGray(true), UseGray(false)), Values(UseGray(true),UseGray(false)),
Values(DetectShadow(true), DetectShadow(false))) Values(DetectShadow(true), DetectShadow(false)),
Values(UseFloat(false),UseFloat(true)))
); );
OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_getBackgroundImage, (Values(DetectShadow(true), DetectShadow(false))) OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_getBackgroundImage, Combine(
Values(DetectShadow(true), DetectShadow(false)),
Values(UseFloat(false),UseFloat(true)))
); );
}}// namespace cvtest::ocl }}// namespace cvtest::ocl