27 #include "Image/MixtureOfGaussians.hh"
28 #include <Base/Image/ImageConvert.hh>
29 #include <Base/ImageUtils/ImageDraw.hh>
30 #include <Base/Image/ROI.hh>
31 #include <bias_config.h>
32 #include <Base/Image/ImageIO.hh>
33 #include <Base/Common/FileHandling.hh>
34 #include <Filter/Erosion.hh>
35 #include <Base/Debug/TimeMeasure.hh>
41 template <
class StorageType>
44 const unsigned int sizeWindow,
45 const float updateFactor,
47 dDistributions_ = numDistributions;
48 dWindow_ = sizeWindow /2;
50 fUpdateFactor_ = updateFactor;
53 fError_ = 2.9f * 2.9f;
56 colorModel_ = colorModel;
57 blobDetector_.SetMinSize(1000);
58 bAllowNewDistributionCreation_ =
true;
60 bInverseCleanup_ =
false;
61 blobDetectorRan_ =
false;
64 #ifdef BIAS_HAVE_PTHREADS
65 guardimagemutex =
new pthread_mutex_t;
66 pthread_mutex_init(guardimagemutex, NULL);
70 template <
class StorageType>
76 template <
class StorageType>
81 blobDetector_.SetGaussSigma(1.0);
83 blobDetector_.SetGaussSigma(0.0);
86 template <
class StorageType>
90 const float errorMargin) {
91 dMaxWeight_ = maxWeight;
92 dMinWeight_ = minWeight;
93 fError_ = errorMargin * errorMargin;
97 template <
class StorageType>
100 #ifdef BIAS_HAVE_PTHREADS
101 delete guardimagemutex;
105 template <
class StorageType>
111 blobDetectorRan_ =
false;
129 CreateNormalizedImage_(in, workImage_);
131 #ifdef BIAS_HAVE_PTHREADS
132 pthread_mutex_lock(guardimagemutex);
151 if (dFrameCounter_ > dMinWeight_) {
153 if (bInverseCleanup_) {
155 white.
Init(differenceSave_.GetWidth(), differenceSave_.GetHeight(), differenceSave_.GetChannelCount());
157 differenceSave_ = white - differenceSave_;
158 blobDetector_.SetEraseBelowMinSize(
true);
159 if(!blobDetectorRan_){
160 blobDetector_.Detect(differenceSave_, corners_);
161 blobDetectorRan_ =
true;
163 differenceSave_ = white - differenceSave_;
168 blobDetector_.SetEraseBelowMinSize(
true);
169 if(!blobDetectorRan_){
170 blobDetector_.Detect(differenceSave_, corners_);
171 blobDetectorRan_ =
true;
178 erosion.
Erode3Fast(differenceSave_, difference_);
179 erosion.
Erode3Fast(difference_, differenceSave_);
184 #ifdef BIAS_HAVE_PTHREADS
185 pthread_mutex_unlock(guardimagemutex);
189 if (dFrameCounter_ > 250 && dFrameCounter_ < 300) {
205 template <
class StorageType>
208 normalized = workImage_;
212 template <
class StorageType>
219 template <
class StorageType>
227 float **idaWeight = weight_.GetImageDataArray();
229 for (
unsigned int y=0;y<height_;y++) {
230 for (
unsigned int x=0;x<width_*channels_;x++) {
231 for (
unsigned int i=0;i<dCurDistributions_;i++) {
232 val = idaWeight[y][x*dDistributions_+i];
233 if (val > idaRet[y][x])
241 template <
class StorageType>
244 #ifdef BIAS_HAVE_PTHREADS
245 pthread_mutex_lock(guardimagemutex);
247 match = matchValueImage_;
248 #ifdef BIAS_HAVE_PTHREADS
249 pthread_mutex_unlock(guardimagemutex);
255 template <
class StorageType>
260 #ifdef BIAS_HAVE_PTHREADS
261 pthread_mutex_lock(guardimagemutex);
263 diff = differenceSave_;
264 #ifdef BIAS_HAVE_PTHREADS
265 pthread_mutex_unlock(guardimagemutex);
267 if (dFrameCounter_ < dMinWeight_)
273 template <
class StorageType>
276 if (dFrameCounter_ < dMinWeight_)
278 unsigned char **visu = differenceVisu_.GetImageDataArray();
280 #ifdef BIAS_HAVE_PTHREADS
281 pthread_mutex_lock(guardimagemutex);
283 unsigned char **idaD = differenceSave_.GetImageDataArray();
284 for (
unsigned int y=0;y<height_;y++) {
285 for (
unsigned int x=0;x<width_;x++) {
286 for (
unsigned int c=0;c<3;c++) {
287 visu[y][x*3+c] = idaD[y][x];
291 #ifdef BIAS_HAVE_PTHREADS
292 pthread_mutex_unlock(guardimagemutex);
294 if(!blobDetectorRan_){
295 blobDetector_.Detect(differenceSave_, corners_);
296 blobDetectorRan_ =
true;
298 blobDetector_.DrawInImage(differenceVisu_);
300 guiImage = differenceVisu_;
304 template <
class StorageType>
307 if (corners_.size()>0) {
315 template <
class StorageType>
318 if(!blobDetectorRan_){
319 blobDetector_.Detect(differenceSave_, corners_);
320 blobDetectorRan_ =
true;
322 return blobDetector_.GetLargestBoundingBox(corners);
325 template <
class StorageType>
328 distributionImages.clear();
329 distributionImages.resize(dCurDistributions_);
331 float **idaGuess = guess_.GetImageDataArray();
333 for (
unsigned int i=0; i<dCurDistributions_;i++) {
334 if (!distributionImages[i].IsEmpty())
335 distributionImages[i].Release();
336 distributionImages[i].Init(width_, height_, channels_);
337 float **idaD = distributionImages[i].GetImageDataArray();
338 for (
unsigned int y=0; y<height_; y++) {
339 for (
unsigned int x=0; x<width_; x++) {
340 for (
unsigned int c=0; c<channels_; c++) {
341 idaD[y][x*channels_+c] = idaGuess[y][(x*channels_+c)*dDistributions_+i];
353 template <
class StorageType>
367 unsigned int depthChannel =0;
373 #ifdef BIAS_HAVE_OPENMP
374 #pragma omp parallel for
376 for (
int y=0;y<(int)height_;y++) {
377 for (
int x=0;x<(int)width_;x++) {
378 for (
unsigned c=0;c<channels_;c++) {
380 idaFL[y][x*channels_+c] /= maxDepth_;
382 idaFL[y][x*channels_+c] /= 255.0f;
391 if(colorModel_==
MOG_HS ) channels_ = 2;
392 else if(colorModel_==
MOG_HSD ) channels_ = 3;
394 #ifdef BIAS_HAVE_OPENMP
395 #pragma omp parallel for
397 for (
int y=0;y<(int)height_;y++) {
398 for (
int x=0;x<(int)width_;x++) {
399 for (
unsigned c=0;c<channels_;c++) {
401 idaFL[y][x*channels_+c] /= maxDepth_;
403 idaFL[y][x*channels_+c] /= 255.0f;
412 #ifdef BIAS_HAVE_OPENMP
413 #pragma omp parallel for
415 for (
int y=0;y<(int)height_;y++) {
416 for (
int x=0;x<(int)width_;x++) {
419 for(
int c =0;c<(int)channels_;c++){
420 if(c<3) norm += (idaFL[y][x*channels_+c])*(idaFL[y][x*channels_+c]);
422 norm = (float) sqrt(norm);
425 if (norm <= 1.0f) norm = 1.0f;
426 for(
unsigned c =0;c<channels_;c++) {
428 idaFL[y][x*channels_+c] /= maxDepth_;
430 idaFL[y][x*channels_+c] /= norm;
443 template <
class StorageType>
446 dCurDistributions_ = 1;
447 guess_.ReInit(width_*channels_,height_,dDistributions_,
449 cov_.ReInit(width_*channels_,height_,dDistributions_,
451 weight_.ReInit(width_*channels_,height_,dDistributions_,
457 matchValueImage_.FillImageWithConstValue(0.0f);
464 float **idaImage = workImage_.GetImageDataArray();
465 float **idaWeight = weight_.GetImageDataArray();
466 float **idaGuess= guess_.GetImageDataArray();
467 float **idaCov = cov_.GetImageDataArray();;
470 for (
unsigned int c=0;c<channels_;c++) {
471 for (
unsigned int y=0;y<height_;y++) {
472 for (
unsigned int x=0;x<width_;x++) {
475 for (
unsigned int yw=y-dWindow_;yw<y+dWindow_;yw++) {
476 for (
unsigned int xw=x-dWindow_;xw<x+dWindow_;xw++) {
477 if (yw<0 || xw<0 || yw>=height_ || xw >= width_)
479 valGuess += idaImage[yw][xw*channels_+c];
485 valGuess /= (float)cntPix;
490 idaGuess[y][(x*channels_+c)*dDistributions_] = valGuess;
496 for (
unsigned int c=0;c<channels_;c++) {
497 for (
unsigned int y=0;y<height_;y++) {
498 for (
unsigned int x=0;x<width_;x++) {
501 for (
unsigned int yw=y-dWindow_;yw<y+dWindow_;yw++) {
502 for (
unsigned int xw=x-dWindow_;xw<x+dWindow_;xw++) {
503 if (yw<0 || xw<0 || yw>=height_ || xw >= width_)
505 val += (idaImage[yw][xw*channels_+c] - idaGuess[yw][(xw*channels_+c)*dDistributions_])
506 * (idaImage[yw][xw*channels_+c] - idaGuess[yw][(xw*channels_+c)*dDistributions_]);
511 val /= (float)(cntPix*cntPix);
514 idaCov[y][(x*channels_+c)*dDistributions_] = val;
520 for (
unsigned int y=0;y<height_;y++) {
521 for (
unsigned int x=0;x<width_*channels_;x++) {
522 for (
unsigned int i=1;i<dDistributions_;i++) {
523 xc = x*dDistributions_+i;
524 idaWeight[y][xc] = -1;
525 idaGuess[y][xc] = -1;
534 template <
class StorageType>
536 InitOnePixel_(
unsigned int x,
unsigned int y,
unsigned int c,
unsigned int distrib) {
540 float **idaImage = workImage_.GetImageDataArray();
541 float **idaGuess = guess_.GetImageDataArray();
542 float **idaCov = cov_.GetImageDataArray();
543 float **idaWeight = weight_.GetImageDataArray();
545 for (
unsigned int yw=y-dWindow_;yw<y+dWindow_;yw++) {
546 for (
unsigned int xw=x-dWindow_;xw<x+dWindow_;xw++) {
547 if (yw<0 || xw<0 || yw>=height_ || xw >= width_)
549 val += idaImage[yw][xw*channels_+c];
554 val /= (float)cntPix;
557 xc = (x*channels_+c)*dDistributions_+distrib;
561 idaGuess[y][xc] = val;
565 for (
unsigned int yw=y-dWindow_;yw<y+dWindow_;yw++) {
566 for (
unsigned int xw=x-dWindow_;xw<x+dWindow_;xw++) {
567 if (yw<0 || xw<0 || yw>=height_ || xw >= width_)
569 xc = (xw*channels_+c)*dDistributions_+distrib;
570 val += (idaImage[yw][xw*channels_+c] - idaGuess[yw][xc]) *
571 (idaImage[yw][xw*channels_+c] - idaGuess[yw][xc]);
576 val /= (float)(cntPix*cntPix);
579 xc = (x*channels_+c)*dDistributions_+distrib;
581 idaWeight[y][xc] = 1;
586 template <
class StorageType>
591 difference_.FillImageWithConstValue((
unsigned char)255);
593 float **idaImage = workImage_.GetImageDataArray();
594 float **idaWeight = weight_.GetImageDataArray();
595 float **idaGuess= guess_.GetImageDataArray();
596 float **idaCov = cov_.GetImageDataArray();;
597 float **idaMaxWeight = maxWeight_.GetImageDataArray();;
598 float **idaMatchValue = matchValueImage_.GetImageDataArray();
599 unsigned char **idaDiff = difference_.GetImageDataArray();
603 for (
int y=(
int)roiULy_ ; y<(int)roiLRy_ ; y++) {
604 int xc = 0;
bool matched=
false;
608 for (
int x=(
int)roiULx_;x<(int)roiLRx_;x++) {
609 unsigned int timesMatched_=0;
610 float matchValue_=0.0f;
611 unsigned distCount =0;
613 for (
int c=0;c<(int)channels_;c++) {
615 float min_weight = 10000;
617 float max_weight = -10000;
619 unsigned int min_distrib = 0;
624 for (
int i=0;i<(int)dDistributions_;i++) {
625 xc = (x*channels_+c)*dDistributions_+i;
627 if (idaWeight[y][xc] > max_weight) {
628 max_weight = idaWeight[y][xc];
632 if (idaWeight[y][xc] < min_weight) {
633 min_weight = idaWeight[y][xc];
636 if (idaWeight[y][xc] < 0)
642 float val = idaImage[y][x*channels_+c];
645 for (
int i=0;i<(int)dCurDistributions_;i++) {
646 xc = (x*channels_+c)*dDistributions_+i;
648 float guess = idaGuess[y][xc];
649 if (guess < 0)
continue;
650 float cov = idaCov[y][xc];
651 float absdiff = abs(val - guess);
652 matchValue_ += absdiff;
654 float absdiffSquared = absdiff*absdiff;
656 if (!matched && absdiffSquared < fError_*cov) {
658 if (idaWeight[y][xc] <= dMaxWeight_)
661 float myCovTest=0.0f,myGuessTest =0.0f;
663 myGuessTest = (1.0f-fUpdateFactor_)*guess + fUpdateFactor_*val;
664 myCovTest = (1.0f-fUpdateFactor_)*cov + fUpdateFactor_*absdiffSquared;
666 if (myCovTest < 1e-5) {
667 idaCov[y][xc] = 1e-5f;
668 }
else if (myCovTest > 0.05) {
669 idaCov[y][xc] = 0.05f;
672 idaGuess[y][xc] = myGuessTest;
680 if (bAllowNewDistributionCreation_) {
681 if (idaWeight[y][xc] > dMinWeight_)
689 if (!matched && bAllowNewDistributionCreation_) {
690 InitOnePixel_(x,y,c,min_distrib);
691 if (min_distrib >= dCurDistributions_) {
692 dCurDistributions_ = min_distrib +1;
696 idaMaxWeight[y][x] = max_weight;
700 if (timesMatched_ == channels_) {
706 if (matchValue_ <= 0) {
707 idaMatchValue[y][x] = 0;
709 idaMatchValue[y][x] = matchValue_ / (float)(distCount);
713 differenceSave_.CopyIn_NoInit(difference_.GetImageData());
int GetMaxWeightImage(BIAS::Image< float > &weight)
get image with current max weights, only interesting for visualisation
int GetNormalizedImage(BIAS::Image< float > &normalized)
get normalized rgb image
void SetSmoothing(const bool smooth)
void GetCorners(unsigned &UpperLeftX, unsigned &UpperLeftY, unsigned &LowerRightX, unsigned &LowerRightY) const
Return the region of interest, by saving the coordinates within the variables defined by the paramete...
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
void SetHalfWinSize(const int hws, bool AdjustSigma=true)
define the half win size of the kernel, if AdjustSigma is true sigma is computed according to the cut...
int GetCurrentDistributions(std::vector< Image< float > > &distributionImages)
get vector of images containing current guesses (distributions)
int GetWeightImage(BIAS::Image< float > &weights)
get image with current weights and distributions
int InitOnePixel_(unsigned int x, unsigned int y, unsigned int c, unsigned int distrib)
int GetBoundingBoxes(std::vector< BIAS::BIASBlob > &corners)
get vector of corners for each bounding box of detected changes
unsigned int GetWidth() const
int InitWeights(const int maxWeight, const int minWeight, const float errorMargin)
init weights for background/object distinction
Helper class to store blob corners.
void SetColorModel(MoGColorModel model)
set the used color model note that the images have to be given in the correct model no conversion wil...
int GetMatchValueImage(BIAS::Image< float > &match)
ROI * GetROI()
Returns a pointer to the roi object.
Erosion operator for binary images (black and white)
static int ConvertST(const BIAS::ImageBase &source, BIAS::ImageBase &dest, ImageBase::EStorageType targetST)
Function to convert the storage type of images e.g.
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
color values, 3 channels, order: red,green,blue
static std::string LeadingZeroString(const int &n, const unsigned int &digits=DEFAULT_LEADING_ZEROS)
Create a string with leading zeroes from number.
unsigned int GetHeight() const
void SetSigma(const double si)
int Erode3Fast(const Image< InputStorageType > &src, Image< OutputStorageType > &dest, bool Neighbor4=false)
Very fast erode with 3x3 mask, all values, which are not not zero, are treated as foreground...
void FillImageWithConstValue(StorageType Value)
fill grey images
The image template class for specific storage types.
int GetLargestBoundingBox(BIAS::BIASBlob &corners)
get largest bounding box of detected changes
static int Save(const std::string &filename, const ImageBase &img, const enum TFileFormat FileFormat=FF_auto, const bool sync=BIAS_DEFAULT_SYNC, const int c_jpeg_quality=BIAS_DEFAULT_IMAGE_QUALITY, const bool forceNewID=BIAS_DEFAULT_FORCENEWID, const bool &writeMetaData=true)
Export image as file using extrnal libs.
int CreateNormalizedImage_(const BIAS::Image< StorageType > &in, BIAS::Image< float > &out)
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
sets gauss kernel if params changed and calls convolution or fast grey implementation if possible ...
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
int GetDifferenceImage(BIAS::Image< unsigned char > &diff)
get image of detected scene changes.
MixtureOfGaussians(const unsigned int numDistributions, const unsigned int sizeWindow=3, const float updateFactor=0.1, const MoGColorModel colorModel=MOG_NRGB)
constructor
enum EStorageType GetStorageType() const
(8bit) unsigned char image storage type
~MixtureOfGaussians()
destructor
int GetDifferenceImageWithVisuals(BIAS::Image< unsigned char > &guiImage)
get image of detected scene changes with visualisations of detection
int Apply(BIAS::Image< StorageType > &in)
update calculations with new image the image has to be formatted correctly, e.g for MoG on HSL images...
class TimeMeasure contains functions for timing real time and cpu time.
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase