mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 08:13:04 +04:00
move obsolete algorithms from cudabgsegm to cudalegacy:
* GMG * FGD
This commit is contained in:
@@ -0,0 +1,801 @@
|
||||
/*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) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// 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 materials 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*/
|
||||
|
||||
#if !defined CUDA_DISABLER
|
||||
|
||||
#include "opencv2/core/cuda/common.hpp"
|
||||
#include "opencv2/core/cuda/vec_math.hpp"
|
||||
#include "opencv2/core/cuda/limits.hpp"
|
||||
#include "opencv2/core/cuda/utility.hpp"
|
||||
#include "opencv2/core/cuda/reduce.hpp"
|
||||
#include "opencv2/core/cuda/functional.hpp"
|
||||
#include "fgd.hpp"
|
||||
|
||||
using namespace cv::cuda;
|
||||
using namespace cv::cuda::device;
|
||||
|
||||
namespace fgd
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// calcDiffHistogram
|
||||
|
||||
const unsigned int UINT_BITS = 32U;
|
||||
const int LOG_WARP_SIZE = 5;
|
||||
const int WARP_SIZE = 1 << LOG_WARP_SIZE;
|
||||
#if (__CUDA_ARCH__ < 120)
|
||||
const unsigned int TAG_MASK = (1U << (UINT_BITS - LOG_WARP_SIZE)) - 1U;
|
||||
#endif
|
||||
|
||||
const int MERGE_THREADBLOCK_SIZE = 256;
|
||||
|
||||
__device__ __forceinline__ void addByte(unsigned int* s_WarpHist_, unsigned int data, unsigned int threadTag)
|
||||
{
|
||||
#if (__CUDA_ARCH__ < 120)
|
||||
volatile unsigned int* s_WarpHist = s_WarpHist_;
|
||||
unsigned int count;
|
||||
do
|
||||
{
|
||||
count = s_WarpHist[data] & TAG_MASK;
|
||||
count = threadTag | (count + 1);
|
||||
s_WarpHist[data] = count;
|
||||
} while (s_WarpHist[data] != count);
|
||||
#else
|
||||
atomicInc(s_WarpHist_ + data, (unsigned int)(-1));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template <typename PT, typename CT>
|
||||
__global__ void calcPartialHistogram(const PtrStepSz<PT> prevFrame, const PtrStep<CT> curFrame, unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2)
|
||||
{
|
||||
#if (__CUDA_ARCH__ < 200)
|
||||
const int HISTOGRAM_WARP_COUNT = 4;
|
||||
#else
|
||||
const int HISTOGRAM_WARP_COUNT = 6;
|
||||
#endif
|
||||
const int HISTOGRAM_THREADBLOCK_SIZE = HISTOGRAM_WARP_COUNT * WARP_SIZE;
|
||||
const int HISTOGRAM_THREADBLOCK_MEMORY = HISTOGRAM_WARP_COUNT * HISTOGRAM_BIN_COUNT;
|
||||
|
||||
//Per-warp subhistogram storage
|
||||
__shared__ unsigned int s_Hist0[HISTOGRAM_THREADBLOCK_MEMORY];
|
||||
__shared__ unsigned int s_Hist1[HISTOGRAM_THREADBLOCK_MEMORY];
|
||||
__shared__ unsigned int s_Hist2[HISTOGRAM_THREADBLOCK_MEMORY];
|
||||
|
||||
//Clear shared memory storage for current threadblock before processing
|
||||
#pragma unroll
|
||||
for (int i = 0; i < (HISTOGRAM_THREADBLOCK_MEMORY / HISTOGRAM_THREADBLOCK_SIZE); ++i)
|
||||
{
|
||||
s_Hist0[threadIdx.x + i * HISTOGRAM_THREADBLOCK_SIZE] = 0;
|
||||
s_Hist1[threadIdx.x + i * HISTOGRAM_THREADBLOCK_SIZE] = 0;
|
||||
s_Hist2[threadIdx.x + i * HISTOGRAM_THREADBLOCK_SIZE] = 0;
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
const unsigned int warpId = threadIdx.x >> LOG_WARP_SIZE;
|
||||
|
||||
unsigned int* s_WarpHist0 = s_Hist0 + warpId * HISTOGRAM_BIN_COUNT;
|
||||
unsigned int* s_WarpHist1 = s_Hist1 + warpId * HISTOGRAM_BIN_COUNT;
|
||||
unsigned int* s_WarpHist2 = s_Hist2 + warpId * HISTOGRAM_BIN_COUNT;
|
||||
|
||||
const unsigned int tag = threadIdx.x << (UINT_BITS - LOG_WARP_SIZE);
|
||||
const int dataCount = prevFrame.rows * prevFrame.cols;
|
||||
for (unsigned int pos = blockIdx.x * HISTOGRAM_THREADBLOCK_SIZE + threadIdx.x; pos < dataCount; pos += HISTOGRAM_THREADBLOCK_SIZE * PARTIAL_HISTOGRAM_COUNT)
|
||||
{
|
||||
const unsigned int y = pos / prevFrame.cols;
|
||||
const unsigned int x = pos % prevFrame.cols;
|
||||
|
||||
PT prevVal = prevFrame(y, x);
|
||||
CT curVal = curFrame(y, x);
|
||||
|
||||
int3 diff = make_int3(
|
||||
::abs(curVal.x - prevVal.x),
|
||||
::abs(curVal.y - prevVal.y),
|
||||
::abs(curVal.z - prevVal.z)
|
||||
);
|
||||
|
||||
addByte(s_WarpHist0, diff.x, tag);
|
||||
addByte(s_WarpHist1, diff.y, tag);
|
||||
addByte(s_WarpHist2, diff.z, tag);
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
//Merge per-warp histograms into per-block and write to global memory
|
||||
for (unsigned int bin = threadIdx.x; bin < HISTOGRAM_BIN_COUNT; bin += HISTOGRAM_THREADBLOCK_SIZE)
|
||||
{
|
||||
unsigned int sum0 = 0;
|
||||
unsigned int sum1 = 0;
|
||||
unsigned int sum2 = 0;
|
||||
|
||||
#pragma unroll
|
||||
for (int i = 0; i < HISTOGRAM_WARP_COUNT; ++i)
|
||||
{
|
||||
#if (__CUDA_ARCH__ < 120)
|
||||
sum0 += s_Hist0[bin + i * HISTOGRAM_BIN_COUNT] & TAG_MASK;
|
||||
sum1 += s_Hist1[bin + i * HISTOGRAM_BIN_COUNT] & TAG_MASK;
|
||||
sum2 += s_Hist2[bin + i * HISTOGRAM_BIN_COUNT] & TAG_MASK;
|
||||
#else
|
||||
sum0 += s_Hist0[bin + i * HISTOGRAM_BIN_COUNT];
|
||||
sum1 += s_Hist1[bin + i * HISTOGRAM_BIN_COUNT];
|
||||
sum2 += s_Hist2[bin + i * HISTOGRAM_BIN_COUNT];
|
||||
#endif
|
||||
}
|
||||
|
||||
partialBuf0[blockIdx.x * HISTOGRAM_BIN_COUNT + bin] = sum0;
|
||||
partialBuf1[blockIdx.x * HISTOGRAM_BIN_COUNT + bin] = sum1;
|
||||
partialBuf2[blockIdx.x * HISTOGRAM_BIN_COUNT + bin] = sum2;
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void mergeHistogram(const unsigned int* partialBuf0, const unsigned int* partialBuf1, const unsigned int* partialBuf2, unsigned int* hist0, unsigned int* hist1, unsigned int* hist2)
|
||||
{
|
||||
unsigned int sum0 = 0;
|
||||
unsigned int sum1 = 0;
|
||||
unsigned int sum2 = 0;
|
||||
|
||||
#pragma unroll
|
||||
for (unsigned int i = threadIdx.x; i < PARTIAL_HISTOGRAM_COUNT; i += MERGE_THREADBLOCK_SIZE)
|
||||
{
|
||||
sum0 += partialBuf0[blockIdx.x + i * HISTOGRAM_BIN_COUNT];
|
||||
sum1 += partialBuf1[blockIdx.x + i * HISTOGRAM_BIN_COUNT];
|
||||
sum2 += partialBuf2[blockIdx.x + i * HISTOGRAM_BIN_COUNT];
|
||||
}
|
||||
|
||||
__shared__ unsigned int data0[MERGE_THREADBLOCK_SIZE];
|
||||
__shared__ unsigned int data1[MERGE_THREADBLOCK_SIZE];
|
||||
__shared__ unsigned int data2[MERGE_THREADBLOCK_SIZE];
|
||||
|
||||
plus<unsigned int> op;
|
||||
reduce<MERGE_THREADBLOCK_SIZE>(smem_tuple(data0, data1, data2), thrust::tie(sum0, sum1, sum2), threadIdx.x, thrust::make_tuple(op, op, op));
|
||||
|
||||
if(threadIdx.x == 0)
|
||||
{
|
||||
hist0[blockIdx.x] = sum0;
|
||||
hist1[blockIdx.x] = sum1;
|
||||
hist2[blockIdx.x] = sum2;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PT, typename CT>
|
||||
void calcDiffHistogram_gpu(PtrStepSzb prevFrame, PtrStepSzb curFrame,
|
||||
unsigned int* hist0, unsigned int* hist1, unsigned int* hist2,
|
||||
unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2,
|
||||
bool cc20, cudaStream_t stream)
|
||||
{
|
||||
const int HISTOGRAM_WARP_COUNT = cc20 ? 6 : 4;
|
||||
const int HISTOGRAM_THREADBLOCK_SIZE = HISTOGRAM_WARP_COUNT * WARP_SIZE;
|
||||
|
||||
calcPartialHistogram<PT, CT><<<PARTIAL_HISTOGRAM_COUNT, HISTOGRAM_THREADBLOCK_SIZE, 0, stream>>>(
|
||||
(PtrStepSz<PT>)prevFrame, (PtrStepSz<CT>)curFrame, partialBuf0, partialBuf1, partialBuf2);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
mergeHistogram<<<HISTOGRAM_BIN_COUNT, MERGE_THREADBLOCK_SIZE, 0, stream>>>(partialBuf0, partialBuf1, partialBuf2, hist0, hist1, hist2);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
if (stream == 0)
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
}
|
||||
|
||||
template void calcDiffHistogram_gpu<uchar3, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, unsigned int* hist0, unsigned int* hist1, unsigned int* hist2, unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2, bool cc20, cudaStream_t stream);
|
||||
template void calcDiffHistogram_gpu<uchar3, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, unsigned int* hist0, unsigned int* hist1, unsigned int* hist2, unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2, bool cc20, cudaStream_t stream);
|
||||
template void calcDiffHistogram_gpu<uchar4, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, unsigned int* hist0, unsigned int* hist1, unsigned int* hist2, unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2, bool cc20, cudaStream_t stream);
|
||||
template void calcDiffHistogram_gpu<uchar4, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, unsigned int* hist0, unsigned int* hist1, unsigned int* hist2, unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2, bool cc20, cudaStream_t stream);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// calcDiffThreshMask
|
||||
|
||||
template <typename PT, typename CT>
|
||||
__global__ void calcDiffThreshMask(const PtrStepSz<PT> prevFrame, const PtrStep<CT> curFrame, uchar3 bestThres, PtrStepb changeMask)
|
||||
{
|
||||
const int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
const int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
if (y > prevFrame.rows || x > prevFrame.cols)
|
||||
return;
|
||||
|
||||
PT prevVal = prevFrame(y, x);
|
||||
CT curVal = curFrame(y, x);
|
||||
|
||||
int3 diff = make_int3(
|
||||
::abs(curVal.x - prevVal.x),
|
||||
::abs(curVal.y - prevVal.y),
|
||||
::abs(curVal.z - prevVal.z)
|
||||
);
|
||||
|
||||
if (diff.x > bestThres.x || diff.y > bestThres.y || diff.z > bestThres.z)
|
||||
changeMask(y, x) = 255;
|
||||
}
|
||||
|
||||
template <typename PT, typename CT>
|
||||
void calcDiffThreshMask_gpu(PtrStepSzb prevFrame, PtrStepSzb curFrame, uchar3 bestThres, PtrStepSzb changeMask, cudaStream_t stream)
|
||||
{
|
||||
dim3 block(32, 8);
|
||||
dim3 grid(divUp(prevFrame.cols, block.x), divUp(prevFrame.rows, block.y));
|
||||
|
||||
calcDiffThreshMask<PT, CT><<<grid, block, 0, stream>>>((PtrStepSz<PT>)prevFrame, (PtrStepSz<CT>)curFrame, bestThres, changeMask);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
if (stream == 0)
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
}
|
||||
|
||||
template void calcDiffThreshMask_gpu<uchar3, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, uchar3 bestThres, PtrStepSzb changeMask, cudaStream_t stream);
|
||||
template void calcDiffThreshMask_gpu<uchar3, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, uchar3 bestThres, PtrStepSzb changeMask, cudaStream_t stream);
|
||||
template void calcDiffThreshMask_gpu<uchar4, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, uchar3 bestThres, PtrStepSzb changeMask, cudaStream_t stream);
|
||||
template void calcDiffThreshMask_gpu<uchar4, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, uchar3 bestThres, PtrStepSzb changeMask, cudaStream_t stream);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// bgfgClassification
|
||||
|
||||
__constant__ BGPixelStat c_stat;
|
||||
|
||||
void setBGPixelStat(const BGPixelStat& stat)
|
||||
{
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_stat, &stat, sizeof(BGPixelStat)) );
|
||||
}
|
||||
|
||||
template <typename T> struct Output;
|
||||
template <> struct Output<uchar3>
|
||||
{
|
||||
static __device__ __forceinline__ uchar3 make(uchar v0, uchar v1, uchar v2)
|
||||
{
|
||||
return make_uchar3(v0, v1, v2);
|
||||
}
|
||||
};
|
||||
template <> struct Output<uchar4>
|
||||
{
|
||||
static __device__ __forceinline__ uchar4 make(uchar v0, uchar v1, uchar v2)
|
||||
{
|
||||
return make_uchar4(v0, v1, v2, 255);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PT, typename CT, typename OT>
|
||||
__global__ void bgfgClassification(const PtrStepSz<PT> prevFrame, const PtrStep<CT> curFrame,
|
||||
const PtrStepb Ftd, const PtrStepb Fbd, PtrStepb foreground,
|
||||
int deltaC, int deltaCC, float alpha2, int N1c, int N1cc)
|
||||
{
|
||||
const int i = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
const int j = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
if (i > prevFrame.rows || j > prevFrame.cols)
|
||||
return;
|
||||
|
||||
if (Fbd(i, j) || Ftd(i, j))
|
||||
{
|
||||
float Pb = 0.0f;
|
||||
float Pv = 0.0f;
|
||||
float Pvb = 0.0f;
|
||||
|
||||
int val = 0;
|
||||
|
||||
// Is it a motion pixel?
|
||||
if (Ftd(i, j))
|
||||
{
|
||||
if (!c_stat.is_trained_dyn_model(i, j))
|
||||
val = 1;
|
||||
else
|
||||
{
|
||||
PT prevVal = prevFrame(i, j);
|
||||
CT curVal = curFrame(i, j);
|
||||
|
||||
// Compare with stored CCt vectors:
|
||||
for (int k = 0; k < N1cc && c_stat.PV_CC(i, j, k) > alpha2; ++k)
|
||||
{
|
||||
OT v1 = c_stat.V1_CC<OT>(i, j, k);
|
||||
OT v2 = c_stat.V2_CC<OT>(i, j, k);
|
||||
|
||||
if (::abs(v1.x - prevVal.x) <= deltaCC &&
|
||||
::abs(v1.y - prevVal.y) <= deltaCC &&
|
||||
::abs(v1.z - prevVal.z) <= deltaCC &&
|
||||
::abs(v2.x - curVal.x) <= deltaCC &&
|
||||
::abs(v2.y - curVal.y) <= deltaCC &&
|
||||
::abs(v2.z - curVal.z) <= deltaCC)
|
||||
{
|
||||
Pv += c_stat.PV_CC(i, j, k);
|
||||
Pvb += c_stat.PVB_CC(i, j, k);
|
||||
}
|
||||
}
|
||||
|
||||
Pb = c_stat.Pbcc(i, j);
|
||||
if (2 * Pvb * Pb <= Pv)
|
||||
val = 1;
|
||||
}
|
||||
}
|
||||
else if(c_stat.is_trained_st_model(i, j))
|
||||
{
|
||||
CT curVal = curFrame(i, j);
|
||||
|
||||
// Compare with stored Ct vectors:
|
||||
for (int k = 0; k < N1c && c_stat.PV_C(i, j, k) > alpha2; ++k)
|
||||
{
|
||||
OT v = c_stat.V_C<OT>(i, j, k);
|
||||
|
||||
if (::abs(v.x - curVal.x) <= deltaC &&
|
||||
::abs(v.y - curVal.y) <= deltaC &&
|
||||
::abs(v.z - curVal.z) <= deltaC)
|
||||
{
|
||||
Pv += c_stat.PV_C(i, j, k);
|
||||
Pvb += c_stat.PVB_C(i, j, k);
|
||||
}
|
||||
}
|
||||
Pb = c_stat.Pbc(i, j);
|
||||
if (2 * Pvb * Pb <= Pv)
|
||||
val = 1;
|
||||
}
|
||||
|
||||
// Update foreground:
|
||||
foreground(i, j) = static_cast<uchar>(val);
|
||||
} // end if( change detection...
|
||||
}
|
||||
|
||||
template <typename PT, typename CT, typename OT>
|
||||
void bgfgClassification_gpu(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground,
|
||||
int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream)
|
||||
{
|
||||
dim3 block(32, 8);
|
||||
dim3 grid(divUp(prevFrame.cols, block.x), divUp(prevFrame.rows, block.y));
|
||||
|
||||
cudaSafeCall( cudaFuncSetCacheConfig(bgfgClassification<PT, CT, OT>, cudaFuncCachePreferL1) );
|
||||
|
||||
bgfgClassification<PT, CT, OT><<<grid, block, 0, stream>>>((PtrStepSz<PT>)prevFrame, (PtrStepSz<CT>)curFrame,
|
||||
Ftd, Fbd, foreground,
|
||||
deltaC, deltaCC, alpha2, N1c, N1cc);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
if (stream == 0)
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
}
|
||||
|
||||
template void bgfgClassification_gpu<uchar3, uchar3, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
template void bgfgClassification_gpu<uchar3, uchar3, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
template void bgfgClassification_gpu<uchar3, uchar4, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
template void bgfgClassification_gpu<uchar3, uchar4, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
template void bgfgClassification_gpu<uchar4, uchar3, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
template void bgfgClassification_gpu<uchar4, uchar3, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
template void bgfgClassification_gpu<uchar4, uchar4, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
template void bgfgClassification_gpu<uchar4, uchar4, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// updateBackgroundModel
|
||||
|
||||
template <typename PT, typename CT, typename OT, class PrevFramePtr2D, class CurFramePtr2D, class FtdPtr2D, class FbdPtr2D>
|
||||
__global__ void updateBackgroundModel(int cols, int rows, const PrevFramePtr2D prevFrame, const CurFramePtr2D curFrame, const FtdPtr2D Ftd, const FbdPtr2D Fbd,
|
||||
PtrStepb foreground, PtrStep<OT> background,
|
||||
int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T)
|
||||
{
|
||||
const int i = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
const int j = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
if (i > rows || j > cols)
|
||||
return;
|
||||
|
||||
const float MIN_PV = 1e-10f;
|
||||
|
||||
const uchar is_trained_dyn_model = c_stat.is_trained_dyn_model(i, j);
|
||||
if (Ftd(i, j) || !is_trained_dyn_model)
|
||||
{
|
||||
const float alpha = is_trained_dyn_model ? alpha2 : alpha3;
|
||||
|
||||
float Pbcc = c_stat.Pbcc(i, j);
|
||||
|
||||
//update Pb
|
||||
Pbcc *= (1.0f - alpha);
|
||||
if (!foreground(i, j))
|
||||
{
|
||||
Pbcc += alpha;
|
||||
}
|
||||
|
||||
int min_dist = numeric_limits<int>::max();
|
||||
int indx = -1;
|
||||
|
||||
PT prevVal = prevFrame(i, j);
|
||||
CT curVal = curFrame(i, j);
|
||||
|
||||
// Find best Vi match:
|
||||
for (int k = 0; k < N2cc; ++k)
|
||||
{
|
||||
float PV_CC = c_stat.PV_CC(i, j, k);
|
||||
if (!PV_CC)
|
||||
break;
|
||||
|
||||
if (PV_CC < MIN_PV)
|
||||
{
|
||||
c_stat.PV_CC(i, j, k) = 0;
|
||||
c_stat.PVB_CC(i, j, k) = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
c_stat.PV_CC(i, j, k) = PV_CC * (1.0f - alpha);
|
||||
c_stat.PVB_CC(i, j, k) = c_stat.PVB_CC(i, j, k) * (1.0f - alpha);
|
||||
|
||||
OT v1 = c_stat.V1_CC<OT>(i, j, k);
|
||||
|
||||
int3 val1 = make_int3(
|
||||
::abs(v1.x - prevVal.x),
|
||||
::abs(v1.y - prevVal.y),
|
||||
::abs(v1.z - prevVal.z)
|
||||
);
|
||||
|
||||
OT v2 = c_stat.V2_CC<OT>(i, j, k);
|
||||
|
||||
int3 val2 = make_int3(
|
||||
::abs(v2.x - curVal.x),
|
||||
::abs(v2.y - curVal.y),
|
||||
::abs(v2.z - curVal.z)
|
||||
);
|
||||
|
||||
int dist = val1.x + val1.y + val1.z + val2.x + val2.y + val2.z;
|
||||
|
||||
if (dist < min_dist &&
|
||||
val1.x <= deltaCC && val1.y <= deltaCC && val1.z <= deltaCC &&
|
||||
val2.x <= deltaCC && val2.y <= deltaCC && val2.z <= deltaCC)
|
||||
{
|
||||
min_dist = dist;
|
||||
indx = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (indx < 0)
|
||||
{
|
||||
// Replace N2th elem in the table by new feature:
|
||||
indx = N2cc - 1;
|
||||
c_stat.PV_CC(i, j, indx) = alpha;
|
||||
c_stat.PVB_CC(i, j, indx) = alpha;
|
||||
|
||||
//udate Vt
|
||||
c_stat.V1_CC<OT>(i, j, indx) = Output<OT>::make(prevVal.x, prevVal.y, prevVal.z);
|
||||
c_stat.V2_CC<OT>(i, j, indx) = Output<OT>::make(curVal.x, curVal.y, curVal.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update:
|
||||
c_stat.PV_CC(i, j, indx) += alpha;
|
||||
|
||||
if (!foreground(i, j))
|
||||
{
|
||||
c_stat.PVB_CC(i, j, indx) += alpha;
|
||||
}
|
||||
}
|
||||
|
||||
//re-sort CCt table by Pv
|
||||
const float PV_CC_indx = c_stat.PV_CC(i, j, indx);
|
||||
const float PVB_CC_indx = c_stat.PVB_CC(i, j, indx);
|
||||
const OT V1_CC_indx = c_stat.V1_CC<OT>(i, j, indx);
|
||||
const OT V2_CC_indx = c_stat.V2_CC<OT>(i, j, indx);
|
||||
for (int k = 0; k < indx; ++k)
|
||||
{
|
||||
if (c_stat.PV_CC(i, j, k) <= PV_CC_indx)
|
||||
{
|
||||
//shift elements
|
||||
float Pv_tmp1;
|
||||
float Pv_tmp2 = PV_CC_indx;
|
||||
|
||||
float Pvb_tmp1;
|
||||
float Pvb_tmp2 = PVB_CC_indx;
|
||||
|
||||
OT v1_tmp1;
|
||||
OT v1_tmp2 = V1_CC_indx;
|
||||
|
||||
OT v2_tmp1;
|
||||
OT v2_tmp2 = V2_CC_indx;
|
||||
|
||||
for (int l = k; l <= indx; ++l)
|
||||
{
|
||||
Pv_tmp1 = c_stat.PV_CC(i, j, l);
|
||||
c_stat.PV_CC(i, j, l) = Pv_tmp2;
|
||||
Pv_tmp2 = Pv_tmp1;
|
||||
|
||||
Pvb_tmp1 = c_stat.PVB_CC(i, j, l);
|
||||
c_stat.PVB_CC(i, j, l) = Pvb_tmp2;
|
||||
Pvb_tmp2 = Pvb_tmp1;
|
||||
|
||||
v1_tmp1 = c_stat.V1_CC<OT>(i, j, l);
|
||||
c_stat.V1_CC<OT>(i, j, l) = v1_tmp2;
|
||||
v1_tmp2 = v1_tmp1;
|
||||
|
||||
v2_tmp1 = c_stat.V2_CC<OT>(i, j, l);
|
||||
c_stat.V2_CC<OT>(i, j, l) = v2_tmp2;
|
||||
v2_tmp2 = v2_tmp1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float sum1 = 0.0f;
|
||||
float sum2 = 0.0f;
|
||||
|
||||
//check "once-off" changes
|
||||
for (int k = 0; k < N1cc; ++k)
|
||||
{
|
||||
const float PV_CC = c_stat.PV_CC(i, j, k);
|
||||
if (!PV_CC)
|
||||
break;
|
||||
|
||||
sum1 += PV_CC;
|
||||
sum2 += c_stat.PVB_CC(i, j, k);
|
||||
}
|
||||
|
||||
if (sum1 > T)
|
||||
c_stat.is_trained_dyn_model(i, j) = 1;
|
||||
|
||||
float diff = sum1 - Pbcc * sum2;
|
||||
|
||||
// Update stat table:
|
||||
if (diff > T)
|
||||
{
|
||||
//new BG features are discovered
|
||||
for (int k = 0; k < N1cc; ++k)
|
||||
{
|
||||
const float PV_CC = c_stat.PV_CC(i, j, k);
|
||||
if (!PV_CC)
|
||||
break;
|
||||
|
||||
c_stat.PVB_CC(i, j, k) = (PV_CC - Pbcc * c_stat.PVB_CC(i, j, k)) / (1.0f - Pbcc);
|
||||
}
|
||||
}
|
||||
|
||||
c_stat.Pbcc(i, j) = Pbcc;
|
||||
}
|
||||
|
||||
// Handle "stationary" pixel:
|
||||
if (!Ftd(i, j))
|
||||
{
|
||||
const float alpha = c_stat.is_trained_st_model(i, j) ? alpha2 : alpha3;
|
||||
|
||||
float Pbc = c_stat.Pbc(i, j);
|
||||
|
||||
//update Pb
|
||||
Pbc *= (1.0f - alpha);
|
||||
if (!foreground(i, j))
|
||||
{
|
||||
Pbc += alpha;
|
||||
}
|
||||
|
||||
int min_dist = numeric_limits<int>::max();
|
||||
int indx = -1;
|
||||
|
||||
CT curVal = curFrame(i, j);
|
||||
|
||||
//find best Vi match
|
||||
for (int k = 0; k < N2c; ++k)
|
||||
{
|
||||
float PV_C = c_stat.PV_C(i, j, k);
|
||||
|
||||
if (PV_C < MIN_PV)
|
||||
{
|
||||
c_stat.PV_C(i, j, k) = 0;
|
||||
c_stat.PVB_C(i, j, k) = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exponential decay of memory
|
||||
c_stat.PV_C(i, j, k) = PV_C * (1.0f - alpha);
|
||||
c_stat.PVB_C(i, j, k) = c_stat.PVB_C(i, j, k) * (1.0f - alpha);
|
||||
|
||||
OT v = c_stat.V_C<OT>(i, j, k);
|
||||
int3 val = make_int3(
|
||||
::abs(v.x - curVal.x),
|
||||
::abs(v.y - curVal.y),
|
||||
::abs(v.z - curVal.z)
|
||||
);
|
||||
|
||||
int dist = val.x + val.y + val.z;
|
||||
|
||||
if (dist < min_dist && val.x <= deltaC && val.y <= deltaC && val.z <= deltaC)
|
||||
{
|
||||
min_dist = dist;
|
||||
indx = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (indx < 0)
|
||||
{
|
||||
//N2th elem in the table is replaced by a new features
|
||||
indx = N2c - 1;
|
||||
|
||||
c_stat.PV_C(i, j, indx) = alpha;
|
||||
c_stat.PVB_C(i, j, indx) = alpha;
|
||||
|
||||
//udate Vt
|
||||
c_stat.V_C<OT>(i, j, indx) = Output<OT>::make(curVal.x, curVal.y, curVal.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
//update
|
||||
c_stat.PV_C(i, j, indx) += alpha;
|
||||
|
||||
if (!foreground(i, j))
|
||||
{
|
||||
c_stat.PVB_C(i, j, indx) += alpha;
|
||||
}
|
||||
}
|
||||
|
||||
//re-sort Ct table by Pv
|
||||
const float PV_C_indx = c_stat.PV_C(i, j, indx);
|
||||
const float PVB_C_indx = c_stat.PVB_C(i, j, indx);
|
||||
OT V_C_indx = c_stat.V_C<OT>(i, j, indx);
|
||||
for (int k = 0; k < indx; ++k)
|
||||
{
|
||||
if (c_stat.PV_C(i, j, k) <= PV_C_indx)
|
||||
{
|
||||
//shift elements
|
||||
float Pv_tmp1;
|
||||
float Pv_tmp2 = PV_C_indx;
|
||||
|
||||
float Pvb_tmp1;
|
||||
float Pvb_tmp2 = PVB_C_indx;
|
||||
|
||||
OT v_tmp1;
|
||||
OT v_tmp2 = V_C_indx;
|
||||
|
||||
for (int l = k; l <= indx; ++l)
|
||||
{
|
||||
Pv_tmp1 = c_stat.PV_C(i, j, l);
|
||||
c_stat.PV_C(i, j, l) = Pv_tmp2;
|
||||
Pv_tmp2 = Pv_tmp1;
|
||||
|
||||
Pvb_tmp1 = c_stat.PVB_C(i, j, l);
|
||||
c_stat.PVB_C(i, j, l) = Pvb_tmp2;
|
||||
Pvb_tmp2 = Pvb_tmp1;
|
||||
|
||||
v_tmp1 = c_stat.V_C<OT>(i, j, l);
|
||||
c_stat.V_C<OT>(i, j, l) = v_tmp2;
|
||||
v_tmp2 = v_tmp1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check "once-off" changes:
|
||||
float sum1 = 0.0f;
|
||||
float sum2 = 0.0f;
|
||||
for (int k = 0; k < N1c; ++k)
|
||||
{
|
||||
const float PV_C = c_stat.PV_C(i, j, k);
|
||||
if (!PV_C)
|
||||
break;
|
||||
|
||||
sum1 += PV_C;
|
||||
sum2 += c_stat.PVB_C(i, j, k);
|
||||
}
|
||||
|
||||
if (sum1 > T)
|
||||
c_stat.is_trained_st_model(i, j) = 1;
|
||||
|
||||
float diff = sum1 - Pbc * sum2;
|
||||
|
||||
// Update stat table:
|
||||
if (diff > T)
|
||||
{
|
||||
//new BG features are discovered
|
||||
for (int k = 0; k < N1c; ++k)
|
||||
{
|
||||
const float PV_C = c_stat.PV_C(i, j, k);
|
||||
if (!PV_C)
|
||||
break;
|
||||
|
||||
c_stat.PVB_C(i, j, k) = (PV_C - Pbc * c_stat.PVB_C(i, j, k)) / (1.0f - Pbc);
|
||||
}
|
||||
|
||||
c_stat.Pbc(i, j) = 1.0f - Pbc;
|
||||
}
|
||||
else
|
||||
{
|
||||
c_stat.Pbc(i, j) = Pbc;
|
||||
}
|
||||
} // if !(change detection) at pixel (i,j)
|
||||
|
||||
// Update the reference BG image:
|
||||
if (!foreground(i, j))
|
||||
{
|
||||
CT curVal = curFrame(i, j);
|
||||
|
||||
if (!Ftd(i, j) && !Fbd(i, j))
|
||||
{
|
||||
// Apply IIR filter:
|
||||
OT oldVal = background(i, j);
|
||||
|
||||
int3 newVal = make_int3(
|
||||
__float2int_rn(oldVal.x * (1.0f - alpha1) + curVal.x * alpha1),
|
||||
__float2int_rn(oldVal.y * (1.0f - alpha1) + curVal.y * alpha1),
|
||||
__float2int_rn(oldVal.z * (1.0f - alpha1) + curVal.z * alpha1)
|
||||
);
|
||||
|
||||
background(i, j) = Output<OT>::make(
|
||||
static_cast<uchar>(newVal.x),
|
||||
static_cast<uchar>(newVal.y),
|
||||
static_cast<uchar>(newVal.z)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
background(i, j) = Output<OT>::make(curVal.x, curVal.y, curVal.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PT, typename CT, typename OT>
|
||||
struct UpdateBackgroundModel
|
||||
{
|
||||
static void call(PtrStepSz<PT> prevFrame, PtrStepSz<CT> curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSz<OT> background,
|
||||
int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T,
|
||||
cudaStream_t stream)
|
||||
{
|
||||
dim3 block(32, 8);
|
||||
dim3 grid(divUp(prevFrame.cols, block.x), divUp(prevFrame.rows, block.y));
|
||||
|
||||
cudaSafeCall( cudaFuncSetCacheConfig(updateBackgroundModel<PT, CT, OT, PtrStep<PT>, PtrStep<CT>, PtrStepb, PtrStepb>, cudaFuncCachePreferL1) );
|
||||
|
||||
updateBackgroundModel<PT, CT, OT, PtrStep<PT>, PtrStep<CT>, PtrStepb, PtrStepb><<<grid, block, 0, stream>>>(
|
||||
prevFrame.cols, prevFrame.rows,
|
||||
prevFrame, curFrame,
|
||||
Ftd, Fbd, foreground, background,
|
||||
deltaC, deltaCC, alpha1, alpha2, alpha3, N1c, N1cc, N2c, N2cc, T);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
if (stream == 0)
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PT, typename CT, typename OT>
|
||||
void updateBackgroundModel_gpu(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background,
|
||||
int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T,
|
||||
cudaStream_t stream)
|
||||
{
|
||||
UpdateBackgroundModel<PT, CT, OT>::call(PtrStepSz<PT>(prevFrame), PtrStepSz<CT>(curFrame), Ftd, Fbd, foreground, PtrStepSz<OT>(background),
|
||||
deltaC, deltaCC, alpha1, alpha2, alpha3, N1c, N1cc, N2c, N2cc, T, stream);
|
||||
}
|
||||
|
||||
template void updateBackgroundModel_gpu<uchar3, uchar3, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
template void updateBackgroundModel_gpu<uchar3, uchar3, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
template void updateBackgroundModel_gpu<uchar3, uchar4, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
template void updateBackgroundModel_gpu<uchar3, uchar4, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
template void updateBackgroundModel_gpu<uchar4, uchar3, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
template void updateBackgroundModel_gpu<uchar4, uchar3, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
template void updateBackgroundModel_gpu<uchar4, uchar4, uchar3>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
template void updateBackgroundModel_gpu<uchar4, uchar4, uchar4>(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground, PtrStepSzb background, int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
}
|
||||
|
||||
#endif /* CUDA_DISABLER */
|
||||
@@ -0,0 +1,189 @@
|
||||
/*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) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// 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 materials 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*/
|
||||
|
||||
#ifndef __FGD_BGFG_COMMON_HPP__
|
||||
#define __FGD_BGFG_COMMON_HPP__
|
||||
|
||||
#include "opencv2/core/cuda_types.hpp"
|
||||
|
||||
namespace fgd
|
||||
{
|
||||
struct BGPixelStat
|
||||
{
|
||||
public:
|
||||
#ifdef __CUDACC__
|
||||
__device__ float& Pbc(int i, int j);
|
||||
__device__ float& Pbcc(int i, int j);
|
||||
|
||||
__device__ unsigned char& is_trained_st_model(int i, int j);
|
||||
__device__ unsigned char& is_trained_dyn_model(int i, int j);
|
||||
|
||||
__device__ float& PV_C(int i, int j, int k);
|
||||
__device__ float& PVB_C(int i, int j, int k);
|
||||
template <typename T> __device__ T& V_C(int i, int j, int k);
|
||||
|
||||
__device__ float& PV_CC(int i, int j, int k);
|
||||
__device__ float& PVB_CC(int i, int j, int k);
|
||||
template <typename T> __device__ T& V1_CC(int i, int j, int k);
|
||||
template <typename T> __device__ T& V2_CC(int i, int j, int k);
|
||||
#endif
|
||||
|
||||
int rows_;
|
||||
|
||||
unsigned char* Pbc_data_;
|
||||
size_t Pbc_step_;
|
||||
|
||||
unsigned char* Pbcc_data_;
|
||||
size_t Pbcc_step_;
|
||||
|
||||
unsigned char* is_trained_st_model_data_;
|
||||
size_t is_trained_st_model_step_;
|
||||
|
||||
unsigned char* is_trained_dyn_model_data_;
|
||||
size_t is_trained_dyn_model_step_;
|
||||
|
||||
unsigned char* ctable_Pv_data_;
|
||||
size_t ctable_Pv_step_;
|
||||
|
||||
unsigned char* ctable_Pvb_data_;
|
||||
size_t ctable_Pvb_step_;
|
||||
|
||||
unsigned char* ctable_v_data_;
|
||||
size_t ctable_v_step_;
|
||||
|
||||
unsigned char* cctable_Pv_data_;
|
||||
size_t cctable_Pv_step_;
|
||||
|
||||
unsigned char* cctable_Pvb_data_;
|
||||
size_t cctable_Pvb_step_;
|
||||
|
||||
unsigned char* cctable_v1_data_;
|
||||
size_t cctable_v1_step_;
|
||||
|
||||
unsigned char* cctable_v2_data_;
|
||||
size_t cctable_v2_step_;
|
||||
};
|
||||
|
||||
#ifdef __CUDACC__
|
||||
__device__ __forceinline__ float& BGPixelStat::Pbc(int i, int j)
|
||||
{
|
||||
return *((float*)(Pbc_data_ + i * Pbc_step_) + j);
|
||||
}
|
||||
|
||||
__device__ __forceinline__ float& BGPixelStat::Pbcc(int i, int j)
|
||||
{
|
||||
return *((float*)(Pbcc_data_ + i * Pbcc_step_) + j);
|
||||
}
|
||||
|
||||
__device__ __forceinline__ unsigned char& BGPixelStat::is_trained_st_model(int i, int j)
|
||||
{
|
||||
return *((unsigned char*)(is_trained_st_model_data_ + i * is_trained_st_model_step_) + j);
|
||||
}
|
||||
|
||||
__device__ __forceinline__ unsigned char& BGPixelStat::is_trained_dyn_model(int i, int j)
|
||||
{
|
||||
return *((unsigned char*)(is_trained_dyn_model_data_ + i * is_trained_dyn_model_step_) + j);
|
||||
}
|
||||
|
||||
__device__ __forceinline__ float& BGPixelStat::PV_C(int i, int j, int k)
|
||||
{
|
||||
return *((float*)(ctable_Pv_data_ + ((k * rows_) + i) * ctable_Pv_step_) + j);
|
||||
}
|
||||
|
||||
__device__ __forceinline__ float& BGPixelStat::PVB_C(int i, int j, int k)
|
||||
{
|
||||
return *((float*)(ctable_Pvb_data_ + ((k * rows_) + i) * ctable_Pvb_step_) + j);
|
||||
}
|
||||
|
||||
template <typename T> __device__ __forceinline__ T& BGPixelStat::V_C(int i, int j, int k)
|
||||
{
|
||||
return *((T*)(ctable_v_data_ + ((k * rows_) + i) * ctable_v_step_) + j);
|
||||
}
|
||||
|
||||
__device__ __forceinline__ float& BGPixelStat::PV_CC(int i, int j, int k)
|
||||
{
|
||||
return *((float*)(cctable_Pv_data_ + ((k * rows_) + i) * cctable_Pv_step_) + j);
|
||||
}
|
||||
|
||||
__device__ __forceinline__ float& BGPixelStat::PVB_CC(int i, int j, int k)
|
||||
{
|
||||
return *((float*)(cctable_Pvb_data_ + ((k * rows_) + i) * cctable_Pvb_step_) + j);
|
||||
}
|
||||
|
||||
template <typename T> __device__ __forceinline__ T& BGPixelStat::V1_CC(int i, int j, int k)
|
||||
{
|
||||
return *((T*)(cctable_v1_data_ + ((k * rows_) + i) * cctable_v1_step_) + j);
|
||||
}
|
||||
|
||||
template <typename T> __device__ __forceinline__ T& BGPixelStat::V2_CC(int i, int j, int k)
|
||||
{
|
||||
return *((T*)(cctable_v2_data_ + ((k * rows_) + i) * cctable_v2_step_) + j);
|
||||
}
|
||||
#endif
|
||||
|
||||
const int PARTIAL_HISTOGRAM_COUNT = 240;
|
||||
const int HISTOGRAM_BIN_COUNT = 256;
|
||||
|
||||
template <typename PT, typename CT>
|
||||
void calcDiffHistogram_gpu(cv::cuda::PtrStepSzb prevFrame, cv::cuda::PtrStepSzb curFrame,
|
||||
unsigned int* hist0, unsigned int* hist1, unsigned int* hist2,
|
||||
unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2,
|
||||
bool cc20, cudaStream_t stream);
|
||||
|
||||
template <typename PT, typename CT>
|
||||
void calcDiffThreshMask_gpu(cv::cuda::PtrStepSzb prevFrame, cv::cuda::PtrStepSzb curFrame, uchar3 bestThres, cv::cuda::PtrStepSzb changeMask, cudaStream_t stream);
|
||||
|
||||
void setBGPixelStat(const BGPixelStat& stat);
|
||||
|
||||
template <typename PT, typename CT, typename OT>
|
||||
void bgfgClassification_gpu(cv::cuda::PtrStepSzb prevFrame, cv::cuda::PtrStepSzb curFrame,
|
||||
cv::cuda::PtrStepSzb Ftd, cv::cuda::PtrStepSzb Fbd, cv::cuda::PtrStepSzb foreground,
|
||||
int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
|
||||
template <typename PT, typename CT, typename OT>
|
||||
void updateBackgroundModel_gpu(cv::cuda::PtrStepSzb prevFrame, cv::cuda::PtrStepSzb curFrame,
|
||||
cv::cuda::PtrStepSzb Ftd, cv::cuda::PtrStepSzb Fbd, cv::cuda::PtrStepSzb foreground, cv::cuda::PtrStepSzb background,
|
||||
int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T,
|
||||
cudaStream_t stream);
|
||||
}
|
||||
|
||||
#endif // __FGD_BGFG_COMMON_HPP__
|
||||
@@ -0,0 +1,258 @@
|
||||
/*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) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// 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 materials 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*/
|
||||
|
||||
#if !defined CUDA_DISABLER
|
||||
|
||||
#include "opencv2/core/cuda/common.hpp"
|
||||
#include "opencv2/core/cuda/vec_traits.hpp"
|
||||
#include "opencv2/core/cuda/limits.hpp"
|
||||
|
||||
namespace cv { namespace cuda { namespace device {
|
||||
namespace gmg
|
||||
{
|
||||
__constant__ int c_width;
|
||||
__constant__ int c_height;
|
||||
__constant__ float c_minVal;
|
||||
__constant__ float c_maxVal;
|
||||
__constant__ int c_quantizationLevels;
|
||||
__constant__ float c_backgroundPrior;
|
||||
__constant__ float c_decisionThreshold;
|
||||
__constant__ int c_maxFeatures;
|
||||
__constant__ int c_numInitializationFrames;
|
||||
|
||||
void loadConstants(int width, int height, float minVal, float maxVal, int quantizationLevels, float backgroundPrior,
|
||||
float decisionThreshold, int maxFeatures, int numInitializationFrames)
|
||||
{
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_width, &width, sizeof(width)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_height, &height, sizeof(height)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_minVal, &minVal, sizeof(minVal)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_maxVal, &maxVal, sizeof(maxVal)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_quantizationLevels, &quantizationLevels, sizeof(quantizationLevels)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_backgroundPrior, &backgroundPrior, sizeof(backgroundPrior)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_decisionThreshold, &decisionThreshold, sizeof(decisionThreshold)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_maxFeatures, &maxFeatures, sizeof(maxFeatures)) );
|
||||
cudaSafeCall( cudaMemcpyToSymbol(c_numInitializationFrames, &numInitializationFrames, sizeof(numInitializationFrames)) );
|
||||
}
|
||||
|
||||
__device__ float findFeature(const int color, const PtrStepi& colors, const PtrStepf& weights, const int x, const int y, const int nfeatures)
|
||||
{
|
||||
for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
|
||||
{
|
||||
if (color == colors(fy, x))
|
||||
return weights(fy, x);
|
||||
}
|
||||
|
||||
// not in histogram, so return 0.
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
__device__ void normalizeHistogram(PtrStepf weights, const int x, const int y, const int nfeatures)
|
||||
{
|
||||
float total = 0.0f;
|
||||
for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
|
||||
total += weights(fy, x);
|
||||
|
||||
if (total != 0.0f)
|
||||
{
|
||||
for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
|
||||
weights(fy, x) /= total;
|
||||
}
|
||||
}
|
||||
|
||||
__device__ bool insertFeature(const int color, const float weight, PtrStepi colors, PtrStepf weights, const int x, const int y, int& nfeatures)
|
||||
{
|
||||
for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
|
||||
{
|
||||
if (color == colors(fy, x))
|
||||
{
|
||||
// feature in histogram
|
||||
|
||||
weights(fy, x) += weight;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (nfeatures == c_maxFeatures)
|
||||
{
|
||||
// discard oldest feature
|
||||
|
||||
int idx = -1;
|
||||
float minVal = numeric_limits<float>::max();
|
||||
for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
|
||||
{
|
||||
const float w = weights(fy, x);
|
||||
if (w < minVal)
|
||||
{
|
||||
minVal = w;
|
||||
idx = fy;
|
||||
}
|
||||
}
|
||||
|
||||
colors(idx, x) = color;
|
||||
weights(idx, x) = weight;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
colors(nfeatures * c_height + y, x) = color;
|
||||
weights(nfeatures * c_height + y, x) = weight;
|
||||
|
||||
++nfeatures;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <int cn> struct Quantization
|
||||
{
|
||||
template <typename T>
|
||||
__device__ static int apply(const T& val)
|
||||
{
|
||||
int res = 0;
|
||||
res |= static_cast<int>((val.x - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal));
|
||||
res |= static_cast<int>((val.y - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal)) << 8;
|
||||
res |= static_cast<int>((val.z - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal)) << 16;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct Quantization<1>
|
||||
{
|
||||
template <typename T>
|
||||
__device__ static int apply(T val)
|
||||
{
|
||||
return static_cast<int>((val - c_minVal) * c_quantizationLevels / (c_maxVal - c_minVal));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T> struct Quantization : detail::Quantization<VecTraits<T>::cn> {};
|
||||
|
||||
template <typename SrcT>
|
||||
__global__ void update(const PtrStep<SrcT> frame, PtrStepb fgmask, PtrStepi colors_, PtrStepf weights_, PtrStepi nfeatures_,
|
||||
const int frameNum, const float learningRate, const bool updateBackgroundModel)
|
||||
{
|
||||
const int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
const int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
|
||||
if (x >= c_width || y >= c_height)
|
||||
return;
|
||||
|
||||
const SrcT pix = frame(y, x);
|
||||
const int newFeatureColor = Quantization<SrcT>::apply(pix);
|
||||
|
||||
int nfeatures = nfeatures_(y, x);
|
||||
|
||||
if (frameNum >= c_numInitializationFrames)
|
||||
{
|
||||
// typical operation
|
||||
|
||||
const float weight = findFeature(newFeatureColor, colors_, weights_, x, y, nfeatures);
|
||||
|
||||
// see Godbehere, Matsukawa, Goldberg (2012) for reasoning behind this implementation of Bayes rule
|
||||
const float posterior = (weight * c_backgroundPrior) / (weight * c_backgroundPrior + (1.0f - weight) * (1.0f - c_backgroundPrior));
|
||||
|
||||
const bool isForeground = ((1.0f - posterior) > c_decisionThreshold);
|
||||
fgmask(y, x) = (uchar)(-isForeground);
|
||||
|
||||
// update histogram.
|
||||
|
||||
if (updateBackgroundModel)
|
||||
{
|
||||
for (int i = 0, fy = y; i < nfeatures; ++i, fy += c_height)
|
||||
weights_(fy, x) *= 1.0f - learningRate;
|
||||
|
||||
bool inserted = insertFeature(newFeatureColor, learningRate, colors_, weights_, x, y, nfeatures);
|
||||
|
||||
if (inserted)
|
||||
{
|
||||
normalizeHistogram(weights_, x, y, nfeatures);
|
||||
nfeatures_(y, x) = nfeatures;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (updateBackgroundModel)
|
||||
{
|
||||
// training-mode update
|
||||
|
||||
insertFeature(newFeatureColor, 1.0f, colors_, weights_, x, y, nfeatures);
|
||||
|
||||
if (frameNum == c_numInitializationFrames - 1)
|
||||
normalizeHistogram(weights_, x, y, nfeatures);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SrcT>
|
||||
void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures,
|
||||
int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream)
|
||||
{
|
||||
const dim3 block(32, 8);
|
||||
const dim3 grid(divUp(frame.cols, block.x), divUp(frame.rows, block.y));
|
||||
|
||||
cudaSafeCall( cudaFuncSetCacheConfig(update<SrcT>, cudaFuncCachePreferL1) );
|
||||
|
||||
update<SrcT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>) frame, fgmask, colors, weights, nfeatures, frameNum, learningRate, updateBackgroundModel);
|
||||
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
if (stream == 0)
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
}
|
||||
|
||||
template void update_gpu<uchar >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
template void update_gpu<uchar3 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
template void update_gpu<uchar4 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
|
||||
template void update_gpu<ushort >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
template void update_gpu<ushort3>(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
template void update_gpu<ushort4>(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
|
||||
template void update_gpu<float >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
template void update_gpu<float3 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
template void update_gpu<float4 >(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
}
|
||||
}}}
|
||||
|
||||
|
||||
#endif /* CUDA_DISABLER */
|
||||
@@ -0,0 +1,729 @@
|
||||
/*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) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// 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 materials 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 "precomp.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::cuda;
|
||||
|
||||
#if !defined(HAVE_CUDA) || defined(CUDA_DISABLER) || !defined(HAVE_OPENCV_IMGPROC) || !defined(HAVE_OPENCV_CUDAARITHM) || !defined(HAVE_OPENCV_CUDAIMGPROC)
|
||||
|
||||
cv::cuda::FGDParams::FGDParams() { throw_no_cuda(); }
|
||||
|
||||
Ptr<cuda::BackgroundSubtractorFGD> cv::cuda::createBackgroundSubtractorFGD(const FGDParams&) { throw_no_cuda(); return Ptr<cuda::BackgroundSubtractorFGD>(); }
|
||||
|
||||
#else
|
||||
|
||||
#include "cuda/fgd.hpp"
|
||||
#include "opencv2/imgproc/imgproc_c.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// FGDParams
|
||||
|
||||
namespace
|
||||
{
|
||||
// Default parameters of foreground detection algorithm:
|
||||
const int BGFG_FGD_LC = 128;
|
||||
const int BGFG_FGD_N1C = 15;
|
||||
const int BGFG_FGD_N2C = 25;
|
||||
|
||||
const int BGFG_FGD_LCC = 64;
|
||||
const int BGFG_FGD_N1CC = 25;
|
||||
const int BGFG_FGD_N2CC = 40;
|
||||
|
||||
// Background reference image update parameter:
|
||||
const float BGFG_FGD_ALPHA_1 = 0.1f;
|
||||
|
||||
// stat model update parameter
|
||||
// 0.002f ~ 1K frame(~45sec), 0.005 ~ 18sec (if 25fps and absolutely static BG)
|
||||
const float BGFG_FGD_ALPHA_2 = 0.005f;
|
||||
|
||||
// start value for alpha parameter (to fast initiate statistic model)
|
||||
const float BGFG_FGD_ALPHA_3 = 0.1f;
|
||||
|
||||
const float BGFG_FGD_DELTA = 2.0f;
|
||||
|
||||
const float BGFG_FGD_T = 0.9f;
|
||||
|
||||
const float BGFG_FGD_MINAREA= 15.0f;
|
||||
}
|
||||
|
||||
cv::cuda::FGDParams::FGDParams()
|
||||
{
|
||||
Lc = BGFG_FGD_LC;
|
||||
N1c = BGFG_FGD_N1C;
|
||||
N2c = BGFG_FGD_N2C;
|
||||
|
||||
Lcc = BGFG_FGD_LCC;
|
||||
N1cc = BGFG_FGD_N1CC;
|
||||
N2cc = BGFG_FGD_N2CC;
|
||||
|
||||
delta = BGFG_FGD_DELTA;
|
||||
|
||||
alpha1 = BGFG_FGD_ALPHA_1;
|
||||
alpha2 = BGFG_FGD_ALPHA_2;
|
||||
alpha3 = BGFG_FGD_ALPHA_3;
|
||||
|
||||
T = BGFG_FGD_T;
|
||||
minArea = BGFG_FGD_MINAREA;
|
||||
|
||||
is_obj_without_holes = true;
|
||||
perform_morphing = 1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// copyChannels
|
||||
|
||||
namespace
|
||||
{
|
||||
void copyChannels(const GpuMat& src, GpuMat& dst, int dst_cn = -1)
|
||||
{
|
||||
const int src_cn = src.channels();
|
||||
|
||||
if (dst_cn < 0)
|
||||
dst_cn = src_cn;
|
||||
|
||||
cuda::ensureSizeIsEnough(src.size(), CV_MAKE_TYPE(src.depth(), dst_cn), dst);
|
||||
|
||||
if (src_cn == dst_cn)
|
||||
{
|
||||
src.copyTo(dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
static const int cvt_codes[4][4] =
|
||||
{
|
||||
{-1, -1, COLOR_GRAY2BGR, COLOR_GRAY2BGRA},
|
||||
{-1, -1, -1, -1},
|
||||
{COLOR_BGR2GRAY, -1, -1, COLOR_BGR2BGRA},
|
||||
{COLOR_BGRA2GRAY, -1, COLOR_BGRA2BGR, -1}
|
||||
};
|
||||
|
||||
const int cvt_code = cvt_codes[src_cn - 1][dst_cn - 1];
|
||||
CV_DbgAssert( cvt_code >= 0 );
|
||||
|
||||
cuda::cvtColor(src, dst, cvt_code, dst_cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// changeDetection
|
||||
|
||||
namespace
|
||||
{
|
||||
void calcDiffHistogram(const GpuMat& prevFrame, const GpuMat& curFrame, GpuMat& hist, GpuMat& histBuf)
|
||||
{
|
||||
typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame,
|
||||
unsigned int* hist0, unsigned int* hist1, unsigned int* hist2,
|
||||
unsigned int* partialBuf0, unsigned int* partialBuf1, unsigned int* partialBuf2,
|
||||
bool cc20, cudaStream_t stream);
|
||||
static const func_t funcs[4][4] =
|
||||
{
|
||||
{0,0,0,0},
|
||||
{0,0,0,0},
|
||||
{0,0,fgd::calcDiffHistogram_gpu<uchar3, uchar3>,fgd::calcDiffHistogram_gpu<uchar3, uchar4>},
|
||||
{0,0,fgd::calcDiffHistogram_gpu<uchar4, uchar3>,fgd::calcDiffHistogram_gpu<uchar4, uchar4>}
|
||||
};
|
||||
|
||||
hist.create(3, 256, CV_32SC1);
|
||||
histBuf.create(3, fgd::PARTIAL_HISTOGRAM_COUNT * fgd::HISTOGRAM_BIN_COUNT, CV_32SC1);
|
||||
|
||||
funcs[prevFrame.channels() - 1][curFrame.channels() - 1](
|
||||
prevFrame, curFrame,
|
||||
hist.ptr<unsigned int>(0), hist.ptr<unsigned int>(1), hist.ptr<unsigned int>(2),
|
||||
histBuf.ptr<unsigned int>(0), histBuf.ptr<unsigned int>(1), histBuf.ptr<unsigned int>(2),
|
||||
deviceSupports(FEATURE_SET_COMPUTE_20), 0);
|
||||
}
|
||||
|
||||
void calcRelativeVariance(unsigned int hist[3 * 256], double relativeVariance[3][fgd::HISTOGRAM_BIN_COUNT])
|
||||
{
|
||||
std::memset(relativeVariance, 0, 3 * fgd::HISTOGRAM_BIN_COUNT * sizeof(double));
|
||||
|
||||
for (int thres = fgd::HISTOGRAM_BIN_COUNT - 2; thres >= 0; --thres)
|
||||
{
|
||||
Vec3d sum(0.0, 0.0, 0.0);
|
||||
Vec3d sqsum(0.0, 0.0, 0.0);
|
||||
Vec3i count(0, 0, 0);
|
||||
|
||||
for (int j = thres; j < fgd::HISTOGRAM_BIN_COUNT; ++j)
|
||||
{
|
||||
sum[0] += static_cast<double>(j) * hist[j];
|
||||
sqsum[0] += static_cast<double>(j * j) * hist[j];
|
||||
count[0] += hist[j];
|
||||
|
||||
sum[1] += static_cast<double>(j) * hist[j + 256];
|
||||
sqsum[1] += static_cast<double>(j * j) * hist[j + 256];
|
||||
count[1] += hist[j + 256];
|
||||
|
||||
sum[2] += static_cast<double>(j) * hist[j + 512];
|
||||
sqsum[2] += static_cast<double>(j * j) * hist[j + 512];
|
||||
count[2] += hist[j + 512];
|
||||
}
|
||||
|
||||
count[0] = std::max(count[0], 1);
|
||||
count[1] = std::max(count[1], 1);
|
||||
count[2] = std::max(count[2], 1);
|
||||
|
||||
Vec3d my(
|
||||
sum[0] / count[0],
|
||||
sum[1] / count[1],
|
||||
sum[2] / count[2]
|
||||
);
|
||||
|
||||
relativeVariance[0][thres] = std::sqrt(sqsum[0] / count[0] - my[0] * my[0]);
|
||||
relativeVariance[1][thres] = std::sqrt(sqsum[1] / count[1] - my[1] * my[1]);
|
||||
relativeVariance[2][thres] = std::sqrt(sqsum[2] / count[2] - my[2] * my[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void calcDiffThreshMask(const GpuMat& prevFrame, const GpuMat& curFrame, Vec3d bestThres, GpuMat& changeMask)
|
||||
{
|
||||
typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame, uchar3 bestThres, PtrStepSzb changeMask, cudaStream_t stream);
|
||||
static const func_t funcs[4][4] =
|
||||
{
|
||||
{0,0,0,0},
|
||||
{0,0,0,0},
|
||||
{0,0,fgd::calcDiffThreshMask_gpu<uchar3, uchar3>,fgd::calcDiffThreshMask_gpu<uchar3, uchar4>},
|
||||
{0,0,fgd::calcDiffThreshMask_gpu<uchar4, uchar3>,fgd::calcDiffThreshMask_gpu<uchar4, uchar4>}
|
||||
};
|
||||
|
||||
changeMask.setTo(Scalar::all(0));
|
||||
|
||||
funcs[prevFrame.channels() - 1][curFrame.channels() - 1](prevFrame, curFrame,
|
||||
make_uchar3((uchar)bestThres[0], (uchar)bestThres[1], (uchar)bestThres[2]),
|
||||
changeMask, 0);
|
||||
}
|
||||
|
||||
// performs change detection for Foreground detection algorithm
|
||||
void changeDetection(const GpuMat& prevFrame, const GpuMat& curFrame, GpuMat& changeMask, GpuMat& hist, GpuMat& histBuf)
|
||||
{
|
||||
calcDiffHistogram(prevFrame, curFrame, hist, histBuf);
|
||||
|
||||
unsigned int histData[3 * 256];
|
||||
Mat h_hist(3, 256, CV_32SC1, histData);
|
||||
hist.download(h_hist);
|
||||
|
||||
double relativeVariance[3][fgd::HISTOGRAM_BIN_COUNT];
|
||||
calcRelativeVariance(histData, relativeVariance);
|
||||
|
||||
// Find maximum:
|
||||
Vec3d bestThres(10.0, 10.0, 10.0);
|
||||
for (int i = 0; i < fgd::HISTOGRAM_BIN_COUNT; ++i)
|
||||
{
|
||||
bestThres[0] = std::max(bestThres[0], relativeVariance[0][i]);
|
||||
bestThres[1] = std::max(bestThres[1], relativeVariance[1][i]);
|
||||
bestThres[2] = std::max(bestThres[2], relativeVariance[2][i]);
|
||||
}
|
||||
|
||||
calcDiffThreshMask(prevFrame, curFrame, bestThres, changeMask);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// bgfgClassification
|
||||
|
||||
namespace
|
||||
{
|
||||
int bgfgClassification(const GpuMat& prevFrame, const GpuMat& curFrame,
|
||||
const GpuMat& Ftd, const GpuMat& Fbd,
|
||||
GpuMat& foreground,
|
||||
const FGDParams& params, int out_cn)
|
||||
{
|
||||
typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd, PtrStepSzb foreground,
|
||||
int deltaC, int deltaCC, float alpha2, int N1c, int N1cc, cudaStream_t stream);
|
||||
static const func_t funcs[4][4][4] =
|
||||
{
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}
|
||||
},
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}
|
||||
},
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0},
|
||||
{0,0,fgd::bgfgClassification_gpu<uchar3, uchar3, uchar3>,fgd::bgfgClassification_gpu<uchar3, uchar3, uchar4>},
|
||||
{0,0,fgd::bgfgClassification_gpu<uchar3, uchar4, uchar3>,fgd::bgfgClassification_gpu<uchar3, uchar4, uchar4>}
|
||||
},
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0},
|
||||
{0,0,fgd::bgfgClassification_gpu<uchar4, uchar3, uchar3>,fgd::bgfgClassification_gpu<uchar4, uchar3, uchar4>},
|
||||
{0,0,fgd::bgfgClassification_gpu<uchar4, uchar4, uchar3>,fgd::bgfgClassification_gpu<uchar4, uchar4, uchar4>}
|
||||
}
|
||||
};
|
||||
|
||||
const int deltaC = cvRound(params.delta * 256 / params.Lc);
|
||||
const int deltaCC = cvRound(params.delta * 256 / params.Lcc);
|
||||
|
||||
funcs[prevFrame.channels() - 1][curFrame.channels() - 1][out_cn - 1](prevFrame, curFrame, Ftd, Fbd, foreground,
|
||||
deltaC, deltaCC, params.alpha2,
|
||||
params.N1c, params.N1cc, 0);
|
||||
|
||||
int count = cuda::countNonZero(foreground);
|
||||
|
||||
cuda::multiply(foreground, Scalar::all(255), foreground);
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// smoothForeground
|
||||
|
||||
#ifdef HAVE_OPENCV_CUDAFILTERS
|
||||
|
||||
namespace
|
||||
{
|
||||
void morphology(const GpuMat& src, GpuMat& dst, GpuMat& filterBrd, int brd, Ptr<cuda::Filter>& filter, Scalar brdVal)
|
||||
{
|
||||
cuda::copyMakeBorder(src, filterBrd, brd, brd, brd, brd, BORDER_CONSTANT, brdVal);
|
||||
filter->apply(filterBrd(Rect(brd, brd, src.cols, src.rows)), dst);
|
||||
}
|
||||
|
||||
void smoothForeground(GpuMat& foreground, GpuMat& filterBrd, GpuMat& buf,
|
||||
Ptr<cuda::Filter>& erodeFilter, Ptr<cuda::Filter>& dilateFilter,
|
||||
const FGDParams& params)
|
||||
{
|
||||
const int brd = params.perform_morphing;
|
||||
|
||||
const Scalar erodeBrdVal = Scalar::all(UCHAR_MAX);
|
||||
const Scalar dilateBrdVal = Scalar::all(0);
|
||||
|
||||
// MORPH_OPEN
|
||||
morphology(foreground, buf, filterBrd, brd, erodeFilter, erodeBrdVal);
|
||||
morphology(buf, foreground, filterBrd, brd, dilateFilter, dilateBrdVal);
|
||||
|
||||
// MORPH_CLOSE
|
||||
morphology(foreground, buf, filterBrd, brd, dilateFilter, dilateBrdVal);
|
||||
morphology(buf, foreground, filterBrd, brd, erodeFilter, erodeBrdVal);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// findForegroundRegions
|
||||
|
||||
namespace
|
||||
{
|
||||
void seqToContours(CvSeq* _ccontours, CvMemStorage* storage, OutputArrayOfArrays _contours)
|
||||
{
|
||||
Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
|
||||
|
||||
size_t total = all_contours.size();
|
||||
|
||||
_contours.create((int) total, 1, 0, -1, true);
|
||||
|
||||
SeqIterator<CvSeq*> it = all_contours.begin();
|
||||
for (size_t i = 0; i < total; ++i, ++it)
|
||||
{
|
||||
CvSeq* c = *it;
|
||||
((CvContour*)c)->color = (int)i;
|
||||
_contours.create((int)c->total, 1, CV_32SC2, (int)i, true);
|
||||
Mat ci = _contours.getMat((int)i);
|
||||
CV_Assert( ci.isContinuous() );
|
||||
cvCvtSeqToArray(c, ci.data);
|
||||
}
|
||||
}
|
||||
|
||||
int findForegroundRegions(GpuMat& d_foreground, Mat& h_foreground, std::vector< std::vector<Point> >& foreground_regions,
|
||||
CvMemStorage* storage, const FGDParams& params)
|
||||
{
|
||||
int region_count = 0;
|
||||
|
||||
// Discard under-size foreground regions:
|
||||
|
||||
d_foreground.download(h_foreground);
|
||||
IplImage ipl_foreground = h_foreground;
|
||||
CvSeq* first_seq = 0;
|
||||
|
||||
cvFindContours(&ipl_foreground, storage, &first_seq, sizeof(CvContour), CV_RETR_LIST);
|
||||
|
||||
for (CvSeq* seq = first_seq; seq; seq = seq->h_next)
|
||||
{
|
||||
CvContour* cnt = reinterpret_cast<CvContour*>(seq);
|
||||
|
||||
if (cnt->rect.width * cnt->rect.height < params.minArea || (params.is_obj_without_holes && CV_IS_SEQ_HOLE(seq)))
|
||||
{
|
||||
// Delete under-size contour:
|
||||
CvSeq* prev_seq = seq->h_prev;
|
||||
if (prev_seq)
|
||||
{
|
||||
prev_seq->h_next = seq->h_next;
|
||||
|
||||
if (seq->h_next)
|
||||
seq->h_next->h_prev = prev_seq;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_seq = seq->h_next;
|
||||
|
||||
if (seq->h_next)
|
||||
seq->h_next->h_prev = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
region_count++;
|
||||
}
|
||||
}
|
||||
|
||||
seqToContours(first_seq, storage, foreground_regions);
|
||||
h_foreground.setTo(0);
|
||||
|
||||
drawContours(h_foreground, foreground_regions, -1, Scalar::all(255), -1);
|
||||
|
||||
d_foreground.upload(h_foreground);
|
||||
|
||||
return region_count;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// updateBackgroundModel
|
||||
|
||||
namespace
|
||||
{
|
||||
void updateBackgroundModel(const GpuMat& prevFrame, const GpuMat& curFrame, const GpuMat& Ftd, const GpuMat& Fbd,
|
||||
const GpuMat& foreground, GpuMat& background,
|
||||
const FGDParams& params)
|
||||
{
|
||||
typedef void (*func_t)(PtrStepSzb prevFrame, PtrStepSzb curFrame, PtrStepSzb Ftd, PtrStepSzb Fbd,
|
||||
PtrStepSzb foreground, PtrStepSzb background,
|
||||
int deltaC, int deltaCC, float alpha1, float alpha2, float alpha3, int N1c, int N1cc, int N2c, int N2cc, float T, cudaStream_t stream);
|
||||
static const func_t funcs[4][4][4] =
|
||||
{
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}
|
||||
},
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}
|
||||
},
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0},
|
||||
{0,0,fgd::updateBackgroundModel_gpu<uchar3, uchar3, uchar3>,fgd::updateBackgroundModel_gpu<uchar3, uchar3, uchar4>},
|
||||
{0,0,fgd::updateBackgroundModel_gpu<uchar3, uchar4, uchar3>,fgd::updateBackgroundModel_gpu<uchar3, uchar4, uchar4>}
|
||||
},
|
||||
{
|
||||
{0,0,0,0}, {0,0,0,0},
|
||||
{0,0,fgd::updateBackgroundModel_gpu<uchar4, uchar3, uchar3>,fgd::updateBackgroundModel_gpu<uchar4, uchar3, uchar4>},
|
||||
{0,0,fgd::updateBackgroundModel_gpu<uchar4, uchar4, uchar3>,fgd::updateBackgroundModel_gpu<uchar4, uchar4, uchar4>}
|
||||
}
|
||||
};
|
||||
|
||||
const int deltaC = cvRound(params.delta * 256 / params.Lc);
|
||||
const int deltaCC = cvRound(params.delta * 256 / params.Lcc);
|
||||
|
||||
funcs[prevFrame.channels() - 1][curFrame.channels() - 1][background.channels() - 1](
|
||||
prevFrame, curFrame, Ftd, Fbd, foreground, background,
|
||||
deltaC, deltaCC, params.alpha1, params.alpha2, params.alpha3,
|
||||
params.N1c, params.N1cc, params.N2c, params.N2cc, params.T,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
class BGPixelStat
|
||||
{
|
||||
public:
|
||||
void create(Size size, const FGDParams& params);
|
||||
|
||||
void setTrained();
|
||||
|
||||
operator fgd::BGPixelStat();
|
||||
|
||||
private:
|
||||
GpuMat Pbc_;
|
||||
GpuMat Pbcc_;
|
||||
GpuMat is_trained_st_model_;
|
||||
GpuMat is_trained_dyn_model_;
|
||||
|
||||
GpuMat ctable_Pv_;
|
||||
GpuMat ctable_Pvb_;
|
||||
GpuMat ctable_v_;
|
||||
|
||||
GpuMat cctable_Pv_;
|
||||
GpuMat cctable_Pvb_;
|
||||
GpuMat cctable_v1_;
|
||||
GpuMat cctable_v2_;
|
||||
};
|
||||
|
||||
void BGPixelStat::create(Size size, const FGDParams& params)
|
||||
{
|
||||
cuda::ensureSizeIsEnough(size, CV_32FC1, Pbc_);
|
||||
Pbc_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(size, CV_32FC1, Pbcc_);
|
||||
Pbcc_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(size, CV_8UC1, is_trained_st_model_);
|
||||
is_trained_st_model_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(size, CV_8UC1, is_trained_dyn_model_);
|
||||
is_trained_dyn_model_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_32FC1, ctable_Pv_);
|
||||
ctable_Pv_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_32FC1, ctable_Pvb_);
|
||||
ctable_Pvb_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(params.N2c * size.height, size.width, CV_8UC4, ctable_v_);
|
||||
ctable_v_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_32FC1, cctable_Pv_);
|
||||
cctable_Pv_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_32FC1, cctable_Pvb_);
|
||||
cctable_Pvb_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_8UC4, cctable_v1_);
|
||||
cctable_v1_.setTo(Scalar::all(0));
|
||||
|
||||
cuda::ensureSizeIsEnough(params.N2cc * size.height, size.width, CV_8UC4, cctable_v2_);
|
||||
cctable_v2_.setTo(Scalar::all(0));
|
||||
}
|
||||
|
||||
void BGPixelStat::setTrained()
|
||||
{
|
||||
is_trained_st_model_.setTo(Scalar::all(1));
|
||||
is_trained_dyn_model_.setTo(Scalar::all(1));
|
||||
}
|
||||
|
||||
BGPixelStat::operator fgd::BGPixelStat()
|
||||
{
|
||||
fgd::BGPixelStat stat;
|
||||
|
||||
stat.rows_ = Pbc_.rows;
|
||||
|
||||
stat.Pbc_data_ = Pbc_.data;
|
||||
stat.Pbc_step_ = Pbc_.step;
|
||||
|
||||
stat.Pbcc_data_ = Pbcc_.data;
|
||||
stat.Pbcc_step_ = Pbcc_.step;
|
||||
|
||||
stat.is_trained_st_model_data_ = is_trained_st_model_.data;
|
||||
stat.is_trained_st_model_step_ = is_trained_st_model_.step;
|
||||
|
||||
stat.is_trained_dyn_model_data_ = is_trained_dyn_model_.data;
|
||||
stat.is_trained_dyn_model_step_ = is_trained_dyn_model_.step;
|
||||
|
||||
stat.ctable_Pv_data_ = ctable_Pv_.data;
|
||||
stat.ctable_Pv_step_ = ctable_Pv_.step;
|
||||
|
||||
stat.ctable_Pvb_data_ = ctable_Pvb_.data;
|
||||
stat.ctable_Pvb_step_ = ctable_Pvb_.step;
|
||||
|
||||
stat.ctable_v_data_ = ctable_v_.data;
|
||||
stat.ctable_v_step_ = ctable_v_.step;
|
||||
|
||||
stat.cctable_Pv_data_ = cctable_Pv_.data;
|
||||
stat.cctable_Pv_step_ = cctable_Pv_.step;
|
||||
|
||||
stat.cctable_Pvb_data_ = cctable_Pvb_.data;
|
||||
stat.cctable_Pvb_step_ = cctable_Pvb_.step;
|
||||
|
||||
stat.cctable_v1_data_ = cctable_v1_.data;
|
||||
stat.cctable_v1_step_ = cctable_v1_.step;
|
||||
|
||||
stat.cctable_v2_data_ = cctable_v2_.data;
|
||||
stat.cctable_v2_step_ = cctable_v2_.step;
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
class FGDImpl : public cuda::BackgroundSubtractorFGD
|
||||
{
|
||||
public:
|
||||
explicit FGDImpl(const FGDParams& params);
|
||||
~FGDImpl();
|
||||
|
||||
void apply(InputArray image, OutputArray fgmask, double learningRate=-1);
|
||||
|
||||
void getBackgroundImage(OutputArray backgroundImage) const;
|
||||
|
||||
void getForegroundRegions(OutputArrayOfArrays foreground_regions);
|
||||
|
||||
private:
|
||||
void initialize(const GpuMat& firstFrame);
|
||||
|
||||
FGDParams params_;
|
||||
Size frameSize_;
|
||||
|
||||
GpuMat background_;
|
||||
GpuMat foreground_;
|
||||
std::vector< std::vector<Point> > foreground_regions_;
|
||||
|
||||
Mat h_foreground_;
|
||||
|
||||
GpuMat prevFrame_;
|
||||
GpuMat Ftd_;
|
||||
GpuMat Fbd_;
|
||||
BGPixelStat stat_;
|
||||
|
||||
GpuMat hist_;
|
||||
GpuMat histBuf_;
|
||||
|
||||
GpuMat buf_;
|
||||
GpuMat filterBrd_;
|
||||
|
||||
#ifdef HAVE_OPENCV_CUDAFILTERS
|
||||
Ptr<cuda::Filter> dilateFilter_;
|
||||
Ptr<cuda::Filter> erodeFilter_;
|
||||
#endif
|
||||
|
||||
CvMemStorage* storage_;
|
||||
};
|
||||
|
||||
FGDImpl::FGDImpl(const FGDParams& params) : params_(params), frameSize_(0, 0)
|
||||
{
|
||||
storage_ = cvCreateMemStorage();
|
||||
CV_Assert( storage_ != 0 );
|
||||
}
|
||||
|
||||
FGDImpl::~FGDImpl()
|
||||
{
|
||||
cvReleaseMemStorage(&storage_);
|
||||
}
|
||||
|
||||
void FGDImpl::apply(InputArray _frame, OutputArray fgmask, double)
|
||||
{
|
||||
GpuMat curFrame = _frame.getGpuMat();
|
||||
|
||||
if (curFrame.size() != frameSize_)
|
||||
{
|
||||
initialize(curFrame);
|
||||
return;
|
||||
}
|
||||
|
||||
CV_Assert( curFrame.type() == CV_8UC3 || curFrame.type() == CV_8UC4 );
|
||||
CV_Assert( curFrame.size() == prevFrame_.size() );
|
||||
|
||||
cvClearMemStorage(storage_);
|
||||
foreground_regions_.clear();
|
||||
foreground_.setTo(Scalar::all(0));
|
||||
|
||||
changeDetection(prevFrame_, curFrame, Ftd_, hist_, histBuf_);
|
||||
changeDetection(background_, curFrame, Fbd_, hist_, histBuf_);
|
||||
|
||||
int FG_pixels_count = bgfgClassification(prevFrame_, curFrame, Ftd_, Fbd_, foreground_, params_, 4);
|
||||
|
||||
#ifdef HAVE_OPENCV_CUDAFILTERS
|
||||
if (params_.perform_morphing > 0)
|
||||
smoothForeground(foreground_, filterBrd_, buf_, erodeFilter_, dilateFilter_, params_);
|
||||
#endif
|
||||
|
||||
if (params_.minArea > 0 || params_.is_obj_without_holes)
|
||||
findForegroundRegions(foreground_, h_foreground_, foreground_regions_, storage_, params_);
|
||||
|
||||
// Check ALL BG update condition:
|
||||
const double BGFG_FGD_BG_UPDATE_TRESH = 0.5;
|
||||
if (static_cast<double>(FG_pixels_count) / Ftd_.size().area() > BGFG_FGD_BG_UPDATE_TRESH)
|
||||
stat_.setTrained();
|
||||
|
||||
updateBackgroundModel(prevFrame_, curFrame, Ftd_, Fbd_, foreground_, background_, params_);
|
||||
|
||||
copyChannels(curFrame, prevFrame_, 4);
|
||||
|
||||
foreground_.copyTo(fgmask);
|
||||
}
|
||||
|
||||
void FGDImpl::getBackgroundImage(OutputArray backgroundImage) const
|
||||
{
|
||||
cuda::cvtColor(background_, backgroundImage, COLOR_BGRA2BGR);
|
||||
}
|
||||
|
||||
void FGDImpl::getForegroundRegions(OutputArrayOfArrays dst)
|
||||
{
|
||||
size_t total = foreground_regions_.size();
|
||||
|
||||
dst.create((int) total, 1, 0, -1, true);
|
||||
|
||||
for (size_t i = 0; i < total; ++i)
|
||||
{
|
||||
std::vector<Point>& c = foreground_regions_[i];
|
||||
|
||||
dst.create((int) c.size(), 1, CV_32SC2, (int) i, true);
|
||||
Mat ci = dst.getMat((int) i);
|
||||
|
||||
Mat(ci.size(), ci.type(), &c[0]).copyTo(ci);
|
||||
}
|
||||
}
|
||||
|
||||
void FGDImpl::initialize(const GpuMat& firstFrame)
|
||||
{
|
||||
CV_Assert( firstFrame.type() == CV_8UC3 || firstFrame.type() == CV_8UC4 );
|
||||
|
||||
frameSize_ = firstFrame.size();
|
||||
|
||||
cuda::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, foreground_);
|
||||
|
||||
copyChannels(firstFrame, background_, 4);
|
||||
copyChannels(firstFrame, prevFrame_, 4);
|
||||
|
||||
cuda::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, Ftd_);
|
||||
cuda::ensureSizeIsEnough(firstFrame.size(), CV_8UC1, Fbd_);
|
||||
|
||||
stat_.create(firstFrame.size(), params_);
|
||||
fgd::setBGPixelStat(stat_);
|
||||
|
||||
#ifdef HAVE_OPENCV_CUDAFILTERS
|
||||
if (params_.perform_morphing > 0)
|
||||
{
|
||||
Mat kernel = getStructuringElement(MORPH_RECT, Size(1 + params_.perform_morphing * 2, 1 + params_.perform_morphing * 2));
|
||||
Point anchor(params_.perform_morphing, params_.perform_morphing);
|
||||
|
||||
dilateFilter_ = cuda::createMorphologyFilter(MORPH_DILATE, CV_8UC1, kernel, anchor);
|
||||
erodeFilter_ = cuda::createMorphologyFilter(MORPH_ERODE, CV_8UC1, kernel, anchor);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<cuda::BackgroundSubtractorFGD> cv::cuda::createBackgroundSubtractorFGD(const FGDParams& params)
|
||||
{
|
||||
return makePtr<FGDImpl>(params);
|
||||
}
|
||||
|
||||
#endif // HAVE_CUDA
|
||||
@@ -0,0 +1,277 @@
|
||||
/*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) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// 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 materials 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 "precomp.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::cuda;
|
||||
|
||||
#if !defined HAVE_CUDA || defined(CUDA_DISABLER)
|
||||
|
||||
Ptr<cuda::BackgroundSubtractorGMG> cv::cuda::createBackgroundSubtractorGMG(int, double) { throw_no_cuda(); return Ptr<cuda::BackgroundSubtractorGMG>(); }
|
||||
|
||||
#else
|
||||
|
||||
namespace cv { namespace cuda { namespace device {
|
||||
namespace gmg
|
||||
{
|
||||
void loadConstants(int width, int height, float minVal, float maxVal, int quantizationLevels, float backgroundPrior,
|
||||
float decisionThreshold, int maxFeatures, int numInitializationFrames);
|
||||
|
||||
template <typename SrcT>
|
||||
void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures,
|
||||
int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
}
|
||||
}}}
|
||||
|
||||
namespace
|
||||
{
|
||||
class GMGImpl : public cuda::BackgroundSubtractorGMG
|
||||
{
|
||||
public:
|
||||
GMGImpl(int initializationFrames, double decisionThreshold);
|
||||
|
||||
void apply(InputArray image, OutputArray fgmask, double learningRate=-1);
|
||||
void apply(InputArray image, OutputArray fgmask, double learningRate, Stream& stream);
|
||||
|
||||
void getBackgroundImage(OutputArray backgroundImage) const;
|
||||
|
||||
int getMaxFeatures() const { return maxFeatures_; }
|
||||
void setMaxFeatures(int maxFeatures) { maxFeatures_ = maxFeatures; }
|
||||
|
||||
double getDefaultLearningRate() const { return learningRate_; }
|
||||
void setDefaultLearningRate(double lr) { learningRate_ = (float) lr; }
|
||||
|
||||
int getNumFrames() const { return numInitializationFrames_; }
|
||||
void setNumFrames(int nframes) { numInitializationFrames_ = nframes; }
|
||||
|
||||
int getQuantizationLevels() const { return quantizationLevels_; }
|
||||
void setQuantizationLevels(int nlevels) { quantizationLevels_ = nlevels; }
|
||||
|
||||
double getBackgroundPrior() const { return backgroundPrior_; }
|
||||
void setBackgroundPrior(double bgprior) { backgroundPrior_ = (float) bgprior; }
|
||||
|
||||
int getSmoothingRadius() const { return smoothingRadius_; }
|
||||
void setSmoothingRadius(int radius) { smoothingRadius_ = radius; }
|
||||
|
||||
double getDecisionThreshold() const { return decisionThreshold_; }
|
||||
void setDecisionThreshold(double thresh) { decisionThreshold_ = (float) thresh; }
|
||||
|
||||
bool getUpdateBackgroundModel() const { return updateBackgroundModel_; }
|
||||
void setUpdateBackgroundModel(bool update) { updateBackgroundModel_ = update; }
|
||||
|
||||
double getMinVal() const { return minVal_; }
|
||||
void setMinVal(double val) { minVal_ = (float) val; }
|
||||
|
||||
double getMaxVal() const { return maxVal_; }
|
||||
void setMaxVal(double val) { maxVal_ = (float) val; }
|
||||
|
||||
private:
|
||||
void initialize(Size frameSize, float min, float max);
|
||||
|
||||
//! Total number of distinct colors to maintain in histogram.
|
||||
int maxFeatures_;
|
||||
|
||||
//! Set between 0.0 and 1.0, determines how quickly features are "forgotten" from histograms.
|
||||
float learningRate_;
|
||||
|
||||
//! Number of frames of video to use to initialize histograms.
|
||||
int numInitializationFrames_;
|
||||
|
||||
//! Number of discrete levels in each channel to be used in histograms.
|
||||
int quantizationLevels_;
|
||||
|
||||
//! Prior probability that any given pixel is a background pixel. A sensitivity parameter.
|
||||
float backgroundPrior_;
|
||||
|
||||
//! Smoothing radius, in pixels, for cleaning up FG image.
|
||||
int smoothingRadius_;
|
||||
|
||||
//! Value above which pixel is determined to be FG.
|
||||
float decisionThreshold_;
|
||||
|
||||
//! Perform background model update.
|
||||
bool updateBackgroundModel_;
|
||||
|
||||
float minVal_, maxVal_;
|
||||
|
||||
Size frameSize_;
|
||||
int frameNum_;
|
||||
|
||||
GpuMat nfeatures_;
|
||||
GpuMat colors_;
|
||||
GpuMat weights_;
|
||||
|
||||
#if defined(HAVE_OPENCV_CUDAFILTERS) && defined(HAVE_OPENCV_CUDAARITHM)
|
||||
Ptr<cuda::Filter> boxFilter_;
|
||||
GpuMat buf_;
|
||||
#endif
|
||||
};
|
||||
|
||||
GMGImpl::GMGImpl(int initializationFrames, double decisionThreshold)
|
||||
{
|
||||
maxFeatures_ = 64;
|
||||
learningRate_ = 0.025f;
|
||||
numInitializationFrames_ = initializationFrames;
|
||||
quantizationLevels_ = 16;
|
||||
backgroundPrior_ = 0.8f;
|
||||
decisionThreshold_ = (float) decisionThreshold;
|
||||
smoothingRadius_ = 7;
|
||||
updateBackgroundModel_ = true;
|
||||
minVal_ = maxVal_ = 0;
|
||||
}
|
||||
|
||||
void GMGImpl::apply(InputArray image, OutputArray fgmask, double learningRate)
|
||||
{
|
||||
apply(image, fgmask, learningRate, Stream::Null());
|
||||
}
|
||||
|
||||
void GMGImpl::apply(InputArray _frame, OutputArray _fgmask, double newLearningRate, Stream& stream)
|
||||
{
|
||||
using namespace cv::cuda::device::gmg;
|
||||
|
||||
typedef void (*func_t)(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures,
|
||||
int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream);
|
||||
static const func_t funcs[6][4] =
|
||||
{
|
||||
{update_gpu<uchar>, 0, update_gpu<uchar3>, update_gpu<uchar4>},
|
||||
{0,0,0,0},
|
||||
{update_gpu<ushort>, 0, update_gpu<ushort3>, update_gpu<ushort4>},
|
||||
{0,0,0,0},
|
||||
{0,0,0,0},
|
||||
{update_gpu<float>, 0, update_gpu<float3>, update_gpu<float4>}
|
||||
};
|
||||
|
||||
GpuMat frame = _frame.getGpuMat();
|
||||
|
||||
CV_Assert( frame.depth() == CV_8U || frame.depth() == CV_16U || frame.depth() == CV_32F );
|
||||
CV_Assert( frame.channels() == 1 || frame.channels() == 3 || frame.channels() == 4 );
|
||||
|
||||
if (newLearningRate != -1.0)
|
||||
{
|
||||
CV_Assert( newLearningRate >= 0.0 && newLearningRate <= 1.0 );
|
||||
learningRate_ = (float) newLearningRate;
|
||||
}
|
||||
|
||||
if (frame.size() != frameSize_)
|
||||
{
|
||||
double minVal = minVal_;
|
||||
double maxVal = maxVal_;
|
||||
|
||||
if (minVal_ == 0 && maxVal_ == 0)
|
||||
{
|
||||
minVal = 0;
|
||||
maxVal = frame.depth() == CV_8U ? 255.0 : frame.depth() == CV_16U ? std::numeric_limits<ushort>::max() : 1.0;
|
||||
}
|
||||
|
||||
initialize(frame.size(), (float) minVal, (float) maxVal);
|
||||
}
|
||||
|
||||
_fgmask.create(frameSize_, CV_8UC1);
|
||||
GpuMat fgmask = _fgmask.getGpuMat();
|
||||
|
||||
fgmask.setTo(Scalar::all(0), stream);
|
||||
|
||||
funcs[frame.depth()][frame.channels() - 1](frame, fgmask, colors_, weights_, nfeatures_, frameNum_,
|
||||
learningRate_, updateBackgroundModel_, StreamAccessor::getStream(stream));
|
||||
|
||||
#if defined(HAVE_OPENCV_CUDAFILTERS) && defined(HAVE_OPENCV_CUDAARITHM)
|
||||
// medianBlur
|
||||
if (smoothingRadius_ > 0)
|
||||
{
|
||||
boxFilter_->apply(fgmask, buf_, stream);
|
||||
const int minCount = (smoothingRadius_ * smoothingRadius_ + 1) / 2;
|
||||
const double thresh = 255.0 * minCount / (smoothingRadius_ * smoothingRadius_);
|
||||
cuda::threshold(buf_, fgmask, thresh, 255.0, THRESH_BINARY, stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
// keep track of how many frames we have processed
|
||||
++frameNum_;
|
||||
}
|
||||
|
||||
void GMGImpl::getBackgroundImage(OutputArray backgroundImage) const
|
||||
{
|
||||
(void) backgroundImage;
|
||||
CV_Error(Error::StsNotImplemented, "Not implemented");
|
||||
}
|
||||
|
||||
void GMGImpl::initialize(Size frameSize, float min, float max)
|
||||
{
|
||||
using namespace cv::cuda::device::gmg;
|
||||
|
||||
CV_Assert( maxFeatures_ > 0 );
|
||||
CV_Assert( learningRate_ >= 0.0f && learningRate_ <= 1.0f);
|
||||
CV_Assert( numInitializationFrames_ >= 1);
|
||||
CV_Assert( quantizationLevels_ >= 1 && quantizationLevels_ <= 255);
|
||||
CV_Assert( backgroundPrior_ >= 0.0f && backgroundPrior_ <= 1.0f);
|
||||
|
||||
minVal_ = min;
|
||||
maxVal_ = max;
|
||||
CV_Assert( minVal_ < maxVal_ );
|
||||
|
||||
frameSize_ = frameSize;
|
||||
|
||||
frameNum_ = 0;
|
||||
|
||||
nfeatures_.create(frameSize_, CV_32SC1);
|
||||
colors_.create(maxFeatures_ * frameSize_.height, frameSize_.width, CV_32SC1);
|
||||
weights_.create(maxFeatures_ * frameSize_.height, frameSize_.width, CV_32FC1);
|
||||
|
||||
nfeatures_.setTo(Scalar::all(0));
|
||||
|
||||
#if defined(HAVE_OPENCV_CUDAFILTERS) && defined(HAVE_OPENCV_CUDAARITHM)
|
||||
if (smoothingRadius_ > 0)
|
||||
boxFilter_ = cuda::createBoxFilter(CV_8UC1, -1, Size(smoothingRadius_, smoothingRadius_));
|
||||
#endif
|
||||
|
||||
loadConstants(frameSize_.width, frameSize_.height, minVal_, maxVal_,
|
||||
quantizationLevels_, backgroundPrior_, decisionThreshold_, maxFeatures_, numInitializationFrames_);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<cuda::BackgroundSubtractorGMG> cv::cuda::createBackgroundSubtractorGMG(int initializationFrames, double decisionThreshold)
|
||||
{
|
||||
return makePtr<GMGImpl>(initializationFrames, decisionThreshold);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -56,6 +56,18 @@
|
||||
# include "opencv2/objdetect.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENCV_CUDAARITHM
|
||||
# include "opencv2/cudaarithm.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENCV_CUDAFILTERS
|
||||
# include "opencv2/cudafilters.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENCV_CUDAIMGPROC
|
||||
# include "opencv2/cudaimgproc.hpp"
|
||||
#endif
|
||||
|
||||
#include "opencv2/core/private.cuda.hpp"
|
||||
#include "opencv2/cudalegacy/private.hpp"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user