Skip to content

Add robust local optical flow (RLOF) implementations #1940

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Dec 30, 2018

Conversation

tsenst
Copy link
Contributor

@tsenst tsenst commented Dec 9, 2018

The RLOF method is an improved pyramidal iterative Lucas-Kanade approach. This implementations contains interfaces for sparse optical flow for feature tracking and dense optical flow based on sparse-to-dense interpolation schemes.

Add performance and accuracy tests have been implementation as well as documentation with the related publications

force_builders=Custom,Linux x64 Debug,Docs,linux,Mac,Win64,Win32
CPU_BASELINE:Custom=AVX2
docker_image:Custom=fedora:28
buildworker:Custom=linux-1,linux-2,linux-4
**WIP**

…oved pyramidal iterative Lucas-Kanade approach. This implementations contains interfaces for sparse optical flow for feature tracking and dense optical flow based on sparse-to-dense interpolation schemes.

Add performance and accuracy tests have been implementation as well as documentation with the related publications
Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution!

Below are comments from high level review.
Public interfaces look good.

More detailed review will be later (please make builds green).


License Agreement
For Open Source Computer Vision Library
(3-clause BSD License)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using of short form of license header:

// 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.

or avoid using of tabs

title = {Robust Local Optical Flow: Dense Motion Vector Field Interpolation},
booktitle = {Picture Coding Symposium},
year = {2016},
pages = {1--5},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix indentation (replace tabs)

namespace optflow
{
//! @addtogroup optflow
//! @{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid extra indentation in "namespaces" - it is not necessary.

@@ -0,0 +1,309 @@
/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this file? Looks like it is a copy of existed one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were right. The file has been removed:

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed massive but minor updates (spaces, includes, static, etc). Please take a look.


// Initialize point grid
int stepr = prevPyramids[0]->m_Image.rows / 30;
int stepc = prevPyramids[0]->m_Image.rows / 40;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_Image.cols

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks that was a bug

for( y = 0; y < winSize.height; y++ )
{
const uchar* src = (const uchar*)I.data + (y + iprevPt.y)*step + iprevPt.x*cn;
const short* dsrc = (const short*)derivI.data + (y + iprevPt.y)*dstep + iprevPt.x*cn2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid using "data" and "step" calculations. Use .ptr<mat_type>(row, col) instead. Remove using of "steps" in other places too.

const uchar* src = I.ptr<uchar>(y + iprevPt.y, iprevPt.x);
const short* dsrc = derivI.ptr<short>(y + iprevPt.y, iprevPt.x);

_mm_loadl_epi64((const __m128i*)(Jptr + x)), z);
__m128i v01 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(Jptr + x + cn)), z);
__m128i v10 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(Jptr + x + step)), z);
__m128i v11 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(Jptr + x + step + cn)), z);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jptr + step => Jptr1

where:

const uchar* Jptr = J.ptr<uchar>(y + inextPt.y, inextPt.x);
CV_DbgCheckLT(y + inextPt.y + 1, J.rows, "");  // or use std::min(J.rows - 1, y + inextPt.y + 1) below
const uchar* Jptr1 = J.ptr<uchar>(y + inextPt.y + 1, inextPt.x);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of step has been removed with the current pull

return ret;
/*
for (int y = 0; y < in.rows; y++) {
for (int x = 0; x < in.cols; x++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this commented code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This snippet will be removed

@alalek
Copy link
Member

alalek commented Dec 16, 2018

I'm sorry. I though that patch is almost complete.

Merge branch

Please don't do this again.

  • This is error prone. Conflicts has been resolves incorrectly in the most cases. This case is not an exception.
  • Performing merge commit is a time waste without proper strategy...
  • It is almost impossible to verify performed changes in merges. Provide clean commit-after-commit patch history. No merges!
  • Use git "fetch" and "rebase" instead. If you don't know that is this, then it is better to ignore external changes and just force push (git push --force ...) your local changes. I will re-apply my changes then patch will complete.

@alalek
Copy link
Member

alalek commented Dec 16, 2018

This is why we asking to use .ptr():

(gdb) bt
#0  0x00007ffff7b36d80 in cv::error(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*, char const*, int)@plt ()
    at /home/alalek/projects/opencv/build/opencv/lib/libopencv_optflow.so.4.0
#1  0x00007ffff7b71bcc in cv::Mat::ptr<unsigned char>(int, int) const (this=0x7fffffffacf0, i0=-5, i1=0)
    at /home/alalek/projects/opencv/dev/modules/core/include/opencv2/core/mat.inl.hpp:1033
#2  0x00007ffff7b68554 in cv::optflow::plk::radial::TrackerInvoker::operator()(cv::Range const&) const (this=0x7fffffffb210, range=...)
    at /home/alalek/projects/opencv/contrib/modules/optflow/src/rlof/plk_invoker.hpp:172
#3  0x00007ffff2948479 in parallel_for_impl(cv::Range const&, cv::ParallelLoopBody const&, double) (range=..., body=..., nstripes=-1)
    at /home/alalek/projects/opencv/dev/modules/core/src/parallel.cpp:602
#4  0x00007ffff2948263 in cv::parallel_for_(cv::Range const&, cv::ParallelLoopBody const&, double) (range=..., body=..., nstripes=-1)
    at /home/alalek/projects/opencv/dev/modules/core/src/parallel.cpp:518
#5  0x00007ffff7b6ec0a in cv::optflow::calcLocalOpticalFlowCore(cv::Ptr<cv::optflow::CImageBuffer>*, cv::Ptr<cv::optflow::CImageBuffer>*, cv::_InputArray const&, cv::_InputOutputArray const&, cv::optflow::RLOFOpticalFlowParameter const&) (prevPyramids=0x747120, currPyramids=0x747140, _prevPts=..., _nextPts=..., param=...)
    at /home/alalek/projects/opencv/contrib/modules/optflow/src/rlof/rlof_localflow.cpp:467
...
(gdb) f 2
#2  0x00007ffff7b68554 in cv::optflow::plk::radial::TrackerInvoker::operator() (this=0x7fffffffb210, range=...)
    at /home/alalek/projects/opencv/contrib/modules/optflow/src/rlof/plk_invoker.hpp:172
172	                const uchar* src = I.ptr<uchar>(y + iprevPt.y, 0) + iprevPt.x*cn;
(gdb) p iprevPt
$1 = {x = -5, y = -5}
(gdb) p y
$2 = 0
(gdb) p I.cols
$3 = 37
(gdb) p I.rows
$4 = 25

Code tries to access pixels out of the buffer:

  • Debug build
  • breakpoint on "cv::error"
  • disabled threading (to get stable code flow)
./bin/opencv_test_optflow --gtest_filter=SparseOpticalFlow.ReferenceAccuracy:DenseOpticalFlow_RLOF.ReferenceAccuracy \
    --test_threads=1

Perhaps "out of range" (lost) points should be filtered out.

@alalek
Copy link
Member

alalek commented Dec 16, 2018

Rebased commits without "merges" are here: https://github.com/alalek/opencv_contrib/commits/pr1940

@tsenst
Copy link
Contributor Author

tsenst commented Dec 17, 2018

I am sorry for the circumstances. To not cause any new conflicts who should I proceed to integrate the bugfixes?

@alalek
Copy link
Member

alalek commented Dec 17, 2018

It would be nice if you can grab changes from https://github.com/alalek/opencv_contrib/commits/pr1940
If not then just work on this patch as usual. I will all extra minor changes before merge then patch is ready.

int step = static_cast<int>(img.step1());
const cv::Point3_<uchar> * tval = img.ptr<cv::Point3_<uchar>>();
tval += c;
tval += r * step / 3;
Copy link
Member

@alalek alalek Dec 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more manual pointer arithmetic:

-int step = static_cast<int>(img.step1());
-const cv::Point3_<uchar> * tval = img.ptr<cv::Point3_<uchar>>();
-tval += c;
-tval += r * step / 3;
+CV_DbgAssert(img.type() == CV_8UC3);
+const cv::Point3_<uchar> * tval = img.ptr< cv::Point3_<uchar> >(r, c);

"if" check above should be updated too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this function because it is not used anymore. Instead computation is done by the HorizontalCrossSegmentation class

@alalek
Copy link
Member

alalek commented Dec 19, 2018

@tsenst Do you plan adding more commits into this PR?

@tsenst
Copy link
Contributor Author

tsenst commented Dec 19, 2018

I have done some tests on Optical Flow datasets to compare the accuracy of this implementation with the origin one. The results were satisfying. So from my side I am not planning any new commits.

prevImage, currImage and derivI as well as changing the offset of the
points in the invoker classes.

add some static_cast to avoid warning

remove 50 grid size sample from perf test. This grid size is to sparse
for the epic interpolation

remove notSameColor function since it is not used anymore
Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done! Thank you 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants