motionSaliencyBinWangApr2014.cpp 19.7 KB
Newer Older
jaco's avatar
jaco committed
1 2 3 4 5 6 7 8 9 10 11 12
/*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
 //
jaco's avatar
jaco committed
13
 // Copyright (C) 2014, OpenCV Foundation, all rights reserved.
jaco's avatar
jaco committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
 // 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"
43
//TODO delete highgui include
44
//#include <opencv2/highgui.hpp>
jaco's avatar
jaco committed
45

46 47 48
#define thetaA_VAL 200
#define thetaL_VAL 250

jaco's avatar
jaco committed
49 50
namespace cv
{
jaco's avatar
jaco committed
51 52
namespace saliency
{
jaco's avatar
jaco committed
53

jaco's avatar
jaco committed
54
void MotionSaliencyBinWangApr2014::setImagesize( int W, int H )
jaco's avatar
jaco committed
55
{
jaco's avatar
jaco committed
56 57
  imageWidth = W;
  imageHeight = H;
jaco's avatar
jaco committed
58 59 60 61
}

MotionSaliencyBinWangApr2014::MotionSaliencyBinWangApr2014()
{
62
  N_DS = 2;  // Number of template to be downsampled and used in lowResolutionDetection function
jaco's avatar
jaco committed
63
  K = 3;  // Number of background model template
jaco's avatar
jaco committed
64
  N = 4;   // NxN is the size of the block for downsampling in the lowlowResolutionDetection
jaco's avatar
jaco committed
65
  alpha = (float) 0.01;  // Learning rate
66 67
  L0 = 1000;  // Upper-bound values for C0 (efficacy of the first template (matrices) of backgroundModel
  L1 = 800;  // Upper-bound values for C1 (efficacy of the second template (matrices) of backgroundModel
68 69
  thetaL = thetaL_VAL;  // T0, T1 swap threshold
  thetaA = thetaA_VAL;
jaco's avatar
jaco committed
70
  gamma = 3;
jaco's avatar
jaco committed
71
  neighborhoodCheck = true;
jaco's avatar
jaco committed
72 73 74 75

  className = "BinWangApr2014";
}

76 77
bool MotionSaliencyBinWangApr2014::init()
{
jaco's avatar
jaco committed
78 79
  Size imgSize( imageWidth, imageHeight );
  epslonPixelsValue = Mat( imgSize.height, imgSize.width, CV_32F, Scalar( 20 ) );
80 81 82 83
  // Median of range [18, 80] advised in reference paper.
  // Since data is even, the median is estimated using two values ​​that occupy
  // the position (n / 2) and ((n / 2) +1) (choose their arithmetic mean).

jaco's avatar
jaco committed
84
  potentialBackground = Mat( imgSize.height, imgSize.width, CV_32FC2, Scalar( NAN, 0 ) );
85

86
  backgroundModel.resize( K + 1 );
87

88
  for ( int i = 0; i < K + 1; i++ )
jaco's avatar
jaco committed
89
  {
90
    Mat* tmpm = new Mat;
jaco's avatar
jaco committed
91
    tmpm->create( imgSize.height, imgSize.width, CV_32FC2 );
92
    tmpm->setTo( Scalar( NAN, 0 ) );
93 94
    Ptr<Mat> tmp = Ptr<Mat>( tmpm );
    backgroundModel[i] = tmp;
jaco's avatar
jaco committed
95
  }
96 97 98 99 100

  return true;

}

jaco's avatar
jaco committed
101 102 103 104 105 106
MotionSaliencyBinWangApr2014::~MotionSaliencyBinWangApr2014()
{

}

// classification (and adaptation) functions
jaco's avatar
jaco committed
107
bool MotionSaliencyBinWangApr2014::fullResolutionDetection( const Mat& image2, Mat& highResBFMask )
jaco's avatar
jaco committed
108
{
jaco's avatar
jaco committed
109
  Mat image = image2.clone();
110

111 112
  float currentPixelValue;
  float currentEpslonValue;
113
  bool backgFlag = false;
114 115

  // Initially, all pixels are considered as foreground and then we evaluate with the background model
116
  highResBFMask.create( image.rows, image.cols, CV_32F );
117 118
  highResBFMask.setTo( 1 );

jaco's avatar
jaco committed
119 120
  uchar* pImage;
  float* pEpslon;
121
  float* pMask;
jaco's avatar
jaco committed
122

123
  // Scan all pixels of image
jaco's avatar
jaco committed
124
  for ( int i = 0; i < image.rows; i++ )
125
  {
126

jaco's avatar
jaco committed
127 128
    pImage = image.ptr<uchar>( i );
    pEpslon = epslonPixelsValue.ptr<float>( i );
129
    pMask = highResBFMask.ptr<float>( i );
jaco's avatar
jaco committed
130
    for ( int j = 0; j < image.cols; j++ )
131
    {
132

jaco's avatar
jaco committed
133
      backgFlag = false;
jaco's avatar
jaco committed
134
      currentPixelValue = pImage[j];
jaco's avatar
jaco committed
135
      currentEpslonValue = pEpslon[j];
jaco's avatar
jaco committed
136

137 138 139
      int counter = 0;
      for ( size_t z = 0; z < backgroundModel.size(); z++ )
      {
140

jaco's avatar
jaco committed
141
        counter += (int) backgroundModel[z]->ptr<Vec2f>( i )[j][1];
142 143 144
      }

      if( counter != 0 )  //if at least the first template is activated / initialized
145 146
      {

jaco's avatar
jaco committed
147 148
        // scan background model vector
        for ( size_t z = 0; z < backgroundModel.size(); z++ )
149
        {
150 151
          float* currentB;
          float* currentC;
152 153
          currentB = & ( backgroundModel[z]->ptr<Vec2f>( i )[j][0] );
          currentC = & ( backgroundModel[z]->ptr<Vec2f>( i )[j][1] );
jaco's avatar
jaco committed
154

155
          //continue;
jaco's avatar
jaco committed
156
          if( ( *currentC ) > 0 )  //The current template is active
157
          {
jaco's avatar
jaco committed
158
            // If there is a match with a current background template
159
            if( abs( currentPixelValue - ( *currentB ) ) < currentEpslonValue && !backgFlag )
jaco's avatar
jaco committed
160 161 162
            {
              // The correspondence pixel in the  BF mask is set as background ( 0 value)
              pMask[j] = 0;
jaco's avatar
jaco committed
163 164
              if( ( *currentC < L0 && z == 0 ) || ( *currentC < L1 && z == 1 ) || ( z > 1 ) )
              {
165 166
                *currentC += 1;  // increment the efficacy of this template
              }
jaco's avatar
jaco committed
167

168
              *currentB = ( ( 1 - alpha ) * ( *currentB ) ) + ( alpha * currentPixelValue );  // Update the template value
jaco's avatar
jaco committed
169 170 171 172
              backgFlag = true;
            }
            else
            {
173
              *currentC -= 1;  // decrement the efficacy of this template
jaco's avatar
jaco committed
174 175
            }

176
          }
177

jaco's avatar
jaco committed
178
        }  // end "for" cicle of template vector
179

jaco's avatar
jaco committed
180 181 182 183 184
      }
      else
      {
        pMask[j] = 1;  //if the model of the current pixel is not yet initialized, we mark the pixels as foreground
      }
jaco's avatar
jaco committed
185

186
    }
187
  }  // end "for" cicle of all image's pixels
188

jaco's avatar
jaco committed
189 190
  return true;
}
jaco's avatar
jaco committed
191 192

bool MotionSaliencyBinWangApr2014::lowResolutionDetection( const Mat& image, Mat& lowResBFMask )
jaco's avatar
jaco committed
193
{
jaco's avatar
jaco committed
194
  std::vector<Mat> mv;
195
  split( *backgroundModel[0], mv );
196

jaco's avatar
jaco committed
197
  //if at least the first template is activated / initialized for all pixels
198
  if( countNonZero( mv[1] ) > ( mv[1].cols * mv[1].rows ) / 2 )
jaco's avatar
jaco committed
199 200 201 202 203
  {
    float currentPixelValue;
    float currentEpslonValue;
    float currentB;
    float currentC;
jaco's avatar
jaco committed
204

jaco's avatar
jaco committed
205
    // Create a mask to select ROI in the original Image and Backgound model and at the same time compute the mean
jaco's avatar
jaco committed
206

jaco's avatar
jaco committed
207 208 209 210
    Rect roi( Point( 0, 0 ), Size( N, N ) );
    Scalar imageROImean;
    Scalar backGModelROImean;
    Mat currentModel;
jaco's avatar
jaco committed
211

jaco's avatar
jaco committed
212
    // Initially, all pixels are considered as foreground and then we evaluate with the background model
213
    lowResBFMask.create( image.rows, image.cols, CV_32F );
jaco's avatar
jaco committed
214
    lowResBFMask.setTo( 1 );
jaco's avatar
jaco committed
215

jaco's avatar
jaco committed
216
    // Scan all the ROI of original matrices
217
    for ( int i = 0; i < ceil( (float) image.rows / N ); i++ )
jaco's avatar
jaco committed
218
    {
219 220 221 222 223 224 225
      if( ( roi.y + ( N - 1 ) ) <= ( image.rows - 1 ) )
      {
        // Reset original ROI dimension
        roi = Rect( Point( roi.x, roi.y ), Size( N, N ) );
      }

      for ( int j = 0; j < ceil( (float) image.cols / N ); j++ )
jaco's avatar
jaco committed
226
      {
jaco's avatar
jaco committed
227 228 229
        // Compute the mean of image's block and epslonMatrix's block based on ROI
        Mat roiImage = image( roi );
        Mat roiEpslon = epslonPixelsValue( roi );
jaco's avatar
jaco committed
230 231
        currentPixelValue = (float) mean( roiImage ).val[0];
        currentEpslonValue = (float) mean( roiEpslon ).val[0];
jaco's avatar
jaco committed
232 233 234

        // scan background model vector
        for ( int z = 0; z < N_DS; z++ )
235
        {
jaco's avatar
jaco committed
236
          // Select the current template 2 channel matrix, select ROI and compute the mean for each channel separately
237
          Mat roiTemplate = ( * ( backgroundModel[z] ) )( roi );
jaco's avatar
jaco committed
238
          Scalar templateMean = mean( roiTemplate );
jaco's avatar
jaco committed
239 240
          currentB = (float) templateMean[0];
          currentC = (float) templateMean[1];
jaco's avatar
jaco committed
241

jaco's avatar
jaco committed
242
          if( ( currentC ) > 0 )  //The current template is active
243
          {
jaco's avatar
jaco committed
244 245 246 247 248 249 250
            // If there is a match with a current background template
            if( abs( currentPixelValue - ( currentB ) ) < currentEpslonValue )
            {
              // The correspondence pixel in the  BF mask is set as background ( 0 value)
              rectangle( lowResBFMask, roi, Scalar( 0 ), FILLED );
              break;
            }
251 252
          }
        }
jaco's avatar
jaco committed
253 254
        // Shift the ROI from left to right follow the block dimension
        roi = roi + Point( N, 0 );
255 256
        if( ( roi.x + ( roi.width - 1 ) ) > ( image.cols - 1 ) && ( roi.y + ( N - 1 ) ) <= ( image.rows - 1 ) )
        {
257
          roi = Rect( Point( roi.x, roi.y ), Size( abs( ( image.cols - 1 ) - roi.x ) + 1, N ) );
258 259 260
        }
        else if( ( roi.x + ( roi.width - 1 ) ) > ( image.cols - 1 ) && ( roi.y + ( N - 1 ) ) > ( image.rows - 1 ) )
        {
261
          roi = Rect( Point( roi.x, roi.y ), Size( abs( ( image.cols - 1 ) - roi.x ) + 1, abs( ( image.rows - 1 ) - roi.y ) + 1 ) );
262
        }
jaco's avatar
jaco committed
263
      }
jaco's avatar
jaco committed
264 265 266
      //Shift the ROI from up to down follow the block dimension, also bringing it back to beginning of row
      roi.x = 0;
      roi.y += N;
267 268
      if( ( roi.y + ( roi.height - 1 ) ) > ( image.rows - 1 ) )
      {
269
        roi = Rect( Point( roi.x, roi.y ), Size( N, abs( ( image.rows - 1 ) - roi.y ) + 1 ) );
270 271
      }

jaco's avatar
jaco committed
272
    }
jaco's avatar
jaco committed
273 274 275 276
    return true;
  }
  else
  {
277
    lowResBFMask.create( image.rows, image.cols, CV_32F );
278
    lowResBFMask.setTo( 1 );
jaco's avatar
jaco committed
279
    return false;
jaco's avatar
jaco committed
280 281
  }

jaco's avatar
jaco committed
282
}
283

jaco's avatar
jaco committed
284
bool inline pairCompare( std::pair<float, float> t, std::pair<float, float> t_plusOne )
jaco's avatar
jaco committed
285 286 287 288 289 290
{

  return ( t.second > t_plusOne.second );

}

jaco's avatar
jaco committed
291 292 293
// Background model maintenance functions
bool MotionSaliencyBinWangApr2014::templateOrdering()
{
jaco's avatar
jaco committed
294
  std::vector<std::pair<float, float> > pixelTemplates( backgroundModel.size() );
295 296 297

  Vec2f* bgModel_0P;
  Vec2f* bgModel_1P;
jaco's avatar
jaco committed
298

299
// Scan all pixels of image
300
  for ( int i = 0; i < backgroundModel[0]->rows; i++ )
jaco's avatar
jaco committed
301
  {
302 303
    bgModel_0P = backgroundModel[0]->ptr<Vec2f>( i );
    bgModel_1P = backgroundModel[1]->ptr<Vec2f>( i );
304
    for ( int j = 0; j < backgroundModel[0]->cols; j++ )
jaco's avatar
jaco committed
305
    {
jaco's avatar
jaco committed
306 307
      // scan background model vector from T1 to Tk
      for ( size_t z = 1; z < backgroundModel.size(); z++ )
jaco's avatar
jaco committed
308
      {
309
        Vec2f bgModel_zP = backgroundModel[z]->ptr<Vec2f>( i )[j];
jaco's avatar
jaco committed
310
        // Fill vector of pairs
311 312
        pixelTemplates[z - 1].first = bgModel_zP[0];  // Current B (background value)
        pixelTemplates[z - 1].second = bgModel_zP[1];  // Current C (efficacy value)
jaco's avatar
jaco committed
313 314
      }

jaco's avatar
jaco committed
315
      //SORT template from T1 to Tk
jaco's avatar
jaco committed
316 317
      std::sort( pixelTemplates.begin(), pixelTemplates.end(), pairCompare );

jaco's avatar
jaco committed
318 319
      //REFILL CURRENT MODEL ( T1...Tk)
      for ( size_t zz = 1; zz < backgroundModel.size(); zz++ )
jaco's avatar
jaco committed
320
      {
321 322
        backgroundModel[zz]->ptr<Vec2f>( i )[j][0] = pixelTemplates[zz - 1].first;  // Replace previous B with new ordered B value
        backgroundModel[zz]->ptr<Vec2f>( i )[j][1] = pixelTemplates[zz - 1].second;  // Replace previous C with new ordered C value
jaco's avatar
jaco committed
323 324 325
      }

      // SORT Template T0 and T1
326
      if( bgModel_1P[j][1] > thetaL && bgModel_0P[j][1] < thetaL )
jaco's avatar
jaco committed
327 328 329
      {

        // swap B value of T0 with B value of T1 (for current model)
330
        swap( bgModel_0P[j][0], bgModel_1P[j][0] );
jaco's avatar
jaco committed
331 332

        // set new C0 value for current model)
333
        swap( bgModel_0P[j][1], bgModel_1P[j][1] );
jaco's avatar
jaco committed
334
        bgModel_0P[j][1] = (float) gamma * thetaL;
jaco's avatar
jaco committed
335

jaco's avatar
jaco committed
336 337 338 339
      }

    }
  }
jaco's avatar
jaco committed
340 341 342

  return true;
}
343
bool MotionSaliencyBinWangApr2014::templateReplacement( const Mat& finalBFMask, const Mat& image )
jaco's avatar
jaco committed
344
{
jaco's avatar
jaco committed
345
  std::vector<Mat> temp;
346
  split( *backgroundModel[0], temp );
jaco's avatar
jaco committed
347

348
//if at least the first template is activated / initialized for all pixels
349
  if( countNonZero( temp[1] ) <= ( temp[1].cols * temp[1].rows ) / 2 )
jaco's avatar
jaco committed
350
  {
351 352
    thetaA = 50;
    thetaL = 150;
jaco's avatar
jaco committed
353 354 355 356 357
    neighborhoodCheck = false;

  }
  else
  {
358 359
    thetaA = thetaA_VAL;
    thetaL = thetaL_VAL;
360
    neighborhoodCheck = true;
jaco's avatar
jaco committed
361 362
  }

jaco's avatar
jaco committed
363
  int roiSize = 3;  // FIXED ROI SIZE, not change until you first appropriately adjust the following controls in the EVALUATION section!
364
  int countNonZeroElements = 0;
365
  std::vector<Mat> mv;
jaco's avatar
jaco committed
366 367 368
  Mat replicateCurrentBAMat( roiSize, roiSize, CV_32F );
  Mat backgroundModelROI( roiSize, roiSize, CV_32F );
  Mat diffResult( roiSize, roiSize, CV_32F );
jaco's avatar
jaco committed
369

370
// Scan all pixels of finalBFMask and all pixels of others models (the dimension are the same)
371 372 373 374
  const float* finalBFMaskP;
  Vec2f* pbgP;
  const uchar* imageP;
  float* epslonP;
375 376
  for ( int i = 0; i < finalBFMask.rows; i++ )
  {
377 378 379 380
    finalBFMaskP = finalBFMask.ptr<float>( i );
    pbgP = potentialBackground.ptr<Vec2f>( i );
    imageP = image.ptr<uchar>( i );
    epslonP = epslonPixelsValue.ptr<float>( i );
381 382
    for ( int j = 0; j < finalBFMask.cols; j++ )
    {
383
      /////////////////// MAINTENANCE of potentialBackground model ///////////////////
384
      if( finalBFMaskP[j] == 1 )  // i.e. the corresponding frame pixel has been market as foreground
385 386 387
      {
        /* For the pixels with CA= 0, if the current frame pixel has been classified as foreground, its value
         * will be loaded into BA and CA will be set to 1*/
388
        if( pbgP[j][1] == 0 )
389
        {
390 391
          pbgP[j][0] = (float) imageP[j];
          pbgP[j][1] = 1;
392 393 394 395
        }

        /*the distance between this pixel value and BA is calculated, and if this distance is smaller than
         the decision threshold epslon, then CA is increased by 1, otherwise is decreased by 1*/
396
        else if( abs( (float) imageP[j] - pbgP[j][0] ) < epslonP[j] )
397
        {
398
          pbgP[j][1] += 1;
399 400 401
        }
        else
        {
402
          pbgP[j][1] -= 1;
403
        }
404 405
        /*}*/  /////////////////// END of potentialBackground model MAINTENANCE///////////////////
        /////////////////// EVALUATION of potentialBackground values ///////////////////
406
        if( pbgP[j][1] > thetaA )
407
        {
jaco's avatar
jaco committed
408
          if( neighborhoodCheck )
409
          {
jaco's avatar
jaco committed
410
            // replicate currentBA value
411
            replicateCurrentBAMat.setTo( pbgP[j][0] );
412

jaco's avatar
jaco committed
413
            for ( size_t z = 0; z < backgroundModel.size(); z++ )
414
            {
jaco's avatar
jaco committed
415 416 417
              // Neighborhood of current pixel in the current background model template.
              // The ROI is centered in the pixel coordinates

418
              if( i > 0 && j > 0 && i < ( backgroundModel[z]->rows - 1 ) && j < ( backgroundModel[z]->cols - 1 ) )
jaco's avatar
jaco committed
419
              {
420
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
421
                backgroundModelROI = mv[0]( Rect( j - (int) floor( roiSize / 2 ), i - (int) floor( roiSize / 2 ), roiSize, roiSize ) );
jaco's avatar
jaco committed
422
              }
jaco's avatar
jaco committed
423
              else if( i == 0 && j == 0 )  // upper leftt
jaco's avatar
jaco committed
424
              {
425
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
426
                backgroundModelROI = mv[0]( Rect( j, i, (int) ceil( roiSize / 2 ), (int) ceil( roiSize / 2 ) ) );
jaco's avatar
jaco committed
427
              }
428
              else if( j == 0 && i > 0 && i < ( backgroundModel[z]->rows - 1 ) )  // middle left
jaco's avatar
jaco committed
429
              {
430
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
431
                backgroundModelROI = mv[0]( Rect( j, i - (int) floor( roiSize / 2 ), (int) ceil( roiSize / 2 ), roiSize ) );
jaco's avatar
jaco committed
432
              }
433
              else if( i == ( backgroundModel[z]->rows - 1 ) && j == 0 )  //down left
jaco's avatar
jaco committed
434
              {
435
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
436
                backgroundModelROI = mv[0]( Rect( j, i - (int) floor( roiSize / 2 ), (int) ceil( roiSize / 2 ), (int) ceil( roiSize / 2 ) ) );
jaco's avatar
jaco committed
437
              }
438
              else if( i == 0 && j > 0 && j < ( backgroundModel[z]->cols - 1 ) )  // upper - middle
jaco's avatar
jaco committed
439
              {
440
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
441
                backgroundModelROI = mv[0]( Rect( ( j - (int) floor( roiSize / 2 ) ), i, roiSize, (int) ceil( roiSize / 2 ) ) );
jaco's avatar
jaco committed
442
              }
443
              else if( i == ( backgroundModel[z]->rows - 1 ) && j > 0 && j < ( backgroundModel[z]->cols - 1 ) )  //down middle
jaco's avatar
jaco committed
444
              {
445
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
446 447
                backgroundModelROI = mv[0](
                    Rect( j - (int) floor( roiSize / 2 ), i - (int) floor( roiSize / 2 ), roiSize, (int) ceil( roiSize / 2 ) ) );
jaco's avatar
jaco committed
448
              }
449
              else if( i == 0 && j == ( backgroundModel[z]->cols - 1 ) )  // upper right
jaco's avatar
jaco committed
450
              {
451
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
452
                backgroundModelROI = mv[0]( Rect( j - (int) floor( roiSize / 2 ), i, (int) ceil( roiSize / 2 ), (int) ceil( roiSize / 2 ) ) );
jaco's avatar
jaco committed
453
              }
454
              else if( j == ( backgroundModel[z]->cols - 1 ) && i > 0 && i < ( backgroundModel[z]->rows - 1 ) )  // middle - right
jaco's avatar
jaco committed
455
              {
456
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
457 458
                backgroundModelROI = mv[0](
                    Rect( j - (int) floor( roiSize / 2 ), i - (int) floor( roiSize / 2 ), (int) ceil( roiSize / 2 ), roiSize ) );
jaco's avatar
jaco committed
459
              }
460
              else if( i == ( backgroundModel[z]->rows - 1 ) && j == ( backgroundModel[z]->cols - 1 ) )  // down right
jaco's avatar
jaco committed
461
              {
462
                split( *backgroundModel[z], mv );
jaco's avatar
jaco committed
463 464
                backgroundModelROI = mv[0](
                    Rect( j - (int) floor( roiSize / 2 ), i - (int) floor( roiSize / 2 ), (int) ceil( roiSize / 2 ), (int) ceil( roiSize / 2 ) ) );
jaco's avatar
jaco committed
465 466 467 468 469 470 471 472 473
              }

              /* Check if the value of current pixel BA in potentialBackground model is already contained in at least one of its neighbors'
               * background model
               */
              resize( replicateCurrentBAMat, replicateCurrentBAMat, Size( backgroundModelROI.cols, backgroundModelROI.rows ), 0, 0, INTER_LINEAR );
              resize( diffResult, diffResult, Size( backgroundModelROI.cols, backgroundModelROI.rows ), 0, 0, INTER_LINEAR );

              absdiff( replicateCurrentBAMat, backgroundModelROI, diffResult );
474
              threshold( diffResult, diffResult, epslonP[j], 255, THRESH_BINARY_INV );
jaco's avatar
jaco committed
475 476 477 478 479 480
              countNonZeroElements = countNonZero( diffResult );

              if( countNonZeroElements > 0 )
              {
                /////////////////// REPLACEMENT of backgroundModel template ///////////////////
                //replace TA with current TK
481
                backgroundModel[backgroundModel.size() - 1]->at<Vec2f>( i, j ) = potentialBackground.at<Vec2f>( i, j );
482
                potentialBackground.at<Vec2f>( i, j )[0] = (float)NAN;
483
                potentialBackground.at<Vec2f>( i, j )[1] = 0;
484

jaco's avatar
jaco committed
485 486 487 488 489 490
                break;
              }
            }  // end for backgroundModel size
          }
          else
          {
491
            backgroundModel[backgroundModel.size() - 1]->at<Vec2f>( i, j ) = potentialBackground.at<Vec2f>( i, j );
492
            potentialBackground.at<Vec2f>( i, j )[0] = (float)NAN;
jaco's avatar
jaco committed
493
            potentialBackground.at<Vec2f>( i, j )[1] = 0;
jaco's avatar
jaco committed
494
          }
495 496
        }  // close if of EVALUATION
      }  // end of  if( finalBFMask.at<uchar>( i, j ) == 1 )  // i.e. the corresponding frame pixel has been market as foreground
497

498 499
    }  // end of second for
  }  // end of first for
500

jaco's avatar
jaco committed
501 502 503
  return true;
}

504
bool MotionSaliencyBinWangApr2014::computeSaliencyImpl( InputArray image, OutputArray saliencyMap )
jaco's avatar
jaco committed
505
{
506 507 508 509
  Mat highResBFMask;
  Mat lowResBFMask;
  Mat not_lowResBFMask;
  Mat noisePixelsMask;
jaco's avatar
jaco committed
510

511 512
  fullResolutionDetection( image.getMat(), highResBFMask );
  lowResolutionDetection( image.getMat(), lowResBFMask );
jaco's avatar
jaco committed
513

514

515 516
// Compute the final background-foreground mask. One pixel is marked as foreground if and only if it is
// foreground in both masks (full and low)
517
  bitwise_and( highResBFMask, lowResBFMask, saliencyMap );
jaco's avatar
jaco committed
518

519
  templateOrdering();
520
  templateReplacement( saliencyMap.getMat(), image.getMat() );
521
  templateOrdering();
jaco's avatar
jaco committed
522

jaco's avatar
jaco committed
523 524 525
  return true;
}

jaco's avatar
jaco committed
526
}  // namespace saliency
jaco's avatar
jaco committed
527
}  // namespace cv