Skip to content

Commit 881440c

Browse files
authored
Merge pull request opencv#26143 from asmorkalov:as/HAL_opticalFlowLK
Added HAL interface for Lukas-Kanade optical flow opencv#26143 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [ ] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
1 parent ee68501 commit 881440c

File tree

5 files changed

+173
-53
lines changed

5 files changed

+173
-53
lines changed

3rdparty/carotene/hal/tegra_hal.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,4 +1932,34 @@ inline int TEGRA_GaussianBlurBinomial(const uchar* src_data, size_t src_step, uc
19321932

19331933
#endif // OPENCV_IMGPROC_HAL_INTERFACE_H
19341934

1935+
// The optimized branch was developed for old armv7 processors
1936+
#if defined(__ARM_ARCH) && (__ARM_ARCH == 7)
1937+
inline int TEGRA_LKOpticalFlowLevel(const uchar *prev_data, size_t prev_data_step,
1938+
const short* prev_deriv_data, size_t prev_deriv_step,
1939+
const uchar* next_data, size_t next_step,
1940+
int width, int height, int cn,
1941+
const float *prev_points, float *next_points, size_t point_count,
1942+
uchar *status, float *err,
1943+
const int win_width, const int win_height,
1944+
int termination_count, double termination_epsilon,
1945+
bool get_min_eigen_vals,
1946+
float min_eigen_vals_threshold)
1947+
{
1948+
if (!CAROTENE_NS::isSupportedConfiguration())
1949+
return CV_HAL_ERROR_NOT_IMPLEMENTED;
1950+
1951+
CAROTENE_NS::pyrLKOptFlowLevel(CAROTENE_NS::Size2D(width, height), cn,
1952+
prev_data, prev_data_step, prev_deriv_data, prev_deriv_step,
1953+
next_data, next_step,
1954+
point_count, prev_points, next_points,
1955+
status, err, CAROTENE_NS::Size2D(win_width, win_height),
1956+
termination_count, termination_epsilon,
1957+
get_min_eigen_vals, min_eigen_vals_threshold);
1958+
return CV_HAL_ERROR_OK;
1959+
}
1960+
1961+
#undef cv_hal_LKOpticalFlowLevel
1962+
#define cv_hal_LKOpticalFlowLevel TEGRA_LKOpticalFlowLevel
1963+
#endif // __ARM_ARCH=7
1964+
19351965
#endif

3rdparty/carotene/include/carotene/functions.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2485,7 +2485,7 @@ namespace CAROTENE_NS {
24852485
u8 *status, f32 *err,
24862486
const Size2D &winSize,
24872487
u32 terminationCount, f64 terminationEpsilon,
2488-
u32 level, u32 maxLevel, bool useInitialFlow, bool getMinEigenVals,
2488+
bool getMinEigenVals,
24892489
f32 minEigThreshold);
24902490
}
24912491

3rdparty/carotene/src/opticalflow.cpp

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ void pyrLKOptFlowLevel(const Size2D &size, s32 cn,
5858
u8 *status, f32 *err,
5959
const Size2D &winSize,
6060
u32 terminationCount, f64 terminationEpsilon,
61-
u32 level, u32 maxLevel, bool useInitialFlow, bool getMinEigenVals,
61+
bool getMinEigenVals,
6262
f32 minEigThreshold)
6363
{
6464
internal::assertSupportedConfiguration();
@@ -74,32 +74,11 @@ void pyrLKOptFlowLevel(const Size2D &size, s32 cn,
7474

7575
for( u32 ptidx = 0; ptidx < ptCount; ptidx++ )
7676
{
77-
f32 levscale = (1./(1 << level));
7877
u32 ptref = ptidx << 1;
79-
f32 prevPtX = prevPts[ptref+0]*levscale;
80-
f32 prevPtY = prevPts[ptref+1]*levscale;
81-
f32 nextPtX;
82-
f32 nextPtY;
83-
if( level == maxLevel )
84-
{
85-
if( useInitialFlow )
86-
{
87-
nextPtX = nextPts[ptref+0]*levscale;
88-
nextPtY = nextPts[ptref+1]*levscale;
89-
}
90-
else
91-
{
92-
nextPtX = prevPtX;
93-
nextPtY = prevPtY;
94-
}
95-
}
96-
else
97-
{
98-
nextPtX = nextPts[ptref+0]*2.f;
99-
nextPtY = nextPts[ptref+1]*2.f;
100-
}
101-
nextPts[ptref+0] = nextPtX;
102-
nextPts[ptref+1] = nextPtY;
78+
f32 prevPtX = prevPts[ptref+0];
79+
f32 prevPtY = prevPts[ptref+1];
80+
f32 nextPtX = nextPts[ptref+0];
81+
f32 nextPtY = nextPts[ptref+1];
10382

10483
s32 iprevPtX, iprevPtY;
10584
s32 inextPtX, inextPtY;
@@ -111,13 +90,10 @@ void pyrLKOptFlowLevel(const Size2D &size, s32 cn,
11190
if( iprevPtX < -(s32)winSize.width || iprevPtX >= (s32)size.width ||
11291
iprevPtY < -(s32)winSize.height || iprevPtY >= (s32)size.height )
11392
{
114-
if( level == 0 )
115-
{
116-
if( status )
117-
status[ptidx] = false;
118-
if( err )
119-
err[ptidx] = 0;
120-
}
93+
if( status )
94+
status[ptidx] = false;
95+
if( err )
96+
err[ptidx] = 0;
12197
continue;
12298
}
12399

@@ -333,7 +309,7 @@ void pyrLKOptFlowLevel(const Size2D &size, s32 cn,
333309

334310
if( minEig < minEigThreshold || D < FLT_EPSILON )
335311
{
336-
if( level == 0 && status )
312+
if( status )
337313
status[ptidx] = false;
338314
continue;
339315
}
@@ -353,7 +329,7 @@ void pyrLKOptFlowLevel(const Size2D &size, s32 cn,
353329
if( inextPtX < -(s32)winSize.width || inextPtX >= (s32)size.width ||
354330
inextPtY < -(s32)winSize.height || inextPtY >= (s32)size.height )
355331
{
356-
if( level == 0 && status )
332+
if( status )
357333
status[ptidx] = false;
358334
break;
359335
}
@@ -469,8 +445,7 @@ void pyrLKOptFlowLevel(const Size2D &size, s32 cn,
469445
prevDeltaX = deltaX;
470446
prevDeltaY = deltaY;
471447
}
472-
473-
if( status && status[ptidx] && err && level == 0 && !getMinEigenVals )
448+
if( status && status[ptidx] && err && !getMinEigenVals )
474449
{
475450
f32 nextPointX = nextPts[ptref+0] - halfWinX;
476451
f32 nextPointY = nextPts[ptref+1] - halfWinY;
@@ -526,14 +501,10 @@ void pyrLKOptFlowLevel(const Size2D &size, s32 cn,
526501
(void)winSize;
527502
(void)terminationCount;
528503
(void)terminationEpsilon;
529-
(void)level;
530-
(void)maxLevel;
531-
(void)useInitialFlow;
532504
(void)getMinEigenVals;
533505
(void)minEigThreshold;
534506
(void)ptCount;
535507
#endif
536508
}
537509

538510
}//CAROTENE_NS
539-

modules/video/src/hal_replacement.hpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
5+
#ifndef OPENCV_VIDEO_HAL_REPLACEMENT_HPP
6+
#define OPENCV_VIDEO_HAL_REPLACEMENT_HPP
7+
8+
#include "opencv2/core/hal/interface.h"
9+
10+
#if defined(__clang__) // clang or MSVC clang
11+
#pragma clang diagnostic push
12+
#pragma clang diagnostic ignored "-Wunused-parameter"
13+
#elif defined(_MSC_VER)
14+
#pragma warning(push)
15+
#pragma warning(disable : 4100)
16+
#elif defined(__GNUC__)
17+
#pragma GCC diagnostic push
18+
#pragma GCC diagnostic ignored "-Wunused-parameter"
19+
#endif
20+
21+
//! @addtogroup video_hal_interface
22+
//! @note Define your functions to override default implementations:
23+
//! @code
24+
//! #undef cv_hal_LK_optical_flow_level
25+
//! #define cv_hal_LK_optical_flow_level my_hal_LK_optical_flow_level
26+
//! @endcode
27+
//! @{
28+
29+
/**
30+
@brief Lucas-Kanade optical flow for single pyramid layer. See calcOpticalFlowPyrLK
31+
@param prev_data previous frame image data
32+
@param prev_data_step previous frame image data step
33+
@param prev_deriv_data previous frame Schaar derivatives
34+
@param prev_deriv_step previous frame Schaar derivatives step
35+
@param next_data next frame image data
36+
@param next_step next frame image step
37+
@param width input images width
38+
@param height input images height
39+
@param cn source image channels
40+
@param prev_points 2d points coordinates (x,y) on the previous frame
41+
@param next_points points coordinates (x,y) on the next frame
42+
@param point_count - amount of input points
43+
@param status optical flow status for each point. Optional output, expected if not nullptr is provided
44+
@param err optical flow estimation error for each point. Optional output, expected if not nullptr is provided
45+
@param win_width optical flow window width
46+
@param win_height optical flow window heigh
47+
@param termination_count maximum algorithm iterations. 0 means unlimited
48+
@param termination_epsilon maximal allowed algorithm error
49+
@param get_min_eigen_vals return minimal egen values as point errors in err buffer
50+
@param min_eigen_vals_threshold eigen values threshold
51+
**/
52+
inline int hal_ni_LKOpticalFlowLevel(const uchar *prev_data, size_t prev_data_step,
53+
const short* prev_deriv_data, size_t prev_deriv_step,
54+
const uchar* next_data, size_t next_step,
55+
int width, int height, int cn,
56+
const float *prev_points, float *next_points, size_t point_count,
57+
uchar *status, float *err,
58+
const int win_width, const int win_height,
59+
int termination_count, double termination_epsilon,
60+
bool get_min_eigen_vals,
61+
float min_eigen_vals_threshold)
62+
{
63+
return CV_HAL_ERROR_NOT_IMPLEMENTED;
64+
}
65+
66+
//! @cond IGNORED
67+
#define cv_hal_LKOpticalFlowLevel hal_ni_LKOpticalFlowLevel
68+
//! @endcond
69+
70+
//! @}
71+
72+
#if defined(__clang__)
73+
#pragma clang diagnostic pop
74+
#elif defined(_MSC_VER)
75+
#pragma warning(pop)
76+
#elif defined(__GNUC__)
77+
#pragma GCC diagnostic pop
78+
#endif
79+
80+
#include "custom_hal.hpp"
81+
82+
//! @cond IGNORED
83+
#define CALL_HAL_RET(name, fun, retval, ...) \
84+
int res = __CV_EXPAND(fun(__VA_ARGS__, &retval)); \
85+
if (res == CV_HAL_ERROR_OK) \
86+
return retval; \
87+
else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
88+
CV_Error_(cv::Error::StsInternal, \
89+
("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res));
90+
91+
92+
#define CALL_HAL(name, fun, ...) \
93+
int res = __CV_EXPAND(fun(__VA_ARGS__)); \
94+
if (res == CV_HAL_ERROR_OK) \
95+
return; \
96+
else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
97+
CV_Error_(cv::Error::StsInternal, \
98+
("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res));
99+
//! @endcond
100+
101+
#endif

modules/video/src/lkpyramid.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#endif
5151

5252
#include "opencv2/core/openvx/ovx_defs.hpp"
53+
#include "hal_replacement.hpp"
5354

5455
#define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
5556

@@ -184,11 +185,17 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
184185
{
185186
CV_INSTRUMENT_REGION();
186187

188+
const int W_BITS = 14, W_BITS1 = 14;
189+
const float FLT_SCALE = 1.f/(1 << 20);
190+
187191
Point2f halfWin((winSize.width-1)*0.5f, (winSize.height-1)*0.5f);
188192
const Mat& I = *prevImg;
189193
const Mat& J = *nextImg;
190194
const Mat& derivI = *prevDeriv;
191195

196+
cv::AutoBuffer<Point2f> prevPtsScaledData(range.end - range.start);
197+
Point2f* prevPtsScaled = prevPtsScaledData.data();
198+
192199
int j, cn = I.channels(), cn2 = cn*2;
193200
cv::AutoBuffer<deriv_type> _buf(winSize.area()*(cn + cn2));
194201
int derivDepth = DataType<deriv_type>::depth;
@@ -210,7 +217,23 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
210217
else
211218
nextPt = nextPts[ptidx]*2.f;
212219
nextPts[ptidx] = nextPt;
220+
prevPtsScaled[ptidx-range.start] = prevPt;
221+
}
213222

223+
CALL_HAL(LKOpticalFlowLevel, cv_hal_LKOpticalFlowLevel,
224+
I.data, I.step, (const short*)derivI.data, derivI.step, J.data, J.step,
225+
I.cols, I.rows, I.channels(),
226+
(float*)prevPtsScaled, (float*)(nextPts+range.start), range.end-range.start,
227+
(level == 0) ? status+range.start: nullptr,
228+
err != nullptr ? err+range.start: nullptr,
229+
winSize.width, winSize.height, criteria.maxCount, criteria.epsilon,
230+
(flags & OPTFLOW_LK_GET_MIN_EIGENVALS) != 0,
231+
(float)minEigThreshold
232+
);
233+
234+
for( int ptidx = range.start; ptidx < range.end; ptidx++ )
235+
{
236+
Point2f prevPt = prevPtsScaled[ptidx-range.start];
214237
Point2i iprevPt, inextPt;
215238
prevPt -= halfWin;
216239
iprevPt.x = cvFloor(prevPt.x);
@@ -221,8 +244,7 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
221244
{
222245
if( level == 0 )
223246
{
224-
if( status )
225-
status[ptidx] = false;
247+
status[ptidx] = false;
226248
if( err )
227249
err[ptidx] = 0;
228250
}
@@ -231,8 +253,6 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
231253

232254
float a = prevPt.x - iprevPt.x;
233255
float b = prevPt.y - iprevPt.y;
234-
const int W_BITS = 14, W_BITS1 = 14;
235-
const float FLT_SCALE = 1.f/(1 << 20);
236256
int iw00 = cvRound((1.f - a)*(1.f - b)*(1 << W_BITS));
237257
int iw01 = cvRound(a*(1.f - b)*(1 << W_BITS));
238258
int iw10 = cvRound((1.f - a)*b*(1 << W_BITS));
@@ -479,14 +499,14 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
479499

480500
if( minEig < minEigThreshold || D < FLT_EPSILON )
481501
{
482-
if( level == 0 && status )
502+
if(level == 0)
483503
status[ptidx] = false;
484504
continue;
485505
}
486506

487507
D = 1.f/D;
488508

489-
nextPt -= halfWin;
509+
Point2f nextPt = nextPts[ptidx] - halfWin;
490510
Point2f prevDelta;
491511

492512
for( j = 0; j < criteria.maxCount; j++ )
@@ -497,7 +517,7 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
497517
if( inextPt.x < -winSize.width || inextPt.x >= J.cols ||
498518
inextPt.y < -winSize.height || inextPt.y >= J.rows )
499519
{
500-
if( level == 0 && status )
520+
if( level == 0 )
501521
status[ptidx] = false;
502522
break;
503523
}
@@ -680,7 +700,6 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
680700
prevDelta = delta;
681701
}
682702

683-
CV_Assert(status != NULL);
684703
if( status[ptidx] && err && level == 0 && (flags & OPTFLOW_LK_GET_MIN_EIGENVALS) == 0 )
685704
{
686705
Point2f nextPoint = nextPts[ptidx] - halfWin;
@@ -692,8 +711,7 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
692711
if( inextPoint.x < -winSize.width || inextPoint.x >= J.cols ||
693712
inextPoint.y < -winSize.height || inextPoint.y >= J.rows )
694713
{
695-
if( status )
696-
status[ptidx] = false;
714+
status[ptidx] = false;
697715
continue;
698716
}
699717

@@ -1280,7 +1298,7 @@ void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg,
12801298
Mat statusMat = _status.getMat(), errMat;
12811299
CV_Assert( statusMat.isContinuous() );
12821300
uchar* status = statusMat.ptr();
1283-
float* err = 0;
1301+
float* err = nullptr;
12841302

12851303
for( i = 0; i < npoints; i++ )
12861304
status[i] = true;

0 commit comments

Comments
 (0)