123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- // This file is part of OpenCV project.
- // It is subject to the license terms in the LICENSE file found in the top-level directory
- // of this distribution and at http://opencv.org/license.html.
- /*
- * 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
- *
- */
- 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
- };
- namespace {
- std::vector<std::string> splitString(const std::string& s_, const std::string& delimiter)
- {
- std::string s = s_;
- 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;
- }
- float calcDistance(const Rect& a, const Rect& b)
- {
- 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));
- Point2f diff = p_a - p_b;
- return sqrt(diff.dot(diff));
- }
- float calcOverlap(const Rect& a, const Rect& b)
- {
- float rectIntersectionArea = (float)(a & b).area();
- return rectIntersectionArea / (a.area() + b.area() - rectIntersectionArea);
- }
- } // namespace
- template <typename Tracker, typename ROI_t = Rect2d>
- class TrackerTest
- {
- public:
- TrackerTest(const Ptr<Tracker>& tracker, const string& video, float distanceThreshold,
- float overlapThreshold, int shift = NoTransform, int segmentIdx = 1, int numSegments = 10);
- ~TrackerTest() {}
- void run();
- protected:
- void checkDataTest();
- void distanceAndOverlapTest();
- Ptr<Tracker> tracker;
- string video;
- std::vector<Rect> bbs;
- int startFrame;
- string suffix;
- string prefix;
- float overlapThreshold;
- float distanceThreshold;
- int segmentIdx;
- int shift;
- int numSegments;
- int gtStartFrame;
- int endFrame;
- vector<int> validSequence;
- private:
- Rect applyShift(const Rect& bb);
- };
- template <typename Tracker, typename ROI_t>
- TrackerTest<Tracker, ROI_t>::TrackerTest(const Ptr<Tracker>& _tracker, const string& _video, float _distanceThreshold,
- float _overlapThreshold, int _shift, int _segmentIdx, int _numSegments)
- : tracker(_tracker)
- , video(_video)
- , overlapThreshold(_overlapThreshold)
- , distanceThreshold(_distanceThreshold)
- , segmentIdx(_segmentIdx)
- , shift(_shift)
- , numSegments(_numSegments)
- {
- // nothing
- }
- template <typename Tracker, typename ROI_t>
- Rect TrackerTest<Tracker, ROI_t>::applyShift(const Rect& bb_)
- {
- Rect bb = bb_;
- Point center(bb.x + (bb.width / 2), bb.y + (bb.height / 2));
- int xLimit = bb.x + bb.width - 1;
- int yLimit = bb.y + bb.height - 1;
- int h = 0;
- int w = 0;
- float ratio = 1.0;
- 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);
- bb.width = xLimit - bb.x + 1;
- bb.height = yLimit - bb.y + 1;
- break;
- case CornerShiftTopRight:
- xLimit = (int)cvRound(xLimit + 0.1 * bb.width);
- bb.y = (int)cvRound(bb.y - 0.1 * bb.height);
- bb.width = xLimit - bb.x + 1;
- bb.height = yLimit - bb.y + 1;
- break;
- 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;
- break;
- case CornerShiftBottomRight:
- xLimit = (int)cvRound(xLimit + 0.1 * bb.width);
- yLimit = (int)cvRound(yLimit + 0.1 * bb.height);
- 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);
- 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);
- 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);
- 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;
- }
- return bb;
- }
- template <typename Tracker, typename ROI_t>
- void TrackerTest<Tracker, ROI_t>::distanceAndOverlapTest()
- {
- bool initialized = false;
- int fc = (startFrame - gtStartFrame);
- bbs.at(fc) = applyShift(bbs.at(fc));
- Rect currentBBi = bbs.at(fc);
- ROI_t currentBB(currentBBi);
- float sumDistance = 0;
- float sumOverlap = 0;
- string folder = cvtest::TS::ptr()->get_data_path() + "/" + TRACKING_DIR + "/" + video + "/" + FOLDER_IMG;
- string videoPath = folder + "/" + video + ".webm";
- VideoCapture c;
- c.open(videoPath);
- if (!c.isOpened())
- throw SkipTestException("Can't open video file");
- #if 0
- c.set(CAP_PROP_POS_FRAMES, startFrame);
- #else
- if (startFrame)
- std::cout << "startFrame = " << startFrame << std::endl;
- for (int i = 0; i < startFrame; i++)
- {
- Mat dummy_frame;
- c >> dummy_frame;
- ASSERT_FALSE(dummy_frame.empty()) << i << ": " << videoPath;
- }
- #endif
- for (int frameCounter = startFrame; frameCounter < endFrame; frameCounter++)
- {
- Mat frame;
- c >> frame;
- ASSERT_FALSE(frame.empty()) << "frameCounter=" << frameCounter << " video=" << videoPath;
- if (!initialized)
- {
- tracker->init(frame, currentBB);
- std::cout << "frame size = " << frame.size() << std::endl;
- initialized = true;
- }
- else if (initialized)
- {
- if (frameCounter >= (int)bbs.size())
- break;
- tracker->update(frame, currentBB);
- }
- float curDistance = calcDistance(currentBB, bbs.at(fc));
- float curOverlap = calcOverlap(currentBB, bbs.at(fc));
- #ifdef DEBUG_TEST
- Mat result;
- repeat(frame, 1, 2, result);
- rectangle(result, currentBB, Scalar(0, 255, 0), 1);
- Rect roi2(frame.cols, 0, frame.cols, frame.rows);
- rectangle(result(roi2), bbs.at(fc), Scalar(0, 0, 255), 1);
- imshow("result", result);
- waitKey(1);
- #endif
- sumDistance += curDistance;
- sumOverlap += curOverlap;
- fc++;
- }
- float meanDistance = sumDistance / (endFrame - startFrame);
- float meanOverlap = sumOverlap / (endFrame - startFrame);
- EXPECT_LE(meanDistance, distanceThreshold);
- EXPECT_GE(meanOverlap, overlapThreshold);
- }
- template <typename Tracker, typename ROI_t>
- void TrackerTest<Tracker, ROI_t>::checkDataTest()
- {
- 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";
- std::ifstream gt;
- //open the ground truth
- gt.open(gtFile.c_str());
- ASSERT_TRUE(gt.is_open()) << gtFile;
- 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";
- std::ifstream omit;
- 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
- int numFrame = (int)(validSequence.size() / numSegments);
- startFrame += (segmentIdx - 1) * numFrame;
- endFrame = startFrame + numFrame;
- std::ifstream gt2;
- //open the ground truth
- gt2.open(gtFile.c_str());
- ASSERT_TRUE(gt2.is_open()) << gtFile;
- string line2;
- 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()));
- ASSERT_EQ((size_t)4, tokens.size()) << "Incorrect ground truth file " << gtFile;
- bbs.push_back(bb);
- }
- gt2.close();
- if (segmentIdx == numSegments)
- endFrame = (int)bbs.size();
- }
- template <typename Tracker, typename ROI_t>
- void TrackerTest<Tracker, ROI_t>::run()
- {
- srand(1); // FIXIT remove that, ensure that there is no "rand()" in implementation
- ASSERT_TRUE(tracker);
- checkDataTest();
- //check for failure
- if (::testing::Test::HasFatalFailure())
- return;
- distanceAndOverlapTest();
- }
|