Merge pull request #14314 from mehlukas:3.4-opticalflow
authormehlukas <lukas.mehl@gmail.com>
Wed, 15 May 2019 12:13:57 +0000 (14:13 +0200)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Wed, 15 May 2019 12:13:57 +0000 (15:13 +0300)
Extend optical flow tutorial (#14314)

* extend python optical flow tutorial with cpp example code and add it to general tutorial directory

* remove unused parameters, fix comparison between signed and unsigned int

* fix hsv range problem

* switch to samples::findFile for sample file location

* switch to command line parameter for path

* remove old tutorial as in 14393

* minor fixes

doc/py_tutorials/py_video/py_lucas_kanade/py_lucas_kanade.markdown
doc/py_tutorials/py_video/py_table_of_contents_video.markdown
doc/tutorials/video/optical_flow/images/optical_flow_basic1.jpg [moved from doc/py_tutorials/py_video/py_lucas_kanade/images/optical_flow_basic1.jpg with 100% similarity]
doc/tutorials/video/optical_flow/images/opticalfb.jpg [moved from doc/py_tutorials/py_video/py_lucas_kanade/images/opticalfb.jpg with 100% similarity]
doc/tutorials/video/optical_flow/images/opticalflow_lk.jpg [moved from doc/py_tutorials/py_video/py_lucas_kanade/images/opticalflow_lk.jpg with 100% similarity]
doc/tutorials/video/optical_flow/optical_flow.markdown [new file with mode: 0644]
doc/tutorials/video/table_of_content_video.markdown
samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp [new file with mode: 0644]
samples/cpp/tutorial_code/video/optical_flow/optical_flow_dense.cpp [new file with mode: 0644]
samples/python/tutorial_code/video/optical_flow/optical_flow.py [new file with mode: 0644]
samples/python/tutorial_code/video/optical_flow/optical_flow_dense.py [new file with mode: 0644]

index 61abdd4..ccd6c4f 100644 (file)
@@ -1,225 +1,4 @@
 Optical Flow {#tutorial_py_lucas_kanade}
 ============
 
-Goal
-----
-
-In this chapter,
-    -   We will understand the concepts of optical flow and its estimation using Lucas-Kanade
-        method.
-    -   We will use functions like **cv.calcOpticalFlowPyrLK()** to track feature points in a
-        video.
-
-Optical Flow
-------------
-
-Optical flow is the pattern of apparent motion of image objects between two consecutive frames
-caused by the movemement of object or camera. It is 2D vector field where each vector is a
-displacement vector showing the movement of points from first frame to second. Consider the image
-below (Image Courtesy: [Wikipedia article on Optical
-Flow](http://en.wikipedia.org/wiki/Optical_flow)).
-
-![image](images/optical_flow_basic1.jpg)
-
-It shows a ball moving in 5 consecutive frames. The arrow shows its displacement vector. Optical
-flow has many applications in areas like :
-
--   Structure from Motion
--   Video Compression
--   Video Stabilization ...
-
-Optical flow works on several assumptions:
-
--#  The pixel intensities of an object do not change between consecutive frames.
-2.  Neighbouring pixels have similar motion.
-
-Consider a pixel \f$I(x,y,t)\f$ in first frame (Check a new dimension, time, is added here. Earlier we
-were working with images only, so no need of time). It moves by distance \f$(dx,dy)\f$ in next frame
-taken after \f$dt\f$ time. So since those pixels are the same and intensity does not change, we can say,
-
-\f[I(x,y,t) = I(x+dx, y+dy, t+dt)\f]
-
-Then take taylor series approximation of right-hand side, remove common terms and divide by \f$dt\f$ to
-get the following equation:
-
-\f[f_x u + f_y v + f_t = 0 \;\f]
-
-where:
-
-\f[f_x = \frac{\partial f}{\partial x} \; ; \; f_y = \frac{\partial f}{\partial y}\f]\f[u = \frac{dx}{dt} \; ; \; v = \frac{dy}{dt}\f]
-
-Above equation is called Optical Flow equation. In it, we can find \f$f_x\f$ and \f$f_y\f$, they are image
-gradients. Similarly \f$f_t\f$ is the gradient along time. But \f$(u,v)\f$ is unknown. We cannot solve this
-one equation with two unknown variables. So several methods are provided to solve this problem and
-one of them is Lucas-Kanade.
-
-### Lucas-Kanade method
-
-We have seen an assumption before, that all the neighbouring pixels will have similar motion.
-Lucas-Kanade method takes a 3x3 patch around the point. So all the 9 points have the same motion. We
-can find \f$(f_x, f_y, f_t)\f$ for these 9 points. So now our problem becomes solving 9 equations with
-two unknown variables which is over-determined. A better solution is obtained with least square fit
-method. Below is the final solution which is two equation-two unknown problem and solve to get the
-solution.
-
-\f[\begin{bmatrix} u \\ v \end{bmatrix} =
-\begin{bmatrix}
-    \sum_{i}{f_{x_i}}^2  &  \sum_{i}{f_{x_i} f_{y_i} } \\
-    \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2
-\end{bmatrix}^{-1}
-\begin{bmatrix}
-    - \sum_{i}{f_{x_i} f_{t_i}} \\
-    - \sum_{i}{f_{y_i} f_{t_i}}
-\end{bmatrix}\f]
-
-( Check similarity of inverse matrix with Harris corner detector. It denotes that corners are better
-points to be tracked.)
-
-So from the user point of view, the idea is simple, we give some points to track, we receive the optical
-flow vectors of those points. But again there are some problems. Until now, we were dealing with
-small motions, so it fails when there is a large motion. To deal with this we use pyramids. When we go up in
-the pyramid, small motions are removed and large motions become small motions. So by applying
-Lucas-Kanade there, we get optical flow along with the scale.
-
-Lucas-Kanade Optical Flow in OpenCV
------------------------------------
-
-OpenCV provides all these in a single function, **cv.calcOpticalFlowPyrLK()**. Here, we create a
-simple application which tracks some points in a video. To decide the points, we use
-**cv.goodFeaturesToTrack()**. We take the first frame, detect some Shi-Tomasi corner points in it,
-then we iteratively track those points using Lucas-Kanade optical flow. For the function
-**cv.calcOpticalFlowPyrLK()** we pass the previous frame, previous points and next frame. It
-returns next points along with some status numbers which has a value of 1 if next point is found,
-else zero. We iteratively pass these next points as previous points in next step. See the code
-below:
-@code{.py}
-import numpy as np
-import cv2 as cv
-
-cap = cv.VideoCapture('slow.flv')
-
-# params for ShiTomasi corner detection
-feature_params = dict( maxCorners = 100,
-                       qualityLevel = 0.3,
-                       minDistance = 7,
-                       blockSize = 7 )
-
-# Parameters for lucas kanade optical flow
-lk_params = dict( winSize  = (15,15),
-                  maxLevel = 2,
-                  criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
-
-# Create some random colors
-color = np.random.randint(0,255,(100,3))
-
-# Take first frame and find corners in it
-ret, old_frame = cap.read()
-old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY)
-p0 = cv.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
-
-# Create a mask image for drawing purposes
-mask = np.zeros_like(old_frame)
-
-while(1):
-    ret,frame = cap.read()
-    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
-
-    # calculate optical flow
-    p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
-
-    # Select good points
-    good_new = p1[st==1]
-    good_old = p0[st==1]
-
-    # draw the tracks
-    for i,(new,old) in enumerate(zip(good_new,good_old)):
-        a,b = new.ravel()
-        c,d = old.ravel()
-        mask = cv.line(mask, (a,b),(c,d), color[i].tolist(), 2)
-        frame = cv.circle(frame,(a,b),5,color[i].tolist(),-1)
-    img = cv.add(frame,mask)
-
-    cv.imshow('frame',img)
-    k = cv.waitKey(30) & 0xff
-    if k == 27:
-        break
-
-    # Now update the previous frame and previous points
-    old_gray = frame_gray.copy()
-    p0 = good_new.reshape(-1,1,2)
-
-cv.destroyAllWindows()
-cap.release()
-@endcode
-(This code doesn't check how correct are the next keypoints. So even if any feature point disappears
-in image, there is a chance that optical flow finds the next point which may look close to it. So
-actually for a robust tracking, corner points should be detected in particular intervals. OpenCV
-samples comes up with such a sample which finds the feature points at every 5 frames. It also run a
-backward-check of the optical flow points got to select only good ones. Check
-samples/python/lk_track.py).
-
-See the results we got:
-
-![image](images/opticalflow_lk.jpg)
-
-Dense Optical Flow in OpenCV
-----------------------------
-
-Lucas-Kanade method computes optical flow for a sparse feature set (in our example, corners detected
-using Shi-Tomasi algorithm). OpenCV provides another algorithm to find the dense optical flow. It
-computes the optical flow for all the points in the frame. It is based on Gunner Farneback's
-algorithm which is explained in "Two-Frame Motion Estimation Based on Polynomial Expansion" by
-Gunner Farneback in 2003.
-
-Below sample shows how to find the dense optical flow using above algorithm. We get a 2-channel
-array with optical flow vectors, \f$(u,v)\f$. We find their magnitude and direction. We color code the
-result for better visualization. Direction corresponds to Hue value of the image. Magnitude
-corresponds to Value plane. See the code below:
-@code{.py}
-import cv2 as cv
-import numpy as np
-cap = cv.VideoCapture("vtest.avi")
-
-ret, frame1 = cap.read()
-prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY)
-hsv = np.zeros_like(frame1)
-hsv[...,1] = 255
-
-while(1):
-    ret, frame2 = cap.read()
-    next = cv.cvtColor(frame2,cv.COLOR_BGR2GRAY)
-
-    flow = cv.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
-
-    mag, ang = cv.cartToPolar(flow[...,0], flow[...,1])
-    hsv[...,0] = ang*180/np.pi/2
-    hsv[...,2] = cv.normalize(mag,None,0,255,cv.NORM_MINMAX)
-    bgr = cv.cvtColor(hsv,cv.COLOR_HSV2BGR)
-
-    cv.imshow('frame2',bgr)
-    k = cv.waitKey(30) & 0xff
-    if k == 27:
-        break
-    elif k == ord('s'):
-        cv.imwrite('opticalfb.png',frame2)
-        cv.imwrite('opticalhsv.png',bgr)
-    prvs = next
-
-cap.release()
-cv.destroyAllWindows()
-@endcode
-See the result below:
-
-![image](images/opticalfb.jpg)
-
-OpenCV comes with a more advanced sample on dense optical flow, please see
-samples/python/opt_flow.py.
-
-Additional Resources
---------------------
-
-Exercises
----------
-
--#  Check the code in samples/python/lk_track.py. Try to understand the code.
-2.  Check the code in samples/python/opt_flow.py. Try to understand the code.
+Tutorial content has been moved: @ref tutorial_optical_flow
index a12b5ef..badb14e 100644 (file)
@@ -7,7 +7,7 @@ Video Analysis {#tutorial_py_table_of_contents_video}
     an example of color-based tracking. It is simpler. This time, we see significantly better
     algorithms like "Meanshift", and its upgraded version, "Camshift" to find and track them.
 
--   @subpage tutorial_py_lucas_kanade
+-   @ref tutorial_optical_flow
 
     Now let's discuss an important concept, "Optical Flow", which is related to videos and has many applications.
 
diff --git a/doc/tutorials/video/optical_flow/optical_flow.markdown b/doc/tutorials/video/optical_flow/optical_flow.markdown
new file mode 100644 (file)
index 0000000..b32bf5e
--- /dev/null
@@ -0,0 +1,156 @@
+Optical Flow {#tutorial_optical_flow}
+============
+
+Goal
+----
+
+In this chapter,
+    -   We will understand the concepts of optical flow and its estimation using Lucas-Kanade
+        method.
+    -   We will use functions like **cv.calcOpticalFlowPyrLK()** to track feature points in a
+        video.
+    -   We will create a dense optical flow field using the **cv.calcOpticalFlowFarneback()** method.
+
+Optical Flow
+------------
+
+Optical flow is the pattern of apparent motion of image objects between two consecutive frames
+caused by the movemement of object or camera. It is 2D vector field where each vector is a
+displacement vector showing the movement of points from first frame to second. Consider the image
+below (Image Courtesy: [Wikipedia article on Optical Flow](http://en.wikipedia.org/wiki/Optical_flow)).
+
+![image](images/optical_flow_basic1.jpg)
+
+It shows a ball moving in 5 consecutive frames. The arrow shows its displacement vector. Optical
+flow has many applications in areas like :
+
+-   Structure from Motion
+-   Video Compression
+-   Video Stabilization ...
+
+Optical flow works on several assumptions:
+
+-#  The pixel intensities of an object do not change between consecutive frames.
+2.  Neighbouring pixels have similar motion.
+
+Consider a pixel \f$I(x,y,t)\f$ in first frame (Check a new dimension, time, is added here. Earlier we
+were working with images only, so no need of time). It moves by distance \f$(dx,dy)\f$ in next frame
+taken after \f$dt\f$ time. So since those pixels are the same and intensity does not change, we can say,
+
+\f[I(x,y,t) = I(x+dx, y+dy, t+dt)\f]
+
+Then take taylor series approximation of right-hand side, remove common terms and divide by \f$dt\f$ to
+get the following equation:
+
+\f[f_x u + f_y v + f_t = 0 \;\f]
+
+where:
+
+\f[f_x = \frac{\partial f}{\partial x} \; ; \; f_y = \frac{\partial f}{\partial y}\f]\f[u = \frac{dx}{dt} \; ; \; v = \frac{dy}{dt}\f]
+
+Above equation is called Optical Flow equation. In it, we can find \f$f_x\f$ and \f$f_y\f$, they are image
+gradients. Similarly \f$f_t\f$ is the gradient along time. But \f$(u,v)\f$ is unknown. We cannot solve this
+one equation with two unknown variables. So several methods are provided to solve this problem and
+one of them is Lucas-Kanade.
+
+### Lucas-Kanade method
+
+We have seen an assumption before, that all the neighbouring pixels will have similar motion.
+Lucas-Kanade method takes a 3x3 patch around the point. So all the 9 points have the same motion. We
+can find \f$(f_x, f_y, f_t)\f$ for these 9 points. So now our problem becomes solving 9 equations with
+two unknown variables which is over-determined. A better solution is obtained with least square fit
+method. Below is the final solution which is two equation-two unknown problem and solve to get the
+solution.
+
+\f[\begin{bmatrix} u \\ v \end{bmatrix} =
+\begin{bmatrix}
+    \sum_{i}{f_{x_i}}^2  &  \sum_{i}{f_{x_i} f_{y_i} } \\
+    \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2
+\end{bmatrix}^{-1}
+\begin{bmatrix}
+    - \sum_{i}{f_{x_i} f_{t_i}} \\
+    - \sum_{i}{f_{y_i} f_{t_i}}
+\end{bmatrix}\f]
+
+( Check similarity of inverse matrix with Harris corner detector. It denotes that corners are better
+points to be tracked.)
+
+So from the user point of view, the idea is simple, we give some points to track, we receive the optical
+flow vectors of those points. But again there are some problems. Until now, we were dealing with
+small motions, so it fails when there is a large motion. To deal with this we use pyramids. When we go up in
+the pyramid, small motions are removed and large motions become small motions. So by applying
+Lucas-Kanade there, we get optical flow along with the scale.
+
+Lucas-Kanade Optical Flow in OpenCV
+-----------------------------------
+
+OpenCV provides all these in a single function, **cv.calcOpticalFlowPyrLK()**. Here, we create a
+simple application which tracks some points in a video. To decide the points, we use
+**cv.goodFeaturesToTrack()**. We take the first frame, detect some Shi-Tomasi corner points in it,
+then we iteratively track those points using Lucas-Kanade optical flow. For the function
+**cv.calcOpticalFlowPyrLK()** we pass the previous frame, previous points and next frame. It
+returns next points along with some status numbers which has a value of 1 if next point is found,
+else zero. We iteratively pass these next points as previous points in next step. See the code
+below:
+
+@add_toggle_cpp
+-   **Downloadable code**: Click
+    [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp)
+
+-   **Code at glance:**
+    @include samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp
+@end_toggle
+
+@add_toggle_python
+-   **Downloadable code**: Click
+    [here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/video/optical_flow/optical_flow.py)
+
+-   **Code at glance:**
+    @include samples/python/tutorial_code/video/optical_flow/optical_flow.py
+@end_toggle
+
+(This code doesn't check how correct are the next keypoints. So even if any feature point disappears
+in image, there is a chance that optical flow finds the next point which may look close to it. So
+actually for a robust tracking, corner points should be detected in particular intervals. OpenCV
+samples comes up with such a sample which finds the feature points at every 5 frames. It also run a
+backward-check of the optical flow points got to select only good ones. Check
+samples/python/lk_track.py).
+
+See the results we got:
+
+![image](images/opticalflow_lk.jpg)
+
+Dense Optical Flow in OpenCV
+----------------------------
+
+Lucas-Kanade method computes optical flow for a sparse feature set (in our example, corners detected
+using Shi-Tomasi algorithm). OpenCV provides another algorithm to find the dense optical flow. It
+computes the optical flow for all the points in the frame. It is based on Gunner Farneback's
+algorithm which is explained in "Two-Frame Motion Estimation Based on Polynomial Expansion" by
+Gunner Farneback in 2003.
+
+Below sample shows how to find the dense optical flow using above algorithm. We get a 2-channel
+array with optical flow vectors, \f$(u,v)\f$. We find their magnitude and direction. We color code the
+result for better visualization. Direction corresponds to Hue value of the image. Magnitude
+corresponds to Value plane. See the code below:
+
+@add_toggle_cpp
+-   **Downloadable code**: Click
+    [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/video/optical_flow/optical_flow_dense.cpp)
+
+-   **Code at glance:**
+    @include samples/cpp/tutorial_code/video/optical_flow/optical_flow_dense.cpp
+@end_toggle
+
+@add_toggle_python
+-   **Downloadable code**: Click
+    [here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/video/optical_flow/optical_flow_dense.py)
+
+-   **Code at glance:**
+    @include samples/python/tutorial_code/video/optical_flow/optical_flow_dense.py
+@end_toggle
+
+
+See the result below:
+
+![image](images/opticalfb.jpg)
index ca37eb0..92a5315 100644 (file)
@@ -20,3 +20,9 @@ tracking and foreground extractions.
     *Languages:* C++, Python
 
     Learn how to use the Meanshift and Camshift algorithms to track objects in videos.
+
+-   @subpage tutorial_optical_flow
+
+    *Languages:* C++, Python
+
+    We will learn how to use optical flow methods to track sparse features or to create a dense representation.
diff --git a/samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp b/samples/cpp/tutorial_code/video/optical_flow/optical_flow.cpp
new file mode 100644 (file)
index 0000000..9b03d33
--- /dev/null
@@ -0,0 +1,101 @@
+#include <iostream>
+#include <opencv2/core.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/videoio.hpp>
+#include <opencv2/video.hpp>
+
+using namespace cv;
+using namespace std;
+
+int main(int argc, char **argv)
+{
+    const string about =
+        "This sample demonstrates Lucas-Kanade Optical Flow calculation.\n"
+        "The example file can be downloaded from:\n"
+        "  https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4";
+    const string keys =
+        "{ h help |      | print this help message }"
+        "{ @image |<none>| path to image file }";
+    CommandLineParser parser(argc, argv, keys);
+    parser.about(about);
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    string filename = parser.get<string>("@image");
+    if (!parser.check())
+    {
+        parser.printErrors();
+        return 0;
+    }
+
+    VideoCapture capture(filename);
+    if (!capture.isOpened()){
+        //error in opening the video input
+        cerr << "Unable to open file!" << endl;
+        return 0;
+    }
+
+    // Create some random colors
+    vector<Scalar> colors;
+    RNG rng;
+    for(int i = 0; i < 100; i++)
+    {
+        int r = rng.uniform(0, 256);
+        int g = rng.uniform(0, 256);
+        int b = rng.uniform(0, 256);
+        colors.push_back(Scalar(r,g,b));
+    }
+
+    Mat old_frame, old_gray;
+    vector<Point2f> p0, p1;
+
+    // Take first frame and find corners in it
+    capture >> old_frame;
+    cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);
+    goodFeaturesToTrack(old_gray, p0, 100, 0.3, 7, Mat(), 7, false, 0.04);
+
+    // Create a mask image for drawing purposes
+    Mat mask = Mat::zeros(old_frame.size(), old_frame.type());
+
+    while(true){
+        Mat frame, frame_gray;
+
+        capture >> frame;
+        if (frame.empty())
+            break;
+        cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
+
+        // calculate optical flow
+        vector<uchar> status;
+        vector<float> err;
+        TermCriteria criteria = TermCriteria((TermCriteria::COUNT) + (TermCriteria::EPS), 10, 0.03);
+        calcOpticalFlowPyrLK(old_gray, frame_gray, p0, p1, status, err, Size(15,15), 2, criteria);
+
+        vector<Point2f> good_new;
+        for(uint i = 0; i < p0.size(); i++)
+        {
+            // Select good points
+            if(status[i] == 1) {
+                good_new.push_back(p1[i]);
+                // draw the tracks
+                line(mask,p1[i], p0[i], colors[i], 2);
+                circle(frame, p1[i], 5, colors[i], -1);
+            }
+        }
+        Mat img;
+        add(frame, mask, img);
+
+        imshow("Frame", img);
+
+        int keyboard = waitKey(30);
+        if (keyboard == 'q' || keyboard == 27)
+            break;
+
+        // Now update the previous frame and previous points
+        old_gray = frame_gray.clone();
+        p0 = good_new;
+    }
+}
diff --git a/samples/cpp/tutorial_code/video/optical_flow/optical_flow_dense.cpp b/samples/cpp/tutorial_code/video/optical_flow/optical_flow_dense.cpp
new file mode 100644 (file)
index 0000000..b4c12c3
--- /dev/null
@@ -0,0 +1,59 @@
+#include <iostream>
+#include <opencv2/core.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/videoio.hpp>
+#include <opencv2/video.hpp>
+
+using namespace cv;
+using namespace std;
+
+int main()
+{
+    VideoCapture capture(samples::findFile("vtest.avi"));
+    if (!capture.isOpened()){
+        //error in opening the video input
+        cerr << "Unable to open file!" << endl;
+        return 0;
+    }
+
+    Mat frame1, prvs;
+    capture >> frame1;
+    cvtColor(frame1, prvs, COLOR_BGR2GRAY);
+
+    while(true){
+        Mat frame2, next;
+        capture >> frame2;
+        if (frame2.empty())
+            break;
+        cvtColor(frame2, next, COLOR_BGR2GRAY);
+
+        Mat flow(prvs.size(), CV_32FC2);
+        calcOpticalFlowFarneback(prvs, next, flow, 0.5, 3, 15, 3, 5, 1.2, 0);
+
+        // visualization
+        Mat flow_parts[2];
+        split(flow, flow_parts);
+        Mat magnitude, angle, magn_norm;
+        cartToPolar(flow_parts[0], flow_parts[1], magnitude, angle, true);
+        normalize(magnitude, magn_norm, 0.0f, 1.0f, NORM_MINMAX);
+        angle *= ((1.f / 360.f) * (180.f / 255.f));
+
+        //build hsv image
+        Mat _hsv[3], hsv, hsv8, bgr;
+        _hsv[0] = angle;
+        _hsv[1] = Mat::ones(angle.size(), CV_32F);
+        _hsv[2] = magn_norm;
+        merge(_hsv, 3, hsv);
+        hsv.convertTo(hsv8, CV_8U, 255.0);
+        cvtColor(hsv8, bgr, COLOR_HSV2BGR);
+
+        imshow("frame2", bgr);
+
+        int keyboard = waitKey(30);
+        if (keyboard == 'q' || keyboard == 27)
+            break;
+
+        prvs = next;
+    }
+}
diff --git a/samples/python/tutorial_code/video/optical_flow/optical_flow.py b/samples/python/tutorial_code/video/optical_flow/optical_flow.py
new file mode 100644 (file)
index 0000000..c367407
--- /dev/null
@@ -0,0 +1,61 @@
+import numpy as np
+import cv2 as cv
+import argparse
+
+parser = argparse.ArgumentParser(description='This sample demonstrates Lucas-Kanade Optical Flow calculation. \
+                                              The example file can be downloaded from: \
+                                              https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4')
+parser.add_argument('image', type=str, help='path to image file')
+args = parser.parse_args()
+
+cap = cv.VideoCapture(args.image)
+
+# params for ShiTomasi corner detection
+feature_params = dict( maxCorners = 100,
+                       qualityLevel = 0.3,
+                       minDistance = 7,
+                       blockSize = 7 )
+
+# Parameters for lucas kanade optical flow
+lk_params = dict( winSize  = (15,15),
+                  maxLevel = 2,
+                  criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
+
+# Create some random colors
+color = np.random.randint(0,255,(100,3))
+
+# Take first frame and find corners in it
+ret, old_frame = cap.read()
+old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY)
+p0 = cv.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
+
+# Create a mask image for drawing purposes
+mask = np.zeros_like(old_frame)
+
+while(1):
+    ret,frame = cap.read()
+    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
+
+    # calculate optical flow
+    p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
+
+    # Select good points
+    good_new = p1[st==1]
+    good_old = p0[st==1]
+
+    # draw the tracks
+    for i,(new,old) in enumerate(zip(good_new, good_old)):
+        a,b = new.ravel()
+        c,d = old.ravel()
+        mask = cv.line(mask, (a,b),(c,d), color[i].tolist(), 2)
+        frame = cv.circle(frame,(a,b),5,color[i].tolist(),-1)
+    img = cv.add(frame,mask)
+
+    cv.imshow('frame',img)
+    k = cv.waitKey(30) & 0xff
+    if k == 27:
+        break
+
+    # Now update the previous frame and previous points
+    old_gray = frame_gray.copy()
+    p0 = good_new.reshape(-1,1,2)
diff --git a/samples/python/tutorial_code/video/optical_flow/optical_flow_dense.py b/samples/python/tutorial_code/video/optical_flow/optical_flow_dense.py
new file mode 100644 (file)
index 0000000..b937b24
--- /dev/null
@@ -0,0 +1,23 @@
+import numpy as np
+import cv2 as cv
+cap = cv.VideoCapture(cv.samples.findFile("vtest.avi"))
+ret, frame1 = cap.read()
+prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY)
+hsv = np.zeros_like(frame1)
+hsv[...,1] = 255
+while(1):
+    ret, frame2 = cap.read()
+    next = cv.cvtColor(frame2,cv.COLOR_BGR2GRAY)
+    flow = cv.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
+    mag, ang = cv.cartToPolar(flow[...,0], flow[...,1])
+    hsv[...,0] = ang*180/np.pi/2
+    hsv[...,2] = cv.normalize(mag,None,0,255,cv.NORM_MINMAX)
+    bgr = cv.cvtColor(hsv,cv.COLOR_HSV2BGR)
+    cv.imshow('frame2',bgr)
+    k = cv.waitKey(30) & 0xff
+    if k == 27:
+        break
+    elif k == ord('s'):
+        cv.imwrite('opticalfb.png',frame2)
+        cv.imwrite('opticalhsv.png',bgr)
+    prvs = next