1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/video/tracking.hpp"
2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/imgproc/imgproc.hpp"
3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/videoio/videoio.hpp"
4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/highgui/highgui.hpp"
5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <iostream>
7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <ctype.h>
8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerusing namespace cv;
10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerusing namespace std;
11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void help()
13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    // print a welcome message, and the OpenCV version
15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cout << "\nThis is a demo of Lukas-Kanade optical flow lkdemo(),\n"
16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "Using OpenCV version " << CV_VERSION << endl;
17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cout << "\nIt uses camera by default, but you can provide a path to video as an argument.\n";
18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    cout << "\nHot keys: \n"
19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "\tESC - quit the program\n"
20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "\tr - auto-initialize tracking\n"
21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "\tc - delete all the points\n"
22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "\tn - switch the \"night\" mode on/off\n"
23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            "To add/remove a feature point click it\n" << endl;
24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
26793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerPoint2f point;
27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerbool addRemovePt = false;
28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void onMouse( int event, int x, int y, int /*flags*/, void* /*param*/ )
30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( event == EVENT_LBUTTONDOWN )
32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        point = Point2f((float)x, (float)y);
34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        addRemovePt = true;
35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerint main( int argc, char** argv )
39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    help();
41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    VideoCapture cap;
43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    TermCriteria termcrit(TermCriteria::COUNT|TermCriteria::EPS,20,0.03);
44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Size subPixWinSize(10,10), winSize(31,31);
45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    const int MAX_COUNT = 500;
47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool needToInit = false;
48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool nightMode = false;
49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cap.open(argc == 2 ? argv[1][0] - '0' : 0);
52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    else if( argc == 2 )
53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cap.open(argv[1]);
54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    if( !cap.isOpened() )
56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cout << "Could not initialize capturing...\n";
58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return 0;
59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    namedWindow( "LK Demo", 1 );
62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    setMouseCallback( "LK Demo", onMouse, 0 );
63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Mat gray, prevGray, image, frame;
65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    vector<Point2f> points[2];
66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    for(;;)
68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cap >> frame;
70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( frame.empty() )
71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        frame.copyTo(image);
74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cvtColor(image, gray, COLOR_BGR2GRAY);
75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( nightMode )
77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            image = Scalar::all(0);
78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( needToInit )
80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // automatic initialization
82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            goodFeaturesToTrack(gray, points[1], MAX_COUNT, 0.01, 10, Mat(), 3, 0, 0.04);
83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cornerSubPix(gray, points[1], subPixWinSize, Size(-1,-1), termcrit);
84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            addRemovePt = false;
85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        else if( !points[0].empty() )
87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            vector<uchar> status;
89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            vector<float> err;
90793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            if(prevGray.empty())
91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                gray.copyTo(prevGray);
92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize,
93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                                 3, termcrit, 0, 0.001);
94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            size_t i, k;
95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for( i = k = 0; i < points[1].size(); i++ )
96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( addRemovePt )
98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                {
99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    if( norm(point - points[1][i]) <= 5 )
100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    {
101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        addRemovePt = false;
102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                        continue;
103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    }
104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                }
105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if( !status[i] )
107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    continue;
108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                points[1][k++] = points[1][i];
110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                circle( image, points[1][i], 3, Scalar(0,255,0), -1, 8);
111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            points[1].resize(k);
113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( addRemovePt && points[1].size() < (size_t)MAX_COUNT )
116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            vector<Point2f> tmp;
118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            tmp.push_back(point);
119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            cornerSubPix( gray, tmp, winSize, Size(-1,-1), termcrit);
120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            points[1].push_back(tmp[0]);
121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            addRemovePt = false;
122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        needToInit = false;
125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        imshow("LK Demo", image);
126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        char c = (char)waitKey(10);
128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if( c == 27 )
129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        switch( c )
131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        case 'r':
133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            needToInit = true;
134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        case 'c':
136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            points[0].clear();
137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            points[1].clear();
138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        case 'n':
140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            nightMode = !nightMode;
141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            break;
142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        std::swap(points[1], points[0]);
145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cv::swap(prevGray, gray);
146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return 0;
149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
150