motionSaliencyBinWangApr2014.cpp 20 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
 // 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*/

42
#include <limits>
jaco's avatar
jaco committed
43
#include "precomp.hpp"
44
//TODO delete highgui include
45
//#include <opencv2/highgui.hpp>
jaco's avatar
jaco committed
46

47 48 49
#define thetaA_VAL 200
#define thetaL_VAL 250

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

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

MotionSaliencyBinWangApr2014::MotionSaliencyBinWangApr2014()
{
63
  N_DS = 2;  // Number of template to be downsampled and used in lowResolutionDetection function
jaco's avatar
jaco committed
64
  K = 3;  // Number of background model template
jaco's avatar
jaco committed
65
  N = 4;   // NxN is the size of the block for downsampling in the lowlowResolutionDetection
jaco's avatar
jaco committed
66
  alpha = (float) 0.01;  // Learning rate
67 68
  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
69 70
  thetaL = thetaL_VAL;  // T0, T1 swap threshold
  thetaA = thetaA_VAL;
jaco's avatar
jaco committed
71
  gamma = 3;
jaco's avatar
jaco committed
72
  neighborhoodCheck = true;
jaco's avatar
jaco committed
73 74 75 76

  className = "BinWangApr2014";
}

77 78
bool MotionSaliencyBinWangApr2014::init()
{
jaco's avatar
jaco committed
79 80
  Size imgSize( imageWidth, imageHeight );
  epslonPixelsValue = Mat( imgSize.height, imgSize.width, CV_32F, Scalar( 20 ) );
81 82 83 84
  // 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).

85
  potentialBackground = Mat( imgSize.height, imgSize.width, CV_32FC2, Scalar( std::numeric_limits<float>::quiet_NaN(), 0 ) );
86

87
  backgroundModel.resize( K + 1 );
88

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

  return true;

}

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

177
          }
178

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

jaco's avatar
jaco committed
181 182 183 184 185
      }
      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
186

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

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

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

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

jaco's avatar
jaco committed
206
    // 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
207

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

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

jaco's avatar
jaco committed
217
    // Scan all the ROI of original matrices
218
    for ( int i = 0; i < ceil( (float) image.rows / N ); i++ )
jaco's avatar
jaco committed
219
    {
220 221 222 223 224 225 226
      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
227
      {
jaco's avatar
jaco committed
228 229 230
        // 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
231 232
        currentPixelValue = (float) mean( roiImage ).val[0];
        currentEpslonValue = (float) mean( roiEpslon ).val[0];
jaco's avatar
jaco committed
233 234 235

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

jaco's avatar
jaco committed
243
          if( ( currentC ) > 0 )  //The current template is active
244
          {
jaco's avatar
jaco committed
245 246 247 248 249 250 251
            // 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;
            }
252 253
          }
        }
jaco's avatar
jaco committed
254 255
        // Shift the ROI from left to right follow the block dimension
        roi = roi + Point( N, 0 );
256 257
        if( ( roi.x + ( roi.width - 1 ) ) > ( image.cols - 1 ) && ( roi.y + ( N - 1 ) ) <= ( image.rows - 1 ) )
        {
258
          roi = Rect( Point( roi.x, roi.y ), Size( abs( ( image.cols - 1 ) - roi.x ) + 1, N ) );
259 260 261
        }
        else if( ( roi.x + ( roi.width - 1 ) ) > ( image.cols - 1 ) && ( roi.y + ( N - 1 ) ) > ( image.rows - 1 ) )
        {
262
          roi = Rect( Point( roi.x, roi.y ), Size( abs( ( image.cols - 1 ) - roi.x ) + 1, abs( ( image.rows - 1 ) - roi.y ) + 1 ) );
263
        }
jaco's avatar
jaco committed
264
      }
jaco's avatar
jaco committed
265 266 267
      //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;
268 269
      if( ( roi.y + ( roi.height - 1 ) ) > ( image.rows - 1 ) )
      {
270
        roi = Rect( Point( roi.x, roi.y ), Size( N, abs( ( image.rows - 1 ) - roi.y ) + 1 ) );
271 272
      }

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

jaco's avatar
jaco committed
283
}
284

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

  return ( t.second > t_plusOne.second );

}

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

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

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

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

jaco's avatar
jaco committed
319 320
      //REFILL CURRENT MODEL ( T1...Tk)
      for ( size_t zz = 1; zz < backgroundModel.size(); zz++ )
jaco's avatar
jaco committed
321
      {
322 323
        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
324 325 326
      }

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

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

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

jaco's avatar
jaco committed
337 338 339 340
      }

    }
  }
jaco's avatar
jaco committed
341 342 343

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

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

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

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

371
// Scan all pixels of finalBFMask and all pixels of others models (the dimension are the same)
372 373 374 375
  const float* finalBFMaskP;
  Vec2f* pbgP;
  const uchar* imageP;
  float* epslonP;
376 377
  for ( int i = 0; i < finalBFMask.rows; i++ )
  {
378 379 380 381
    finalBFMaskP = finalBFMask.ptr<float>( i );
    pbgP = potentialBackground.ptr<Vec2f>( i );
    imageP = image.ptr<uchar>( i );
    epslonP = epslonPixelsValue.ptr<float>( i );
382 383
    for ( int j = 0; j < finalBFMask.cols; j++ )
    {
384
      /////////////////// MAINTENANCE of potentialBackground model ///////////////////
385
      if( finalBFMaskP[j] == 1 )  // i.e. the corresponding frame pixel has been market as foreground
386 387 388
      {
        /* 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*/
389
        if( pbgP[j][1] == 0 )
390
        {
391 392
          pbgP[j][0] = (float) imageP[j];
          pbgP[j][1] = 1;
393 394 395 396
        }

        /*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*/
397
        else if( abs( (float) imageP[j] - pbgP[j][0] ) < epslonP[j] )
398
        {
399
          pbgP[j][1] += 1;
400 401 402
        }
        else
        {
403
          pbgP[j][1] -= 1;
404
        }
405 406
        /*}*/  /////////////////// END of potentialBackground model MAINTENANCE///////////////////
        /////////////////// EVALUATION of potentialBackground values ///////////////////
407
        if( pbgP[j][1] > thetaA )
408
        {
jaco's avatar
jaco committed
409
          if( neighborhoodCheck )
410
          {
jaco's avatar
jaco committed
411
            // replicate currentBA value
412
            replicateCurrentBAMat.setTo( pbgP[j][0] );
413

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

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

              /* 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 );
475
              threshold( diffResult, diffResult, epslonP[j], 255, THRESH_BINARY_INV );
jaco's avatar
jaco committed
476 477 478 479 480 481
              countNonZeroElements = countNonZero( diffResult );

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

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

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

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

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

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

515

516 517
// 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)
518
  bitwise_and( highResBFMask, lowResBFMask, saliencyMap );
jaco's avatar
jaco committed
519

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

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

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