Commit 489f8df9 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #1333 from sovrasov:tld_improvement

parents 6651fb0b 0c5a8e1f
......@@ -408,7 +408,7 @@ namespace cv
////To fix: Check the paper, probably this cause wrong learning
//
labPatch.isObject = srValue > tld::THETA_NN;
labPatch.shouldBeIntegrated = abs(srValue - tld::THETA_NN) < 0.1;
labPatch.shouldBeIntegrated = abs(srValue - tld::THETA_NN) < tld::CLASSIFIER_MARGIN;
patches[k].push_back(labPatch);
//
......
......@@ -40,6 +40,7 @@
//M*/
#include "tldDetector.hpp"
#include "tracking_utils.hpp"
#include <opencv2/core/utility.hpp>
......@@ -64,27 +65,58 @@ namespace cv
return p;
}
double TLDDetector::computeSminus(const Mat_<uchar>& patch) const
{
double sminus = 0.0;
Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
for (int i = 0; i < *negNum; i++)
{
modelSample.data = &(negExp->data[i * 225]);
sminus = std::max(sminus, 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0));
}
return sminus;
}
// Calculate Relative similarity of the patch (NN-Model)
double TLDDetector::Sr(const Mat_<uchar>& patch) const
{
double splus = 0.0, sminus = 0.0;
Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
for (int i = 0; i < *posNum; i++)
{
modelSample.data = &(posExp->data[i * 225]);
splus = std::max(splus, 0.5 * (NCC(modelSample, patch) + 1.0));
}
for (int i = 0; i < *negNum; i++)
{
modelSample.data = &(negExp->data[i * 225]);
sminus = std::max(sminus, 0.5 * (NCC(modelSample, patch) + 1.0));
splus = std::max(splus, 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0));
}
sminus = computeSminus(patch);
if (splus + sminus == 0.0)
return 0.0;
return splus / (sminus + splus);
}
std::pair<double, double> TLDDetector::SrAndSc(const Mat_<uchar>& patch) const
{
double splusC = 0.0, sminus = 0.0, splus = 0.0;
Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
int med = tracking_internal::getMedian((*timeStampsPositive));
for (int i = 0; i < *posNum; i++)
{
modelSample.data = &(posExp->data[i * 225]);
double s = 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0);
if ((int)(*timeStampsPositive)[i] <= med)
splusC = std::max(splusC, s);
splus = std::max(splus, s);
}
sminus = computeSminus(patch);
double sr = (splus + sminus == 0.0) ? 0. : splus / (sminus + splus);
double sc = (splusC + sminus == 0.0) ? 0. : splusC / (sminus + splusC);
return std::pair<double, double>(sr, sc);
}
#ifdef HAVE_OPENCL
double TLDDetector::ocl_Sr(const Mat_<uchar>& patch)
{
......@@ -167,7 +199,7 @@ namespace cv
for (int id = 0; id < numOfPatches; id++)
{
double spr = 0.0, smr = 0.0, spc = 0.0, smc = 0;
int med = getMedian((*timeStampsPositive));
int med = tracking_internal::getMedian((*timeStampsPositive));
for (int i = 0; i < *posNum; i++)
{
spr = std::max(spr, 0.5 * (posNCC.at<float>(id * 500 + i) + 1.0));
......@@ -195,20 +227,16 @@ namespace cv
{
double splus = 0.0, sminus = 0.0;
Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
int med = getMedian((*timeStampsPositive));
int med = tracking_internal::getMedian((*timeStampsPositive));
for (int i = 0; i < *posNum; i++)
{
if ((int)(*timeStampsPositive)[i] <= med)
{
modelSample.data = &(posExp->data[i * 225]);
splus = std::max(splus, 0.5 * (NCC(modelSample, patch) + 1.0));
splus = std::max(splus, 0.5 * (tracking_internal::computeNCC(modelSample, patch) + 1.0));
}
}
for (int i = 0; i < *negNum; i++)
{
modelSample.data = &(negExp->data[i * 225]);
sminus = std::max(sminus, 0.5 * (NCC(modelSample, patch) + 1.0));
}
sminus = computeSminus(patch);
if (splus + sminus == 0.0)
return 0.0;
......@@ -249,7 +277,7 @@ namespace cv
Mat resNCC = devNCC.getMat(ACCESS_READ);
int med = getMedian((*timeStampsPositive));
int med = tracking_internal::getMedian((*timeStampsPositive));
for (int i = 0; i < *posNum; i++)
if ((int)(*timeStampsPositive)[i] <= med)
splus = std::max(splus, 0.5 * (resNCC.at<float>(i) +1.0));
......@@ -316,9 +344,9 @@ namespace cv
resample(detectorF->resized_imgs[detectorF->ensScaleIDs[ind]],
Rect2d(detectorF->ensBuffer[ind], initSizeF),
detectorF->standardPatches[ind]);
detectorF->scValues[ind] = detectorF->Sc (detectorF->standardPatches[ind]);
detectorF->srValues[ind] = detectorF->Sr (detectorF->standardPatches[ind]);
std::pair<double, double> values = detectorF->SrAndSc(detectorF->standardPatches[ind]);
detectorF->scValues[ind] = values.second;
detectorF->srValues[ind] = values.first;
}
}
......@@ -412,15 +440,17 @@ namespace cv
LabeledPatch labPatch;
double curScale = pow(SCALE_STEP, ensScaleIDs[i]);
labPatch.rect = Rect2d(ensBuffer[i].x*curScale, ensBuffer[i].y*curScale, initSize.width * curScale, initSize.height * curScale);
labPatch.Sc = scValues[i];
//printf("max sc %f\n", labPatch.Sc);
const double srValue = srValues[i];
const double scValue = scValues[i];
////To fix: Check the paper, probably this cause wrong learning
//
labPatch.isObject = srValue > THETA_NN;
labPatch.shouldBeIntegrated = abs(srValue - THETA_NN) < 0.1;
patches.push_back(labPatch);
labPatch.isObject = srValue > THETA_NN;
labPatch.shouldBeIntegrated = abs(srValue - THETA_NN) < CLASSIFIER_MARGIN;
patches.push_back(labPatch);
//
if (!labPatch.isObject)
......@@ -440,7 +470,7 @@ namespace cv
}
}
if (maxSc < 0)
if (maxSc < 0)
return false;
else
{
......@@ -538,7 +568,7 @@ namespace cv
////To fix: Check the paper, probably this cause wrong learning
//
labPatch.isObject = srValue > THETA_NN;
labPatch.shouldBeIntegrated = abs(srValue - THETA_NN) < 0.1;
labPatch.shouldBeIntegrated = abs(srValue - THETA_NN) < CLASSIFIER_MARGIN;
patches.push_back(labPatch);
//
......
......@@ -57,8 +57,9 @@ namespace cv
const int MEASURES_PER_CLASSIFIER = 13;
const int GRIDSIZE = 15;
const int DOWNSCALE_MODE = cv::INTER_LINEAR;
const double THETA_NN = 0.50;
const double THETA_NN = 0.5;
const double CORE_THRESHOLD = 0.5;
const double CLASSIFIER_MARGIN = 0.1;
const double SCALE_STEP = 1.2;
const double ENSEMBLE_THRESHOLD = 0.5;
const double VARIANCE_THRESHOLD = 0.5;
......@@ -77,6 +78,7 @@ namespace cv
void prepareClassifiers(int rowstep);
double Sr(const Mat_<uchar>& patch) const;
double Sc(const Mat_<uchar>& patch) const;
std::pair<double, double> SrAndSc(const Mat_<uchar>& patch) const;
#ifdef HAVE_OPENCL
double ocl_Sr(const Mat_<uchar>& patch);
double ocl_Sc(const Mat_<uchar>& patch);
......@@ -101,6 +103,7 @@ namespace cv
{
Rect2d rect;
bool isObject, shouldBeIntegrated;
double Sc;
};
bool detect(const Mat& img, const Mat& imgBlurred, Rect2d& res, std::vector<LabeledPatch>& patches, Size initSize);
bool ocl_detect(const Mat& img, const Mat& imgBlurred, Rect2d& res, std::vector<LabeledPatch>& patches, Size initSize);
......@@ -108,6 +111,9 @@ namespace cv
friend class MyMouseCallbackDEBUG;
static void computeIntegralImages(const Mat& img, Mat_<double>& intImgP, Mat_<double>& intImgP2){ integral(img, intImgP, intImgP2, CV_64F); }
static inline bool patchVariance(Mat_<double>& intImgP, Mat_<double>& intImgP2, double *originalVariance, Point pt, Size size);
protected:
double computeSminus(const Mat_<uchar>& patch) const;
};
......
......@@ -87,9 +87,9 @@ namespace cv
//Generate initial positive samples and put them to the model
positiveExamples.reserve(200);
for (int i = 0; i < (int)closest.size(); i++)
for (size_t i = 0; i < closest.size(); i++)
{
for (int j = 0; j < 20; j++)
for (size_t j = 0; j < 20; j++)
{
Point2f center;
Size2f size;
......@@ -102,13 +102,15 @@ namespace cv
resample(scaledImg, RotatedRect(center, size, angle), standardPatch);
for (int y = 0; y < standardPatch.rows; y++)
{
for (int x = 0; x < standardPatch.cols; x++)
{
standardPatch(x, y) += (uchar)rng.gaussian(5.0);
}
}
for( int y = 0; y < standardPatch.rows; y++ )
{
uchar* patchRow = standardPatch.ptr(y);
for( int x = 0; x < standardPatch.cols; x++ )
{
int newValue = patchRow[x] + cvRound(rng.gaussian(5.0));
patchRow[x] = saturate_cast<uchar>(newValue);
}
}
#ifdef BLUR_AS_VADIM
GaussianBlur(standardPatch, blurredPatch, GaussBlurKernelSize, 0.0);
......
......@@ -41,7 +41,6 @@
#include "tldTracker.hpp"
namespace cv
{
......@@ -141,38 +140,38 @@ bool TrackerTLDImpl::updateImpl(const Mat& image, Rect2d& boundingBox)
std::vector<Rect2d> candidates;
std::vector<double> candidatesRes;
bool trackerNeedsReInit = false;
bool DETECT_FLG = false;
for( int i = 0; i < 2; i++ )
bool DETECT_FLG = false;
//run tracker
Rect2d tmpCandid = boundingBox;
if(!data->failedLastTime && trackerProxy->update(image, tmpCandid))
{
Rect2d tmpCandid = boundingBox;
candidates.push_back(tmpCandid);
resample(image_gray, tmpCandid, standardPatch);
candidatesRes.push_back(tldModel->detector->Sc(standardPatch));
}
else
trackerNeedsReInit = true;
if (i == 1)
{
//run detector
tmpCandid = boundingBox;
#ifdef HAVE_OPENCL
if (ocl::haveOpenCL())
DETECT_FLG = tldModel->detector->ocl_detect(imageForDetector, image_blurred, tmpCandid, detectorResults, tldModel->getMinSize());
else
if (false)//ocl::useOpenCL())
DETECT_FLG = tldModel->detector->ocl_detect(imageForDetector, image_blurred, tmpCandid, detectorResults, tldModel->getMinSize());
else
#endif
DETECT_FLG = tldModel->detector->detect(imageForDetector, image_blurred, tmpCandid, detectorResults, tldModel->getMinSize());
}
if( ( (i == 0) && !data->failedLastTime && trackerProxy->update(image, tmpCandid) ) || ( DETECT_FLG))
{
candidates.push_back(tmpCandid);
if( i == 0 )
resample(image_gray, tmpCandid, standardPatch);
else
resample(imageForDetector, tmpCandid, standardPatch);
candidatesRes.push_back(tldModel->detector->Sc(standardPatch));
}
else
{
if( i == 0 )
trackerNeedsReInit = true;
}
DETECT_FLG = tldModel->detector->detect(imageForDetector, image_blurred, tmpCandid, detectorResults, tldModel->getMinSize());
if(DETECT_FLG)
{
candidates.push_back(tmpCandid);
resample(imageForDetector, tmpCandid, standardPatch);
candidatesRes.push_back(tldModel->detector->Sc(standardPatch));
}
std::vector<double>::iterator it = std::max_element(candidatesRes.begin(), candidatesRes.end());
if( it == candidatesRes.end() )
if( it == candidatesRes.end() ) //candidates are empty
{
data->confident = false;
data->failedLastTime = true;
......@@ -221,7 +220,7 @@ bool TrackerTLDImpl::updateImpl(const Mat& image, Rect2d& boundingBox)
tldModel->integrateRelabeled(imageForDetector, image_blurred, detectorResults);
pExpert.additionalExamples(examplesForModel, examplesForEnsemble);
#ifdef HAVE_OPENCL
if (ocl::haveOpenCL())
if (false)//ocl::useOpenCL())
tldModel->ocl_integrateAdditional(examplesForModel, examplesForEnsemble, true);
else
#endif
......@@ -230,7 +229,7 @@ bool TrackerTLDImpl::updateImpl(const Mat& image, Rect2d& boundingBox)
nExpert.additionalExamples(examplesForModel, examplesForEnsemble);
#ifdef HAVE_OPENCL
if (ocl::haveOpenCL())
if (false)//ocl::useOpenCL())
tldModel->ocl_integrateAdditional(examplesForModel, examplesForEnsemble, false);
else
#endif
......@@ -257,12 +256,13 @@ int TrackerTLDImpl::Pexpert::additionalExamples(std::vector<Mat_<uchar> >& examp
double scale = scaleAndBlur(img_, cvRound(log(1.0 * resultBox_.width / (initSize_.width)) / log(SCALE_STEP)),
scaledImg, blurredImg, GaussBlurKernelSize, SCALE_STEP);
TLDDetector::generateScanGrid(img_.rows, img_.cols, initSize_, scanGrid);
getClosestN(scanGrid, Rect2d(resultBox_.x / scale, resultBox_.y / scale, resultBox_.width / scale, resultBox_.height / scale), 10, closest);
for( int i = 0; i < (int)closest.size(); i++ )
for( size_t i = 0; i < closest.size(); i++ )
{
for( int j = 0; j < 10; j++ )
for( size_t j = 0; j < 10; j++ )
{
Point2f center;
Size2f size;
......@@ -273,21 +273,24 @@ int TrackerTLDImpl::Pexpert::additionalExamples(std::vector<Mat_<uchar> >& examp
size.height = (float)(closest[i].height * rng.uniform((double)0.99, (double)1.01));
float angle = (float)rng.uniform(-5.0, 5.0);
resample(scaledImg, RotatedRect(center, size, angle), standardPatch);
for( int y = 0; y < standardPatch.rows; y++ )
{
uchar* patchRow = standardPatch.ptr(y);
for( int x = 0; x < standardPatch.cols; x++ )
{
standardPatch(x, y) += (uchar)rng.gaussian(5.0);
int newValue = patchRow[x] + cvRound(rng.gaussian(5.0));
patchRow[x] = saturate_cast<uchar>(newValue);
}
}
#ifdef BLUR_AS_VADIM
examplesForModel.push_back(standardPatch);
#if defined BLUR_AS_VADIM
GaussianBlur(standardPatch, blurredPatch, GaussBlurKernelSize, 0.0);
resize(blurredPatch, blurredPatch, initSize_);
#else
resample(blurredImg, RotatedRect(center, size, angle), blurredPatch);
#endif
resample(scaledImg, RotatedRect(center, size, angle), standardPatch);
examplesForModel.push_back(standardPatch);
examplesForEnsemble.push_back(blurredPatch);
}
}
......
......@@ -112,7 +112,7 @@ private:
};
#define BLUR_AS_VADIM
#undef BLUR_AS_VADIM
#undef CLOSED_LOOP
class TrackerTLDImpl : public TrackerTLD
......
......@@ -151,52 +151,12 @@ void getClosestN(std::vector<Rect2d>& scanGrid, Rect2d bBox, int n, std::vector<
double variance(const Mat& img)
{
double p = 0, p2 = 0;
for( int i = 0; i < img.rows; i++ )
{
for( int j = 0; j < img.cols; j++ )
{
p += img.at<uchar>(i, j);
p2 += img.at<uchar>(i, j) * img.at<uchar>(i, j);
}
}
p = sum(img)(0);
p2 = norm(img, NORM_L2SQR);
p /= (img.cols * img.rows);
p2 /= (img.cols * img.rows);
return p2 - p * p;
}
//Normalized Correlation Coefficient
double NCC(const Mat_<uchar>& patch1, const Mat_<uchar>& patch2)
{
CV_Assert( patch1.rows == patch2.rows );
CV_Assert( patch1.cols == patch2.cols );
int N = patch1.rows * patch1.cols;
int s1 = 0, s2 = 0, n1 = 0, n2 = 0, prod = 0;
for( int i = 0; i < patch1.rows; i++ )
{
for( int j = 0; j < patch1.cols; j++ )
{
int p1 = patch1(i, j), p2 = patch2(i, j);
s1 += p1; s2 += p2;
n1 += (p1 * p1); n2 += (p2 * p2);
prod += (p1 * p2);
}
}
double sq1 = sqrt(std::max(0.0, n1 - 1.0 * s1 * s1 / N)), sq2 = sqrt(std::max(0.0, n2 - 1.0 * s2 * s2 / N));
double ares = (sq2 == 0) ? sq1 / abs(sq1) : (prod - s1 * s2 / N) / sq1 / sq2;
return ares;
}
int getMedian(const std::vector<int>& values, int size)
{
if( size == -1 )
size = (int)values.size();
std::vector<int> copy(values.begin(), values.begin() + size);
std::sort(copy.begin(), copy.end());
if( size % 2 == 0 )
return (copy[size / 2 - 1] + copy[size / 2]) / 2;
else
return copy[(size - 1) / 2];
return p2 - p * p;
}
//Overlap between two BB
......
......@@ -46,13 +46,8 @@ namespace cv
void resample(const Mat& img, const Rect2d& r2, Mat_<uchar>& samples);
/** Computes the variance of single given image.*/
double variance(const Mat& img);
/** Computes normalized corellation coefficient between the two patches (they should be
* of the same size).*/
double NCC(const Mat_<uchar>& patch1, const Mat_<uchar>& patch2);
void getClosestN(std::vector<Rect2d>& scanGrid, Rect2d bBox, int n, std::vector<Rect2d>& res);
double scaleAndBlur(const Mat& originalImg, int scale, Mat& scaledImg, Mat& blurredImg, Size GaussBlurKernelSize, double scaleStep);
int getMedian(const std::vector<int>& values, int size = -1);
}
}
......
......@@ -42,6 +42,7 @@
#include "precomp.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc.hpp"
#include "tracking_utils.hpp"
#include <algorithm>
#include <limits.h>
......@@ -94,12 +95,6 @@ private:
TrackerMedianFlow::Params params;
};
template<typename T>
T getMedian( const std::vector<T>& values );
template<typename T>
T getMedianAndDoPartition( std::vector<T>& values );
Mat getPatch(Mat image, Size patch_size, Point2f patch_center)
{
Mat patch;
......@@ -282,7 +277,7 @@ bool TrackerMedianFlowImpl::medianFlowImpl(Mat oldImage,Mat newImage,Rect2d& old
di[i]-=mDisplacement;
displacements.push_back((float)sqrt(di[i].ddot(di[i])));
}
float median_displacements = getMedianAndDoPartition(displacements);
float median_displacements = tracking_internal::getMedianAndDoPartition(displacements);
dprintf(("\tmedian of length of difference of displacements = %f\n", median_displacements));
if(median_displacements > params.maxMedianLengthOfDisplacementDifference){
dprintf(("\tmedian flow tracker returns false due to big median length of difference between displacements\n"));
......@@ -310,10 +305,10 @@ Rect2d TrackerMedianFlowImpl::vote(const std::vector<Point2f>& oldPoints,const s
float xshift=0,yshift=0;
std::vector<float> buf_for_location(n, 0.);
for(size_t i=0;i<n;i++){ buf_for_location[i]=newPoints[i].x-oldPoints[i].x; }
xshift=getMedianAndDoPartition(buf_for_location);
xshift=tracking_internal::getMedianAndDoPartition(buf_for_location);
newCenter.x+=xshift;
for(size_t i=0;i<n;i++){ buf_for_location[i]=newPoints[i].y-oldPoints[i].y; }
yshift=getMedianAndDoPartition(buf_for_location);
yshift=tracking_internal::getMedianAndDoPartition(buf_for_location);
newCenter.y+=yshift;
mD=Point2f((float)xshift,(float)yshift);
......@@ -327,7 +322,7 @@ Rect2d TrackerMedianFlowImpl::vote(const std::vector<Point2f>& oldPoints,const s
}
}
double scale=getMedianAndDoPartition(buf_for_scale);
double scale=tracking_internal::getMedianAndDoPartition(buf_for_scale);
dprintf(("xshift, yshift, scale = %f %f %f\n",xshift,yshift,scale));
newRect.x=newCenter.x-scale*oldRect.width/2.0;
newRect.y=newCenter.y-scale*oldRect.height/2.0;
......@@ -338,7 +333,6 @@ Rect2d TrackerMedianFlowImpl::vote(const std::vector<Point2f>& oldPoints,const s
return newRect;
}
#if 0
void TrackerMedianFlowImpl::computeStatistics(std::vector<float>& data,int size){
int binnum=10;
......@@ -355,7 +349,6 @@ void TrackerMedianFlowImpl::computeStatistics(std::vector<float>& data,int size)
}
}
#endif
void TrackerMedianFlowImpl::check_FB(const std::vector<Mat>& oldImagePyr, const std::vector<Mat>& newImagePyr,
const std::vector<Point2f>& oldPoints, const std::vector<Point2f>& newPoints, std::vector<bool>& status){
......@@ -373,7 +366,7 @@ void TrackerMedianFlowImpl::check_FB(const std::vector<Mat>& oldImagePyr, const
for(size_t i=0;i<oldPoints.size();i++){
FBerror[i]=(float)norm(oldPoints[i]-pointsToTrackReprojection[i]);
}
float FBerrorMedian=getMedian(FBerror);
float FBerrorMedian=tracking_internal::getMedian(FBerror);
dprintf(("point median=%f\n",FBerrorMedian));
dprintf(("FBerrorMedian=%f\n",FBerrorMedian));
for(size_t i=0;i<oldPoints.size();i++){
......@@ -390,51 +383,14 @@ void TrackerMedianFlowImpl::check_NCC(const Mat& oldImage,const Mat& newImage,
p1 = getPatch(oldImage, params.winSizeNCC, oldPoints[i]);
p2 = getPatch(newImage, params.winSizeNCC, newPoints[i]);
const int patch_area=params.winSizeNCC.area();
double s1=sum(p1)(0),s2=sum(p2)(0);
double n1=norm(p1),n2=norm(p2);
double prod=p1.dot(p2);
double sq1=sqrt(n1*n1-s1*s1/patch_area),sq2=sqrt(n2*n2-s2*s2/patch_area);
double ares=(sq2==0)?sq1/abs(sq1):(prod-s1*s2/patch_area)/sq1/sq2;
NCC[i] = (float)ares;
NCC[i] = (float)tracking_internal::computeNCC(p1, p2);
}
float median = getMedian(NCC);
float median = tracking_internal::getMedian(NCC);
for(size_t i = 0; i < oldPoints.size(); i++) {
status[i] = status[i] && (NCC[i] >= median);
}
}
template<typename T>
T getMedian(const std::vector<T>& values)
{
std::vector<T> copy(values);
return getMedianAndDoPartition(copy);
}
template<typename T>
T getMedianAndDoPartition(std::vector<T>& values)
{
size_t size = values.size();
if(size%2==0)
{
std::nth_element(values.begin(), values.begin() + size/2-1, values.end());
T firstMedian = values[size/2-1];
std::nth_element(values.begin(), values.begin() + size/2, values.end());
T secondMedian = values[size/2];
return (firstMedian + secondMedian) / (T)2;
}
else
{
size_t medianIndex = (size - 1) / 2;
std::nth_element(values.begin(), values.begin() + medianIndex, values.end());
return values[medianIndex];
}
}
} /* anonymous namespace */
namespace cv
......
// 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.
#include "tracking_utils.hpp"
using namespace cv;
double tracking_internal::computeNCC(const Mat& patch1, const Mat& patch2)
{
CV_Assert( patch1.rows == patch2.rows,
patch1.cols == patch2.cols);
int N = patch1.rows * patch1.cols;
if(N <= 1000 && patch1.type() == CV_8U && patch2.type() == CV_8U)
{
unsigned s1 = 0, s2 = 0;
unsigned n1 = 0, n2 = 0;
unsigned prod = 0;
if(patch1.isContinuous() && patch2.isContinuous())
{
const uchar* p1Ptr = patch1.ptr<uchar>(0);
const uchar* p2Ptr = patch2.ptr<uchar>(0);
for(int j = 0; j < N; j++)
{
s1 += p1Ptr[j];
s2 += p2Ptr[j];
n1 += p1Ptr[j]*p1Ptr[j];
n2 += p2Ptr[j]*p2Ptr[j];
prod += p1Ptr[j]*p2Ptr[j];
}
}
else
{
for(int i = 0; i < patch1.rows; i++)
{
const uchar* p1Ptr = patch1.ptr<uchar>(i);
const uchar* p2Ptr = patch2.ptr<uchar>(i);
for(int j = 0; j < patch1.cols; j++)
{
s1 += p1Ptr[j];
s2 += p2Ptr[j];
n1 += p1Ptr[j]*p1Ptr[j];
n2 += p2Ptr[j]*p2Ptr[j];
prod += p1Ptr[j]*p2Ptr[j];
}
}
}
double sq1 = sqrt(std::max(0.0, n1 - 1.0 * s1 * s1 / N));
double sq2 = sqrt(std::max(0.0, n2 - 1.0 * s2 * s2 / N));
return (sq2 == 0) ? sq1 / abs(sq1) : (prod - 1.0 * s1 * s2 / N) / sq1 / sq2;
}
else
{
double s1 = sum(patch1)(0);
double s2 = sum(patch2)(0);
double n1 = norm(patch1, NORM_L2SQR);
double n2 = norm(patch2, NORM_L2SQR);
double prod=patch1.dot(patch2);
double sq1 = sqrt(std::max(0.0, n1 - 1.0 * s1 * s1 / N));
double sq2 = sqrt(std::max(0.0, n2 - 1.0 * s2 * s2 / N));
return (sq2 == 0) ? sq1 / abs(sq1) : (prod - s1 * s2 / N) / sq1 / sq2;
}
}
// 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.
#ifndef __OPENCV_TRACKING_UTILS_HPP__
#include "precomp.hpp"
#include <algorithm>
namespace cv {
namespace tracking_internal
{
/** Computes normalized corellation coefficient between the two patches (they should be
* of the same size).*/
double computeNCC(const Mat& patch1, const Mat& patch2);
template<typename T>
T getMedianAndDoPartition(std::vector<T>& values)
{
size_t size = values.size();
if(size%2==0)
{
std::nth_element(values.begin(), values.begin() + size/2-1, values.end());
T firstMedian = values[size/2-1];
std::nth_element(values.begin(), values.begin() + size/2, values.end());
T secondMedian = values[size/2];
return (firstMedian + secondMedian) / (T)2;
}
else
{
size_t medianIndex = (size - 1) / 2;
std::nth_element(values.begin(), values.begin() + medianIndex, values.end());
return values[medianIndex];
}
}
template<typename T>
T getMedian(const std::vector<T>& values)
{
std::vector<T> copy(values);
return getMedianAndDoPartition(copy);
}
}
}
#endif
......@@ -459,9 +459,9 @@ TEST_P(DistanceAndOverlap, KCF)
test.run();
}
TEST_P(DistanceAndOverlap, DISABLED_TLD)
TEST_P(DistanceAndOverlap, TLD)
{
TrackerTest test( TrackerTLD::create(), dataset, 60, .4f, NoTransform);
TrackerTest test( TrackerTLD::create(), dataset, 40, .45f, NoTransform);
test.run();
}
......@@ -497,9 +497,9 @@ TEST_P(DistanceAndOverlap, Shifted_Data_KCF)
test.run();
}
TEST_P(DistanceAndOverlap, DISABLED_Shifted_Data_TLD)
TEST_P(DistanceAndOverlap, Shifted_Data_TLD)
{
TrackerTest test( TrackerTLD::create(), dataset, 120, .2f, CenterShiftLeft);
TrackerTest test( TrackerTLD::create(), dataset, 30, .35f, CenterShiftLeft);
test.run();
}
......@@ -534,9 +534,9 @@ TEST_P(DistanceAndOverlap, Scaled_Data_KCF)
test.run();
}
TEST_P(DistanceAndOverlap, DISABLED_Scaled_Data_TLD)
TEST_P(DistanceAndOverlap, Scaled_Data_TLD)
{
TrackerTest test( TrackerTLD::create(), dataset, 120, .45f, Scale_1_1);
TrackerTest test( TrackerTLD::create(), dataset, 30, .45f, Scale_1_1);
test.run();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment