test_trackers.cpp 15.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 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 43
/*M///////////////////////////////////////////////////////////////////////////////////////
 //
 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 //
 //  By downloading, copying, installing or using the software you agree to this license.
 //  If you do not agree to this license, do not download, install,
 //  copy or use the software.
 //
 //
 //                           License Agreement
 //                For Open Source Computer Vision Library
 //
 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
 // Third party copyrights are property of their respective owners.
 //
 // Redistribution and use in source and binary forms, with or without modification,
 // are permitted provided that the following conditions are met:
 //
 //   * Redistribution's of source code must retain the above copyright notice,
 //     this list of conditions and the following disclaimer.
 //
 //   * Redistribution's in binary form must reproduce the above copyright notice,
 //     this list of conditions and the following disclaimer in the documentation
 //     and/or other materials provided with the distribution.
 //
 //   * The name of the copyright holders may not be used to endorse or promote products
 //     derived from this software without specific prior written permission.
 //
 // This software is provided by the copyright holders and contributors "as is" and
 // any express or implied warranties, including, but not limited to, the implied
 // warranties of merchantability and fitness for a particular purpose are disclaimed.
 // In no event shall the Intel Corporation or contributors be liable for any direct,
 // indirect, incidental, special, exemplary, or consequential damages
 // (including, but not limited to, procurement of substitute goods or services;
 // loss of use, data, or profits; or business interruption) however caused
 // and on any theory of liability, whether in contract, strict liability,
 // or tort (including negligence or otherwise) arising in any way out of
 // the use of this software, even if advised of the possibility of such damage.
 //
 //M*/

#include "test_precomp.hpp"

44
namespace opencv_test { namespace {
45 46 47 48 49 50 51 52 53 54 55 56 57 58

#define TESTSET_NAMES testing::Values("david","dudek","faceocc2")

const string TRACKING_DIR = "tracking";
const string FOLDER_IMG = "data";
const string FOLDER_OMIT_INIT = "initOmit";

/*
 * The Evaluation Methodologies are partially based on:
 * ====================================================================================================================
 *  [OTB] Y. Wu, J. Lim, and M.-H. Yang, "Online object tracking: A benchmark," in Computer Vision and Pattern Recognition (CVPR), 2013
 *
 */

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
enum BBTransformations
{
    NoTransform = 0,
    CenterShiftLeft = 1,
    CenterShiftRight = 2,
    CenterShiftUp = 3,
    CenterShiftDown = 4,
    CornerShiftTopLeft = 5,
    CornerShiftTopRight = 6,
    CornerShiftBottomLeft = 7,
    CornerShiftBottomRight = 8,
    Scale_0_8 = 9,
    Scale_0_9 = 10,
    Scale_1_1 = 11,
    Scale_1_2 = 12
};

class TrackerTest
77 78 79
{
 public:

80 81
  TrackerTest(Ptr<Tracker> _tracker, string _video, float _distanceThreshold,
                 float _overlapThreshold, int _shift = NoTransform, int _segmentIdx = 1, int _numSegments = 10 );
82
  virtual ~TrackerTest();
83 84 85 86 87
  virtual void run();

 protected:
  void checkDataTest();

88
  void distanceAndOvrerlapTest();
89 90 91 92 93 94 95

  Ptr<Tracker> tracker;
  string video;
  std::vector<Rect> bbs;
  int startFrame;
  string suffix;
  string prefix;
96 97
  float overlapThreshold;
  float distanceThreshold;
98
  int segmentIdx;
99 100 101 102 103
  int shift;
  int numSegments;

  int gtStartFrame;
  int endFrame;
104 105 106 107 108
  vector<int> validSequence;

 private:
  float calcDistance( Rect a, Rect b );
  float calcOverlap( Rect a, Rect b );
109
  Rect applyShift(Rect bb);
110 111 112 113
  std::vector<std::string> splitString( std::string s, std::string delimiter );

};

114 115
TrackerTest::TrackerTest(Ptr<Tracker> _tracker, string _video, float _distanceThreshold,
                                float _overlapThreshold, int _shift, int _segmentIdx, int _numSegments ) :
116 117
    tracker( _tracker ),
    video( _video ),
118 119
    overlapThreshold( _overlapThreshold ),
    distanceThreshold( _distanceThreshold ),
120 121 122
    segmentIdx(_segmentIdx),
    shift(_shift),
    numSegments(_numSegments)
123 124 125
{
}

126
TrackerTest::~TrackerTest()
127 128 129 130
{

}

131
std::vector<std::string> TrackerTest::splitString( std::string s, std::string delimiter )
132 133 134 135 136 137 138 139 140 141 142 143
{
  std::vector<string> token;
  size_t pos = 0;
  while ( ( pos = s.find( delimiter ) ) != std::string::npos )
  {
    token.push_back( s.substr( 0, pos ) );
    s.erase( 0, pos + delimiter.length() );
  }
  token.push_back( s );
  return token;
}

144
float TrackerTest::calcDistance( Rect a, Rect b )
145
{
Ilya Lavrenov's avatar
Ilya Lavrenov committed
146 147
  Point2f p_a( (float)(a.x + a.width / 2), (float)(a.y + a.height / 2) );
  Point2f p_b( (float)(b.x + b.width / 2), (float)(b.y + b.height / 2) );
148 149 150
  return sqrt( pow( p_a.x - p_b.x, 2 ) + pow( p_a.y - p_b.y, 2 ) );
}

151
float TrackerTest::calcOverlap( Rect a, Rect b )
152
{
153 154
  float rectIntersectionArea = (float)(a & b).area();
  return rectIntersectionArea / (a.area() + b.area() - rectIntersectionArea);
155 156
}

157
Rect TrackerTest::applyShift(Rect bb)
158
{
159
  Point center( bb.x + ( bb.width / 2 ), bb.y + ( bb.height / 2 ) );
160

161 162
  int xLimit = bb.x + bb.width - 1;
  int yLimit = bb.y + bb.height - 1;
163

164 165 166
  int h = 0;
  int w = 0;
  float ratio = 1.0;
167

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
  switch ( shift )
  {
    case CenterShiftLeft:
      bb.x = bb.x - (int)ceil( 0.1 * bb.width );
      break;
    case CenterShiftRight:
      bb.x = bb.x + (int)ceil( 0.1 * bb.width );
      break;
    case CenterShiftUp:
      bb.y = bb.y - (int)ceil( 0.1 * bb.height );
      break;
    case CenterShiftDown:
      bb.y = bb.y + (int)ceil( 0.1 * bb.height );
      break;
    case CornerShiftTopLeft:
      bb.x = (int)cvRound( bb.x -  0.1 * bb.width );
      bb.y = (int)cvRound( bb.y - 0.1 * bb.height );
185

186 187 188 189 190
      bb.width = xLimit - bb.x + 1;
      bb.height = yLimit - bb.y + 1;
      break;
    case CornerShiftTopRight:
      xLimit = (int)cvRound( xLimit + 0.1 * bb.width );
191

192 193 194
      bb.y = (int)cvRound( bb.y - 0.1 * bb.height );
      bb.width = xLimit - bb.x + 1;
      bb.height = yLimit - bb.y + 1;
195
      break;
196 197 198 199 200 201
    case CornerShiftBottomLeft:
      bb.x = (int)cvRound( bb.x - 0.1 * bb.width );
      yLimit = (int)cvRound( yLimit + 0.1 * bb.height );

      bb.width = xLimit - bb.x + 1;
      bb.height = yLimit - bb.y + 1;
202
      break;
203 204 205
    case CornerShiftBottomRight:
      xLimit = (int)cvRound( xLimit + 0.1 * bb.width );
      yLimit = (int)cvRound( yLimit + 0.1 * bb.height );
206

207 208 209 210 211 212 213
      bb.width = xLimit - bb.x + 1;
      bb.height = yLimit - bb.y + 1;
      break;
    case Scale_0_8:
      ratio = 0.8f;
      w = (int)(ratio * bb.width);
      h = (int)(ratio * bb.height);
214

215 216 217 218 219 220
      bb = Rect( center.x - ( w / 2 ), center.y - ( h / 2 ), w, h );
      break;
    case Scale_0_9:
      ratio = 0.9f;
      w = (int)(ratio * bb.width);
      h = (int)(ratio * bb.height);
221

222 223 224 225 226 227 228
      bb = Rect( center.x - ( w / 2 ), center.y - ( h / 2 ), w, h );
      break;
    case 11:
      //scale 1.1
      ratio = 1.1f;
      w = (int)(ratio * bb.width);
      h = (int)(ratio * bb.height);
229

230 231 232 233 234 235 236 237 238 239 240 241
      bb = Rect( center.x - ( w / 2 ), center.y - ( h / 2 ), w, h );
      break;
    case 12:
      //scale 1.2
      ratio = 1.2f;
      w = (int)(ratio * bb.width);
      h = (int)(ratio * bb.height);

      bb = Rect( center.x - ( w / 2 ), center.y - ( h / 2 ), w, h );
      break;
    default:
      break;
242 243
  }

244
  return bb;
245 246
}

247
void TrackerTest::distanceAndOvrerlapTest()
248 249 250 251 252
{
  Mat frame;
  bool initialized = false;

  int fc = ( startFrame - gtStartFrame );
253 254

  bbs.at( fc ) = applyShift(bbs.at( fc ));
255 256
  Rect currentBBi = bbs.at( fc );
  Rect2d currentBB(currentBBi);
257
  float sumDistance = 0;
258 259
  float sumOverlap = 0;

260
  string folder = cvtest::TS::ptr()->get_data_path() + "/" + TRACKING_DIR + "/" + video + "/" + FOLDER_IMG;
261 262

  VideoCapture c;
263
  c.open( folder + "/" + video + ".webm" );
264 265 266 267 268
  c.set( CAP_PROP_POS_FRAMES, startFrame );

  for ( int frameCounter = startFrame; frameCounter < endFrame; frameCounter++ )
  {
    c >> frame;
269

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    if( frame.empty() )
    {
      break;
    }
    if( !initialized )
    {
      if( !tracker->init( frame, currentBB ) )
      {
        FAIL()<< "Could not initialize tracker" << endl;
        return;
      }
      initialized = true;
    }
    else if( initialized )
    {
      if( frameCounter >= (int) bbs.size() )
      break;
      tracker->update( frame, currentBB );
    }
289
    float curDistance = calcDistance( currentBB, bbs.at( fc ) );
290 291
    float curOverlap = calcOverlap( currentBB, bbs.at( fc ) );

292
    sumDistance += curDistance;
293 294 295 296
    sumOverlap += curOverlap;
    fc++;
  }

297 298
  float meanDistance = sumDistance / (endFrame - startFrame);
  float meanOverlap = sumOverlap / (endFrame - startFrame);
299

300
  if( meanDistance > distanceThreshold )
301
  {
302 303 304 305 306 307 308
    FAIL()<< "Incorrect distance: curr = " << meanDistance << ", max = " << distanceThreshold << endl;
    return;
  }

  if( meanOverlap < overlapThreshold )
  {
    FAIL()<< "Incorrect overlap: curr = " << meanOverlap << ", min = " << overlapThreshold << endl;
309 310 311 312
    return;
  }
}

313
void TrackerTest::checkDataTest()
314 315 316 317 318 319 320 321 322 323
{

  FileStorage fs;
  fs.open( cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/" + video + ".yml", FileStorage::READ );
  fs["start"] >> startFrame;
  fs["prefix"] >> prefix;
  fs["suffix"] >> suffix;
  fs.release();

  string gtFile = cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/gt.txt";
324
  std::ifstream gt;
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
  //open the ground truth
  gt.open( gtFile.c_str() );
  if( !gt.is_open() )
  {
    FAIL()<< "Ground truth file " << gtFile << " can not be read" << endl;
  }
  string line;
  int bbCounter = 0;
  while ( getline( gt, line ) )
  {
    bbCounter++;
  }
  gt.close();

  int seqLength = bbCounter;
  for ( int i = startFrame; i < seqLength; i++ )
  {
    validSequence.push_back( i );
  }

  //exclude from the images sequence, the frames where the target is occluded or out of view
  string omitFile = cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/" + FOLDER_OMIT_INIT + "/" + video + ".txt";
347
  std::ifstream omit;
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
  omit.open( omitFile.c_str() );
  if( omit.is_open() )
  {
    string omitLine;
    while ( getline( omit, omitLine ) )
    {
      vector<string> tokens = splitString( omitLine, " " );
      int s_start = atoi( tokens.at( 0 ).c_str() );
      int s_end = atoi( tokens.at( 1 ).c_str() );
      for ( int k = s_start; k <= s_end; k++ )
      {
        std::vector<int>::iterator position = std::find( validSequence.begin(), validSequence.end(), k );
        if( position != validSequence.end() )
          validSequence.erase( position );
      }
    }
  }
  omit.close();
  gtStartFrame = startFrame;
  //compute the start and the and for each segment
368
  int numFrame = (int)(validSequence.size() / numSegments);
369 370 371
  startFrame += ( segmentIdx - 1 ) * numFrame;
  endFrame = startFrame + numFrame;

372
  std::ifstream gt2;
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
  //open the ground truth
  gt2.open( gtFile.c_str() );
  if( !gt2.is_open() )
  {
    FAIL()<< "Ground truth file " << gtFile << " can not be read" << endl;
  }
  string line2;
  int bbCounter2 = 0;
  while ( getline( gt2, line2 ) )
  {
    vector<string> tokens = splitString( line2, "," );
    Rect bb( atoi( tokens.at( 0 ).c_str() ), atoi( tokens.at( 1 ).c_str() ), atoi( tokens.at( 2 ).c_str() ), atoi( tokens.at( 3 ).c_str() ) );
    if( tokens.size() != 4 )
    {
      FAIL()<< "Incorrect ground truth file";
    }

    bbs.push_back( bb );
    bbCounter2++;
  }
  gt2.close();

395 396
  if( segmentIdx == numSegments )
    endFrame = (int)bbs.size();
397 398
}

399
void TrackerTest::run()
400 401
{
  srand( 1 );
402

403 404 405 406 407 408 409 410 411 412 413 414 415 416
  SCOPED_TRACE( "A" );

  if( !tracker )
  {
    FAIL()<< "Error in the instantiation of the tracker" << endl;
    return;
  }

  checkDataTest();

  //check for failure
  if( ::testing::Test::HasFatalFailure() )
    return;

417
  distanceAndOvrerlapTest();
418 419 420 421 422 423
}

/****************************************************************************************\
*                                Tests registrations                                     *
 \****************************************************************************************/

424 425
//[TESTDATA]
PARAM_TEST_CASE(DistanceAndOverlap, string)
426 427 428 429 430 431 432 433
{
  string dataset;
  virtual void SetUp()
  {
    dataset = GET_PARAM(0);
  }
};

434
TEST_P(DistanceAndOverlap, MedianFlow)
435
{
436
  TrackerTest test( TrackerMedianFlow::create(), dataset, 35, .5f, NoTransform, 1, 1);
437 438
  test.run();
}
439

440
TEST_P(DistanceAndOverlap, MIL)
441
{
442
  TrackerTest test( TrackerMIL::create(), dataset, 30, .65f, NoTransform);
443 444 445
  test.run();
}

446
TEST_P(DistanceAndOverlap, Boosting)
447
{
448
  TrackerTest test( TrackerBoosting::create(), dataset, 70, .7f, NoTransform);
449 450 451
  test.run();
}

452 453
TEST_P(DistanceAndOverlap, KCF)
{
454
  TrackerTest test( TrackerKCF::create(), dataset, 20, .35f, NoTransform, 5);
455 456 457
  test.run();
}

458
TEST_P(DistanceAndOverlap, TLD)
459
{
460
  TrackerTest test( TrackerTLD::create(), dataset, 40, .45f, NoTransform);
461 462
  test.run();
}
463 464 465 466 467 468 469

TEST_P(DistanceAndOverlap, MOSSE)
{
  TrackerTest test( TrackerMOSSE::create(), dataset, 22, .7f, NoTransform);
  test.run();
}

470 471 472 473 474 475
TEST_P(DistanceAndOverlap, CSRT)
{
  TrackerTest test( TrackerCSRT::create(), dataset, 22, .7f, NoTransform);
  test.run();
}

476 477 478 479
/***************************************************************************************/
//Tests with shifted initial window
TEST_P(DistanceAndOverlap, Shifted_Data_MedianFlow)
{
480
  TrackerTest test( TrackerMedianFlow::create(), dataset, 80, .2f, CenterShiftLeft, 1, 1);
481 482 483 484 485
  test.run();
}

TEST_P(DistanceAndOverlap, Shifted_Data_MIL)
{
486
  TrackerTest test( TrackerMIL::create(), dataset, 30, .6f, CenterShiftLeft);
487 488 489
  test.run();
}

490
TEST_P(DistanceAndOverlap, Shifted_Data_Boosting)
491
{
492
  TrackerTest test( TrackerBoosting::create(), dataset, 80, .65f, CenterShiftLeft);
493 494 495
  test.run();
}

496 497
TEST_P(DistanceAndOverlap, Shifted_Data_KCF)
{
498
  TrackerTest test( TrackerKCF::create(), dataset, 20, .4f, CenterShiftLeft, 5);
499 500 501
  test.run();
}

502
TEST_P(DistanceAndOverlap, Shifted_Data_TLD)
503
{
504
  TrackerTest test( TrackerTLD::create(), dataset, 30, .35f, CenterShiftLeft);
505 506
  test.run();
}
507 508 509 510 511 512

TEST_P(DistanceAndOverlap, Shifted_Data_MOSSE)
{
  TrackerTest test( TrackerMOSSE::create(), dataset, 13, .69f, CenterShiftLeft);
  test.run();
}
513 514 515 516 517 518

TEST_P(DistanceAndOverlap, Shifted_Data_CSRT)
{
  TrackerTest test( TrackerCSRT::create(), dataset, 13, .69f, CenterShiftLeft);
  test.run();
}
519 520 521
/***************************************************************************************/
//Tests with scaled initial window
TEST_P(DistanceAndOverlap, Scaled_Data_MedianFlow)
522
{
523
  TrackerTest test( TrackerMedianFlow::create(), dataset, 25, .5f, Scale_1_1, 1, 1);
524 525 526
  test.run();
}

527
TEST_P(DistanceAndOverlap, Scaled_Data_MIL)
528
{
529
  TrackerTest test( TrackerMIL::create(), dataset, 30, .7f, Scale_1_1);
530 531 532
  test.run();
}

533
TEST_P(DistanceAndOverlap, Scaled_Data_Boosting)
534
{
535
  TrackerTest test( TrackerBoosting::create(), dataset, 80, .7f, Scale_1_1);
536 537 538
  test.run();
}

539 540
TEST_P(DistanceAndOverlap, Scaled_Data_KCF)
{
541
  TrackerTest test( TrackerKCF::create(), dataset, 20, .4f, Scale_1_1, 5);
542 543 544
  test.run();
}

545
TEST_P(DistanceAndOverlap, Scaled_Data_TLD)
546
{
547
  TrackerTest test( TrackerTLD::create(), dataset, 30, .45f, Scale_1_1);
548 549 550
  test.run();
}

551

552 553
TEST_P(DistanceAndOverlap, DISABLED_GOTURN)
{
554
  TrackerTest test(TrackerGOTURN::create(), dataset, 18, .5f, NoTransform);
555 556 557
  test.run();
}

558 559 560 561 562 563
TEST_P(DistanceAndOverlap, Scaled_Data_MOSSE)
{
  TrackerTest test( TrackerMOSSE::create(), dataset, 22, 0.69f, Scale_1_1, 1);
  test.run();
}

564 565 566 567 568 569
TEST_P(DistanceAndOverlap, Scaled_Data_CSRT)
{
  TrackerTest test( TrackerCSRT::create(), dataset, 22, 0.69f, Scale_1_1, 1);
  test.run();
}

570

571
INSTANTIATE_TEST_CASE_P( Tracking, DistanceAndOverlap, TESTSET_NAMES);
572

573
}} // namespace
574
/* End of file. */