diff --git a/modules/video/include/opencv2/video/tracking.hpp b/modules/video/include/opencv2/video/tracking.hpp index 54e249b29..53b84636f 100644 --- a/modules/video/include/opencv2/video/tracking.hpp +++ b/modules/video/include/opencv2/video/tracking.hpp @@ -318,12 +318,13 @@ enum { OPTFLOW_USE_INITIAL_FLOW=4, OPTFLOW_FARNEBACK_GAUSSIAN=256 }; CV_EXPORTS_W void calcOpticalFlowPyrLK( InputArray prevImg, InputArray nextImg, InputArray prevPts, CV_OUT InputOutputArray nextPts, OutputArray status, OutputArray err, - Size winSize=Size(15,15), int maxLevel=3, + Size winSize=Size(21,21), int maxLevel=3, TermCriteria criteria=TermCriteria( TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), double derivLambda=0.5, - int flags=0 ); + int flags=0, + double minEigThreshold=1e-4); //! computes dense optical flow using Farneback algorithm CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next, diff --git a/modules/video/src/lkpyramid.cpp b/modules/video/src/lkpyramid.cpp index b12504f66..397eda5ff 100644 --- a/modules/video/src/lkpyramid.cpp +++ b/modules/video/src/lkpyramid.cpp @@ -134,7 +134,7 @@ struct LKTrackerInvoker const Point2f* _prevPts, Point2f* _nextPts, uchar* _status, float* _err, Size _winSize, TermCriteria _criteria, - int _level, int _maxLevel, int _flags ) + int _level, int _maxLevel, int _flags, float _minEigThreshold ) { prevImg = &_prevImg; prevDeriv = &_prevDeriv; @@ -148,6 +148,7 @@ struct LKTrackerInvoker level = _level; maxLevel = _maxLevel; flags = _flags; + minEigThreshold = _minEigThreshold; } void operator()(const BlockedRange& range) const @@ -308,11 +309,12 @@ struct LKTrackerInvoker float D = A11*A22 - A12*A12; float minEig = (A22 + A11 - std::sqrt((A11-A22)*(A11-A22) + - 4.f*A12*A12))/(2*winSize.width*winSize.height); - if( err ) + 4.f*A12*A12))/(2*winSize.width*winSize.height); + + if( err && (flags & CV_LKFLOW_GET_MIN_EIGENVALS) != 0 ) err[ptidx] = (float)minEig; - if( D < FLT_EPSILON ) + if( minEig < minEigThreshold || D < FLT_EPSILON ) { if( level == 0 && status ) status[ptidx] = false; @@ -431,6 +433,46 @@ struct LKTrackerInvoker } prevDelta = delta; } + + if( status[ptidx] && err && level == 0 && (flags & CV_LKFLOW_GET_MIN_EIGENVALS) == 0 ) + { + Point2f nextPt = nextPts[ptidx]; + Point inextPt; + + inextPt.x = cvFloor(nextPt.x); + inextPt.y = cvFloor(nextPt.y); + + if( inextPt.x < -winSize.width || inextPt.x >= J.cols || + inextPt.y < -winSize.height || inextPt.y >= J.rows ) + { + if( status ) + status[ptidx] = false; + continue; + } + + float a = nextPt.x - inextPt.x; + float b = nextPt.y - inextPt.y; + iw00 = cvRound((1.f - a)*(1.f - b)*(1 << W_BITS)); + iw01 = cvRound(a*(1.f - b)*(1 << W_BITS)); + iw10 = cvRound((1.f - a)*b*(1 << W_BITS)); + iw11 = (1 << W_BITS) - iw00 - iw01 - iw10; + float errval = 0.f; + + for( y = 0; y < winSize.height; y++ ) + { + const uchar* Jptr = (const uchar*)J.data + (y + inextPt.y)*step + inextPt.x*cn; + const deriv_type* Iptr = (const deriv_type*)(IWinBuf.data + y*IWinBuf.step); + + for( x = 0; x < winSize.width*cn; x++ ) + { + int diff = CV_DESCALE(Jptr[x]*iw00 + Jptr[x+cn]*iw01 + + Jptr[x+step]*iw10 + Jptr[x+step+cn]*iw11, + W_BITS1-5) - Iptr[x]; + errval += std::abs((float)diff); + } + } + err[ptidx] = errval * 1.f/(32*winSize.width*cn*winSize.height); + } } } @@ -446,6 +488,7 @@ struct LKTrackerInvoker int level; int maxLevel; int flags; + float minEigThreshold; }; } @@ -456,7 +499,7 @@ void cv::calcOpticalFlowPyrLK( InputArray _prevImg, InputArray _nextImg, Size winSize, int maxLevel, TermCriteria criteria, double derivLambda, - int flags ) + int flags, double minEigThreshold ) { #ifdef HAVE_TEGRA_OPTIMIZATION if (tegra::calcOpticalFlowPyrLK(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err, winSize, maxLevel, criteria, derivLambda, flags)) @@ -570,7 +613,8 @@ void cv::calcOpticalFlowPyrLK( InputArray _prevImg, InputArray _nextImg, parallel_for(BlockedRange(0, npoints), LKTrackerInvoker(prevPyr[level], derivI, nextPyr[level], prevPts, nextPts, status, err, - winSize, criteria, level, maxLevel, flags)); + winSize, criteria, level, maxLevel, + flags, (float)minEigThreshold)); } } diff --git a/samples/cpp/lkdemo.cpp b/samples/cpp/lkdemo.cpp index 94d20d308..0185e4723 100644 --- a/samples/cpp/lkdemo.cpp +++ b/samples/cpp/lkdemo.cpp @@ -39,7 +39,7 @@ int main( int argc, char** argv ) { VideoCapture cap; TermCriteria termcrit(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03); - Size winSize(10,10); + Size subPixWinSize(10,10), winSize(31,31); const int MAX_COUNT = 500; bool needToInit = false; @@ -81,7 +81,7 @@ int main( int argc, char** argv ) { // automatic initialization goodFeaturesToTrack(gray, points[1], MAX_COUNT, 0.01, 10, Mat(), 3, 0, 0.04); - cornerSubPix(gray, points[1], winSize, Size(-1,-1), termcrit); + cornerSubPix(gray, points[1], subPixWinSize, Size(-1,-1), termcrit); addRemovePt = false; } else if( !points[0].empty() ) @@ -91,7 +91,7 @@ int main( int argc, char** argv ) if(prevGray.empty()) gray.copyTo(prevGray); calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize, - 3, termcrit, 0); + 3, termcrit, 0, 0, 0.001); size_t i, k; for( i = k = 0; i < points[1].size(); i++ ) {