|
|
@ -47,393 +47,372 @@ |
|
|
|
#include "opencv2/core/cuda/vec_math.hpp" |
|
|
|
#include "opencv2/core/cuda/vec_math.hpp" |
|
|
|
#include "opencv2/core/cuda/limits.hpp" |
|
|
|
#include "opencv2/core/cuda/limits.hpp" |
|
|
|
|
|
|
|
|
|
|
|
namespace cv { namespace cuda { namespace device |
|
|
|
#include "mog2.hpp" |
|
|
|
{ |
|
|
|
|
|
|
|
namespace mog2 |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
// Utility |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__device__ __forceinline__ float cvt(uchar val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return val; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
__device__ __forceinline__ float3 cvt(const uchar3& val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return make_float3(val.x, val.y, val.z); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
__device__ __forceinline__ float4 cvt(const uchar4& val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return make_float4(val.x, val.y, val.z, val.w); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__device__ __forceinline__ float sqr(float val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return val * val; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
__device__ __forceinline__ float sqr(const float3& val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return val.x * val.x + val.y * val.y + val.z * val.z; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
__device__ __forceinline__ float sqr(const float4& val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return val.x * val.x + val.y * val.y + val.z * val.z; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__device__ __forceinline__ float sum(float val) |
|
|
|
namespace cv |
|
|
|
{ |
|
|
|
{ |
|
|
|
return val; |
|
|
|
namespace cuda |
|
|
|
} |
|
|
|
{ |
|
|
|
__device__ __forceinline__ float sum(const float3& val) |
|
|
|
namespace device |
|
|
|
{ |
|
|
|
{ |
|
|
|
return val.x + val.y + val.z; |
|
|
|
namespace mog2 |
|
|
|
} |
|
|
|
{ |
|
|
|
__device__ __forceinline__ float sum(const float4& val) |
|
|
|
/////////////////////////////////////////////////////////////// |
|
|
|
{ |
|
|
|
// Utility |
|
|
|
return val.x + val.y + val.z; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class Ptr2D> |
|
|
|
|
|
|
|
__device__ __forceinline__ void swap(Ptr2D& ptr, int x, int y, int k, int rows) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
typename Ptr2D::elem_type val = ptr(k * rows + y, x); |
|
|
|
|
|
|
|
ptr(k * rows + y, x) = ptr((k + 1) * rows + y, x); |
|
|
|
|
|
|
|
ptr((k + 1) * rows + y, x) = val; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
// MOG2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__constant__ int c_nmixtures; |
|
|
|
__device__ __forceinline__ float cvt(uchar val) |
|
|
|
__constant__ float c_Tb; |
|
|
|
{ |
|
|
|
__constant__ float c_TB; |
|
|
|
return val; |
|
|
|
__constant__ float c_Tg; |
|
|
|
} |
|
|
|
__constant__ float c_varInit; |
|
|
|
__device__ __forceinline__ float3 cvt(const uchar3 &val) |
|
|
|
__constant__ float c_varMin; |
|
|
|
{ |
|
|
|
__constant__ float c_varMax; |
|
|
|
return make_float3(val.x, val.y, val.z); |
|
|
|
__constant__ float c_tau; |
|
|
|
} |
|
|
|
__constant__ unsigned char c_shadowVal; |
|
|
|
__device__ __forceinline__ float4 cvt(const uchar4 &val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return make_float4(val.x, val.y, val.z, val.w); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void loadConstants(int nmixtures, float Tb, float TB, float Tg, float varInit, float varMin, float varMax, float tau, unsigned char shadowVal) |
|
|
|
__device__ __forceinline__ float sqr(float val) |
|
|
|
{ |
|
|
|
{ |
|
|
|
varMin = ::fminf(varMin, varMax); |
|
|
|
return val * val; |
|
|
|
varMax = ::fmaxf(varMin, varMax); |
|
|
|
} |
|
|
|
|
|
|
|
__device__ __forceinline__ float sqr(const float3 &val) |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_nmixtures, &nmixtures, sizeof(int)) ); |
|
|
|
{ |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_Tb, &Tb, sizeof(float)) ); |
|
|
|
return val.x * val.x + val.y * val.y + val.z * val.z; |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_TB, &TB, sizeof(float)) ); |
|
|
|
} |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_Tg, &Tg, sizeof(float)) ); |
|
|
|
__device__ __forceinline__ float sqr(const float4 &val) |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_varInit, &varInit, sizeof(float)) ); |
|
|
|
{ |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_varMin, &varMin, sizeof(float)) ); |
|
|
|
return val.x * val.x + val.y * val.y + val.z * val.z; |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_varMax, &varMax, sizeof(float)) ); |
|
|
|
} |
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_tau, &tau, sizeof(float)) ); |
|
|
|
|
|
|
|
cudaSafeCall( cudaMemcpyToSymbol(c_shadowVal, &shadowVal, sizeof(unsigned char)) ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <bool detectShadows, typename SrcT, typename WorkT> |
|
|
|
__device__ __forceinline__ float sum(float val) |
|
|
|
__global__ void mog2(const PtrStepSz<SrcT> frame, PtrStepb fgmask, PtrStepb modesUsed, |
|
|
|
{ |
|
|
|
PtrStepf gmm_weight, PtrStepf gmm_variance, PtrStep<WorkT> gmm_mean, |
|
|
|
return val; |
|
|
|
const float alphaT, const float alpha1, const float prune) |
|
|
|
} |
|
|
|
{ |
|
|
|
__device__ __forceinline__ float sum(const float3 &val) |
|
|
|
const int x = blockIdx.x * blockDim.x + threadIdx.x; |
|
|
|
{ |
|
|
|
const int y = blockIdx.y * blockDim.y + threadIdx.y; |
|
|
|
return val.x + val.y + val.z; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
__device__ __forceinline__ float sum(const float4 &val) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return val.x + val.y + val.z; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (x >= frame.cols || y >= frame.rows) |
|
|
|
template <class Ptr2D> |
|
|
|
return; |
|
|
|
__device__ __forceinline__ void swap(Ptr2D &ptr, int x, int y, int k, int rows) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
typename Ptr2D::elem_type val = ptr(k * rows + y, x); |
|
|
|
|
|
|
|
ptr(k * rows + y, x) = ptr((k + 1) * rows + y, x); |
|
|
|
|
|
|
|
ptr((k + 1) * rows + y, x) = val; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
// MOG2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <bool detectShadows, typename SrcT, typename WorkT> |
|
|
|
|
|
|
|
__global__ void mog2(const PtrStepSz<SrcT> frame, PtrStepb fgmask, PtrStepb modesUsed, |
|
|
|
|
|
|
|
PtrStepf gmm_weight, PtrStepf gmm_variance, PtrStep<WorkT> gmm_mean, |
|
|
|
|
|
|
|
const float alphaT, const float alpha1, const float prune, const Constants *const constants) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
const int x = blockIdx.x * blockDim.x + threadIdx.x; |
|
|
|
|
|
|
|
const int y = blockIdx.y * blockDim.y + threadIdx.y; |
|
|
|
|
|
|
|
|
|
|
|
WorkT pix = cvt(frame(y, x)); |
|
|
|
if (x < frame.cols && y < frame.rows) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
WorkT pix = cvt(frame(y, x)); |
|
|
|
|
|
|
|
|
|
|
|
//calculate distances to the modes (+ sort) |
|
|
|
//calculate distances to the modes (+ sort) |
|
|
|
//here we need to go in descending order!!! |
|
|
|
//here we need to go in descending order!!! |
|
|
|
|
|
|
|
|
|
|
|
bool background = false; // true - the pixel classified as background |
|
|
|
bool background = false; // true - the pixel classified as background |
|
|
|
|
|
|
|
|
|
|
|
//internal: |
|
|
|
//internal: |
|
|
|
|
|
|
|
|
|
|
|
bool fitsPDF = false; //if it remains zero a new GMM mode will be added |
|
|
|
bool fitsPDF = false; //if it remains zero a new GMM mode will be added |
|
|
|
|
|
|
|
|
|
|
|
int nmodes = modesUsed(y, x); |
|
|
|
int nmodes = modesUsed(y, x); |
|
|
|
int nNewModes = nmodes; //current number of modes in GMM |
|
|
|
const int nNewModes = nmodes; //current number of modes in GMM |
|
|
|
|
|
|
|
|
|
|
|
float totalWeight = 0.0f; |
|
|
|
float totalWeight = 0.0f; |
|
|
|
|
|
|
|
|
|
|
|
//go through all modes |
|
|
|
//go through all modes |
|
|
|
|
|
|
|
|
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//need only weight if fit is found |
|
|
|
|
|
|
|
float weight = alpha1 * gmm_weight(mode * frame.rows + y, x) + prune; |
|
|
|
|
|
|
|
int swap_count = 0; |
|
|
|
|
|
|
|
//fit not found yet |
|
|
|
|
|
|
|
if (!fitsPDF) |
|
|
|
{ |
|
|
|
{ |
|
|
|
//need only weight if fit is found |
|
|
|
//check if it belongs to some of the remaining modes |
|
|
|
float weight = alpha1 * gmm_weight(mode * frame.rows + y, x) + prune; |
|
|
|
const float var = gmm_variance(mode * frame.rows + y, x); |
|
|
|
int swap_count = 0; |
|
|
|
|
|
|
|
//fit not found yet |
|
|
|
|
|
|
|
if (!fitsPDF) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//check if it belongs to some of the remaining modes |
|
|
|
|
|
|
|
float var = gmm_variance(mode * frame.rows + y, x); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WorkT mean = gmm_mean(mode * frame.rows + y, x); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//calculate difference and distance |
|
|
|
const WorkT mean = gmm_mean(mode * frame.rows + y, x); |
|
|
|
WorkT diff = mean - pix; |
|
|
|
|
|
|
|
float dist2 = sqr(diff); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//background? - Tb - usually larger than Tg |
|
|
|
//calculate difference and distance |
|
|
|
if (totalWeight < c_TB && dist2 < c_Tb * var) |
|
|
|
const WorkT diff = mean - pix; |
|
|
|
background = true; |
|
|
|
const float dist2 = sqr(diff); |
|
|
|
|
|
|
|
|
|
|
|
//check fit |
|
|
|
//background? - Tb - usually larger than Tg |
|
|
|
if (dist2 < c_Tg * var) |
|
|
|
if (totalWeight < constants->TB_ && dist2 < constants->Tb_ * var) |
|
|
|
{ |
|
|
|
background = true; |
|
|
|
//belongs to the mode |
|
|
|
|
|
|
|
fitsPDF = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//update distribution |
|
|
|
//check fit |
|
|
|
|
|
|
|
if (dist2 < constants->Tg_ * var) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//belongs to the mode |
|
|
|
|
|
|
|
fitsPDF = true; |
|
|
|
|
|
|
|
|
|
|
|
//update weight |
|
|
|
//update distribution |
|
|
|
weight += alphaT; |
|
|
|
|
|
|
|
float k = alphaT / weight; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//update mean |
|
|
|
//update weight |
|
|
|
gmm_mean(mode * frame.rows + y, x) = mean - k * diff; |
|
|
|
weight += alphaT; |
|
|
|
|
|
|
|
float k = alphaT / weight; |
|
|
|
|
|
|
|
|
|
|
|
//update variance |
|
|
|
//update mean |
|
|
|
float varnew = var + k * (dist2 - var); |
|
|
|
gmm_mean(mode * frame.rows + y, x) = mean - k * diff; |
|
|
|
|
|
|
|
|
|
|
|
//limit the variance |
|
|
|
//update variance |
|
|
|
varnew = ::fmaxf(varnew, c_varMin); |
|
|
|
float varnew = var + k * (dist2 - var); |
|
|
|
varnew = ::fminf(varnew, c_varMax); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gmm_variance(mode * frame.rows + y, x) = varnew; |
|
|
|
//limit the variance |
|
|
|
|
|
|
|
varnew = ::fmaxf(varnew, constants->varMin_); |
|
|
|
|
|
|
|
varnew = ::fminf(varnew, constants->varMax_); |
|
|
|
|
|
|
|
|
|
|
|
//sort |
|
|
|
gmm_variance(mode * frame.rows + y, x) = varnew; |
|
|
|
//all other weights are at the same place and |
|
|
|
|
|
|
|
//only the matched (iModes) is higher -> just find the new place for it |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = mode; i > 0; --i) |
|
|
|
//sort |
|
|
|
{ |
|
|
|
//all other weights are at the same place and |
|
|
|
//check one up |
|
|
|
//only the matched (iModes) is higher -> just find the new place for it |
|
|
|
if (weight < gmm_weight((i - 1) * frame.rows + y, x)) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
swap_count++; |
|
|
|
for (int i = mode; i > 0; --i) |
|
|
|
//swap one up |
|
|
|
{ |
|
|
|
swap(gmm_weight, x, y, i - 1, frame.rows); |
|
|
|
//check one up |
|
|
|
swap(gmm_variance, x, y, i - 1, frame.rows); |
|
|
|
if (weight < gmm_weight((i - 1) * frame.rows + y, x)) |
|
|
|
swap(gmm_mean, x, y, i - 1, frame.rows); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//belongs to the mode - bFitsPDF becomes 1 |
|
|
|
swap_count++; |
|
|
|
|
|
|
|
//swap one up |
|
|
|
|
|
|
|
swap(gmm_weight, x, y, i - 1, frame.rows); |
|
|
|
|
|
|
|
swap(gmm_variance, x, y, i - 1, frame.rows); |
|
|
|
|
|
|
|
swap(gmm_mean, x, y, i - 1, frame.rows); |
|
|
|
} |
|
|
|
} |
|
|
|
} // !fitsPDF |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//check prune |
|
|
|
//belongs to the mode - bFitsPDF becomes 1 |
|
|
|
if (weight < -prune) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
weight = 0.0f; |
|
|
|
|
|
|
|
nmodes--; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} // !fitsPDF |
|
|
|
|
|
|
|
|
|
|
|
gmm_weight((mode - swap_count) * frame.rows + y, x) = weight; //update weight by the calculated value |
|
|
|
//check prune |
|
|
|
totalWeight += weight; |
|
|
|
if (weight < -prune) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
weight = 0.0f; |
|
|
|
|
|
|
|
nmodes--; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//renormalize weights |
|
|
|
gmm_weight((mode - swap_count) * frame.rows + y, x) = weight; //update weight by the calculated value |
|
|
|
|
|
|
|
totalWeight += weight; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
totalWeight = 1.f / totalWeight; |
|
|
|
//renormalize weights |
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
|
|
|
|
gmm_weight(mode * frame.rows + y, x) *= totalWeight; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nmodes = nNewModes; |
|
|
|
totalWeight = 1.f / totalWeight; |
|
|
|
|
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
|
|
|
|
gmm_weight(mode * frame.rows + y, x) *= totalWeight; |
|
|
|
|
|
|
|
|
|
|
|
//make new mode if needed and exit |
|
|
|
nmodes = nNewModes; |
|
|
|
|
|
|
|
|
|
|
|
if (!fitsPDF) |
|
|
|
//make new mode if needed and exit |
|
|
|
{ |
|
|
|
|
|
|
|
// replace the weakest or add a new one |
|
|
|
|
|
|
|
int mode = nmodes == c_nmixtures ? c_nmixtures - 1 : nmodes++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nmodes == 1) |
|
|
|
if (!fitsPDF) |
|
|
|
gmm_weight(mode * frame.rows + y, x) = 1.f; |
|
|
|
{ |
|
|
|
else |
|
|
|
// replace the weakest or add a new one |
|
|
|
{ |
|
|
|
const int mode = nmodes == constants->nmixtures_ ? constants->nmixtures_ - 1 : nmodes++; |
|
|
|
gmm_weight(mode * frame.rows + y, x) = alphaT; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// renormalize all other weights |
|
|
|
if (nmodes == 1) |
|
|
|
|
|
|
|
gmm_weight(mode * frame.rows + y, x) = 1.f; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
gmm_weight(mode * frame.rows + y, x) = alphaT; |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < nmodes - 1; ++i) |
|
|
|
// renormalize all other weights |
|
|
|
gmm_weight(i * frame.rows + y, x) *= alpha1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// init |
|
|
|
for (int i = 0; i < nmodes - 1; ++i) |
|
|
|
|
|
|
|
gmm_weight(i * frame.rows + y, x) *= alpha1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
gmm_mean(mode * frame.rows + y, x) = pix; |
|
|
|
// init |
|
|
|
gmm_variance(mode * frame.rows + y, x) = c_varInit; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//sort |
|
|
|
gmm_mean(mode * frame.rows + y, x) = pix; |
|
|
|
//find the new place for it |
|
|
|
gmm_variance(mode * frame.rows + y, x) = constants->varInit_; |
|
|
|
|
|
|
|
|
|
|
|
for (int i = nmodes - 1; i > 0; --i) |
|
|
|
//sort |
|
|
|
{ |
|
|
|
//find the new place for it |
|
|
|
// check one up |
|
|
|
|
|
|
|
if (alphaT < gmm_weight((i - 1) * frame.rows + y, x)) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//swap one up |
|
|
|
for (int i = nmodes - 1; i > 0; --i) |
|
|
|
swap(gmm_weight, x, y, i - 1, frame.rows); |
|
|
|
{ |
|
|
|
swap(gmm_variance, x, y, i - 1, frame.rows); |
|
|
|
// check one up |
|
|
|
swap(gmm_mean, x, y, i - 1, frame.rows); |
|
|
|
if (alphaT < gmm_weight((i - 1) * frame.rows + y, x)) |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//swap one up |
|
|
|
|
|
|
|
swap(gmm_weight, x, y, i - 1, frame.rows); |
|
|
|
|
|
|
|
swap(gmm_variance, x, y, i - 1, frame.rows); |
|
|
|
|
|
|
|
swap(gmm_mean, x, y, i - 1, frame.rows); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//set the number of modes |
|
|
|
//set the number of modes |
|
|
|
modesUsed(y, x) = nmodes; |
|
|
|
modesUsed(y, x) = nmodes; |
|
|
|
|
|
|
|
|
|
|
|
bool isShadow = false; |
|
|
|
bool isShadow = false; |
|
|
|
if (detectShadows && !background) |
|
|
|
if (detectShadows && !background) |
|
|
|
{ |
|
|
|
{ |
|
|
|
float tWeight = 0.0f; |
|
|
|
float tWeight = 0.0f; |
|
|
|
|
|
|
|
|
|
|
|
// check all the components marked as background: |
|
|
|
// check all the components marked as background: |
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
{ |
|
|
|
{ |
|
|
|
WorkT mean = gmm_mean(mode * frame.rows + y, x); |
|
|
|
const WorkT mean = gmm_mean(mode * frame.rows + y, x); |
|
|
|
|
|
|
|
|
|
|
|
WorkT pix_mean = pix * mean; |
|
|
|
const WorkT pix_mean = pix * mean; |
|
|
|
|
|
|
|
|
|
|
|
float numerator = sum(pix_mean); |
|
|
|
const float numerator = sum(pix_mean); |
|
|
|
float denominator = sqr(mean); |
|
|
|
const float denominator = sqr(mean); |
|
|
|
|
|
|
|
|
|
|
|
// no division by zero allowed |
|
|
|
// no division by zero allowed |
|
|
|
if (denominator == 0) |
|
|
|
if (denominator == 0) |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
// if tau < a < 1 then also check the color distortion |
|
|
|
|
|
|
|
if (numerator <= denominator && numerator >= c_tau * denominator) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
float a = numerator / denominator; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WorkT dD = a * mean - pix; |
|
|
|
// if tau < a < 1 then also check the color distortion |
|
|
|
|
|
|
|
else if (numerator <= denominator && numerator >= constants->tau_ * denominator) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
const float a = numerator / denominator; |
|
|
|
|
|
|
|
|
|
|
|
if (sqr(dD) < c_Tb * gmm_variance(mode * frame.rows + y, x) * a * a) |
|
|
|
WorkT dD = a * mean - pix; |
|
|
|
{ |
|
|
|
|
|
|
|
isShadow = true; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tWeight += gmm_weight(mode * frame.rows + y, x); |
|
|
|
if (sqr(dD) < constants->Tb_ * gmm_variance(mode * frame.rows + y, x) * a * a) |
|
|
|
if (tWeight > c_TB) |
|
|
|
{ |
|
|
|
|
|
|
|
isShadow = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
fgmask(y, x) = background ? 0 : isShadow ? c_shadowVal : 255; |
|
|
|
tWeight += gmm_weight(mode * frame.rows + y, x); |
|
|
|
|
|
|
|
if (tWeight > constants->TB_) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <typename SrcT, typename WorkT> |
|
|
|
fgmask(y, x) = background ? 0 : isShadow ? constants->shadowVal_ : 255; |
|
|
|
void mog2_caller(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, |
|
|
|
} |
|
|
|
float alphaT, float prune, bool detectShadows, cudaStream_t stream) |
|
|
|
} |
|
|
|
{ |
|
|
|
|
|
|
|
dim3 block(32, 8); |
|
|
|
|
|
|
|
dim3 grid(divUp(frame.cols, block.x), divUp(frame.rows, block.y)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const float alpha1 = 1.0f - alphaT; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (detectShadows) |
|
|
|
template <typename SrcT, typename WorkT> |
|
|
|
{ |
|
|
|
void mog2_caller(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, |
|
|
|
cudaSafeCall( cudaFuncSetCacheConfig(mog2<true, SrcT, WorkT>, cudaFuncCachePreferL1) ); |
|
|
|
float alphaT, float prune, bool detectShadows, const Constants *const constants, cudaStream_t stream) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
dim3 block(32, 8); |
|
|
|
|
|
|
|
dim3 grid(divUp(frame.cols, block.x), divUp(frame.rows, block.y)); |
|
|
|
|
|
|
|
|
|
|
|
mog2<true, SrcT, WorkT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>) frame, fgmask, modesUsed, |
|
|
|
const float alpha1 = 1.0f - alphaT; |
|
|
|
weight, variance, (PtrStepSz<WorkT>) mean, |
|
|
|
|
|
|
|
alphaT, alpha1, prune); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
cudaSafeCall( cudaFuncSetCacheConfig(mog2<false, SrcT, WorkT>, cudaFuncCachePreferL1) ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mog2<false, SrcT, WorkT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>) frame, fgmask, modesUsed, |
|
|
|
if (detectShadows) |
|
|
|
weight, variance, (PtrStepSz<WorkT>) mean, |
|
|
|
{ |
|
|
|
alphaT, alpha1, prune); |
|
|
|
cudaSafeCall(cudaFuncSetCacheConfig(mog2<true, SrcT, WorkT>, cudaFuncCachePreferL1)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cudaSafeCall( cudaGetLastError() ); |
|
|
|
mog2<true, SrcT, WorkT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>)frame, fgmask, modesUsed, |
|
|
|
|
|
|
|
weight, variance, (PtrStepSz<WorkT>)mean, |
|
|
|
|
|
|
|
alphaT, alpha1, prune, constants); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
cudaSafeCall(cudaFuncSetCacheConfig(mog2<false, SrcT, WorkT>, cudaFuncCachePreferL1)); |
|
|
|
|
|
|
|
|
|
|
|
if (stream == 0) |
|
|
|
mog2<false, SrcT, WorkT><<<grid, block, 0, stream>>>((PtrStepSz<SrcT>)frame, fgmask, modesUsed, |
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
weight, variance, (PtrStepSz<WorkT>)mean, |
|
|
|
} |
|
|
|
alphaT, alpha1, prune, constants); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void mog2_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, |
|
|
|
cudaSafeCall(cudaGetLastError()); |
|
|
|
float alphaT, float prune, bool detectShadows, cudaStream_t stream) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
typedef void (*func_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const func_t funcs[] = |
|
|
|
if (stream == 0) |
|
|
|
{ |
|
|
|
cudaSafeCall(cudaDeviceSynchronize()); |
|
|
|
0, mog2_caller<uchar, float>, 0, mog2_caller<uchar3, float3>, mog2_caller<uchar4, float4> |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
funcs[cn](frame, fgmask, modesUsed, weight, variance, mean, alphaT, prune, detectShadows, stream); |
|
|
|
void mog2_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, |
|
|
|
} |
|
|
|
float alphaT, float prune, bool detectShadows, const Constants *const constants, cudaStream_t stream) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
typedef void (*func_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, const Constants *const constants, cudaStream_t stream); |
|
|
|
|
|
|
|
|
|
|
|
template <typename WorkT, typename OutT> |
|
|
|
static const func_t funcs[] = |
|
|
|
__global__ void getBackgroundImage2(const PtrStepSzb modesUsed, const PtrStepf gmm_weight, const PtrStep<WorkT> gmm_mean, PtrStep<OutT> dst) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
const int x = blockIdx.x * blockDim.x + threadIdx.x; |
|
|
|
0, mog2_caller<uchar, float>, 0, mog2_caller<uchar3, float3>, mog2_caller<uchar4, float4>}; |
|
|
|
const int y = blockIdx.y * blockDim.y + threadIdx.y; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (x >= modesUsed.cols || y >= modesUsed.rows) |
|
|
|
funcs[cn](frame, fgmask, modesUsed, weight, variance, mean, alphaT, prune, detectShadows, constants, stream); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int nmodes = modesUsed(y, x); |
|
|
|
template <typename WorkT, typename OutT> |
|
|
|
|
|
|
|
__global__ void getBackgroundImage2(const PtrStepSzb modesUsed, const PtrStepf gmm_weight, const PtrStep<WorkT> gmm_mean, PtrStep<OutT> dst, const Constants *const constants) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
const int x = blockIdx.x * blockDim.x + threadIdx.x; |
|
|
|
|
|
|
|
const int y = blockIdx.y * blockDim.y + threadIdx.y; |
|
|
|
|
|
|
|
|
|
|
|
WorkT meanVal = VecTraits<WorkT>::all(0.0f); |
|
|
|
if (x >= modesUsed.cols || y >= modesUsed.rows) |
|
|
|
float totalWeight = 0.0f; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
int nmodes = modesUsed(y, x); |
|
|
|
{ |
|
|
|
|
|
|
|
float weight = gmm_weight(mode * modesUsed.rows + y, x); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WorkT mean = gmm_mean(mode * modesUsed.rows + y, x); |
|
|
|
WorkT meanVal = VecTraits<WorkT>::all(0.0f); |
|
|
|
meanVal = meanVal + weight * mean; |
|
|
|
float totalWeight = 0.0f; |
|
|
|
|
|
|
|
|
|
|
|
totalWeight += weight; |
|
|
|
for (int mode = 0; mode < nmodes; ++mode) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
float weight = gmm_weight(mode * modesUsed.rows + y, x); |
|
|
|
|
|
|
|
|
|
|
|
if(totalWeight > c_TB) |
|
|
|
WorkT mean = gmm_mean(mode * modesUsed.rows + y, x); |
|
|
|
break; |
|
|
|
meanVal = meanVal + weight * mean; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
meanVal = meanVal * (1.f / totalWeight); |
|
|
|
totalWeight += weight; |
|
|
|
|
|
|
|
|
|
|
|
dst(y, x) = saturate_cast<OutT>(meanVal); |
|
|
|
if (totalWeight > constants->TB_) |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <typename WorkT, typename OutT> |
|
|
|
meanVal = meanVal * (1.f / totalWeight); |
|
|
|
void getBackgroundImage2_caller(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
dim3 block(32, 8); |
|
|
|
|
|
|
|
dim3 grid(divUp(modesUsed.cols, block.x), divUp(modesUsed.rows, block.y)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cudaSafeCall( cudaFuncSetCacheConfig(getBackgroundImage2<WorkT, OutT>, cudaFuncCachePreferL1) ); |
|
|
|
dst(y, x) = saturate_cast<OutT>(meanVal); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
getBackgroundImage2<WorkT, OutT><<<grid, block, 0, stream>>>(modesUsed, weight, (PtrStepSz<WorkT>) mean, (PtrStepSz<OutT>) dst); |
|
|
|
template <typename WorkT, typename OutT> |
|
|
|
cudaSafeCall( cudaGetLastError() ); |
|
|
|
void getBackgroundImage2_caller(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, const Constants *const constants, cudaStream_t stream) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
dim3 block(32, 8); |
|
|
|
|
|
|
|
dim3 grid(divUp(modesUsed.cols, block.x), divUp(modesUsed.rows, block.y)); |
|
|
|
|
|
|
|
|
|
|
|
if (stream == 0) |
|
|
|
cudaSafeCall(cudaFuncSetCacheConfig(getBackgroundImage2<WorkT, OutT>, cudaFuncCachePreferL1)); |
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream) |
|
|
|
getBackgroundImage2<WorkT, OutT><<<grid, block, 0, stream>>>(modesUsed, weight, (PtrStepSz<WorkT>)mean, (PtrStepSz<OutT>)dst, constants); |
|
|
|
{ |
|
|
|
cudaSafeCall(cudaGetLastError()); |
|
|
|
typedef void (*func_t)(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const func_t funcs[] = |
|
|
|
if (stream == 0) |
|
|
|
{ |
|
|
|
cudaSafeCall(cudaDeviceSynchronize()); |
|
|
|
0, getBackgroundImage2_caller<float, uchar>, 0, getBackgroundImage2_caller<float3, uchar3>, getBackgroundImage2_caller<float4, uchar4> |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
funcs[cn](modesUsed, weight, mean, dst, stream); |
|
|
|
void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, const Constants *const constants, cudaStream_t stream) |
|
|
|
} |
|
|
|
{ |
|
|
|
} |
|
|
|
typedef void (*func_t)(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, const Constants *const constants, cudaStream_t stream); |
|
|
|
}}} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const func_t funcs[] = |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
0, getBackgroundImage2_caller<float, uchar>, 0, getBackgroundImage2_caller<float3, uchar3>, getBackgroundImage2_caller<float4, uchar4>}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
funcs[cn](modesUsed, weight, mean, dst, constants, stream); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} // namespace mog2 |
|
|
|
|
|
|
|
} // namespace device |
|
|
|
|
|
|
|
} // namespace cuda |
|
|
|
|
|
|
|
} // namespace cv |
|
|
|
|
|
|
|
|
|
|
|
#endif /* CUDA_DISABLER */ |
|
|
|
#endif /* CUDA_DISABLER */ |
|
|
|