1#include "opencv2/core/utility.hpp"
2#include "opencv2/core/ocl.hpp"
3#include "opencv2/video/tracking.hpp"
4#include "opencv2/imgproc/imgproc.hpp"
5#include "opencv2/videoio/videoio.hpp"
6#include "opencv2/highgui/highgui.hpp"
7
8#include <iostream>
9#include <cctype>
10
11static cv::UMat image;
12static bool backprojMode = false;
13static bool selectObject = false;
14static int trackObject = 0;
15static bool showHist = true;
16static cv::Rect selection;
17static int vmin = 10, vmax = 256, smin = 30;
18
19static void onMouse(int event, int x, int y, int, void*)
20{
21    static cv::Point origin;
22
23    if (selectObject)
24    {
25        selection.x = std::min(x, origin.x);
26        selection.y = std::min(y, origin.y);
27        selection.width = std::abs(x - origin.x);
28        selection.height = std::abs(y - origin.y);
29
30        selection &= cv::Rect(0, 0, image.cols, image.rows);
31    }
32
33    switch (event)
34    {
35    case cv::EVENT_LBUTTONDOWN:
36        origin = cv::Point(x, y);
37        selection = cv::Rect(x, y, 0, 0);
38        selectObject = true;
39        break;
40    case cv::EVENT_LBUTTONUP:
41        selectObject = false;
42        if (selection.width > 0 && selection.height > 0)
43            trackObject = -1;
44        break;
45    default:
46        break;
47    }
48}
49
50static void help()
51{
52    std::cout << "\nThis is a demo that shows mean-shift based tracking using Transparent API\n"
53            "You select a color objects such as your face and it tracks it.\n"
54            "This reads from video camera (0 by default, or the camera number the user enters\n"
55            "Usage: \n"
56            "   ./camshiftdemo [camera number]\n";
57
58    std::cout << "\n\nHot keys: \n"
59            "\tESC - quit the program\n"
60            "\ts - stop the tracking\n"
61            "\tb - switch to/from backprojection view\n"
62            "\th - show/hide object histogram\n"
63            "\tp - pause video\n"
64            "\tc - use OpenCL or not\n"
65            "To initialize tracking, select the object with mouse\n";
66}
67
68int main(int argc, const char ** argv)
69{
70    help();
71
72    cv::VideoCapture cap;
73    cv::Rect trackWindow;
74    int hsize = 16;
75    float hranges[2] = { 0, 180 };
76
77    const char * const keys = { "{@camera_number| 0 | camera number}" };
78    cv::CommandLineParser parser(argc, argv, keys);
79    int camNum = parser.get<int>(0);
80
81    cap.open(camNum);
82
83    if (!cap.isOpened())
84    {
85        help();
86
87        std::cout << "***Could not initialize capturing...***\n";
88        std::cout << "Current parameter's value: \n";
89        parser.printMessage();
90
91        return EXIT_FAILURE;
92    }
93
94    cv::namedWindow("Histogram", cv::WINDOW_NORMAL);
95    cv::namedWindow("CamShift Demo", cv::WINDOW_NORMAL);
96    cv::setMouseCallback("CamShift Demo", onMouse);
97    cv::createTrackbar("Vmin", "CamShift Demo", &vmin, 256);
98    cv::createTrackbar("Vmax", "CamShift Demo", &vmax, 256);
99    cv::createTrackbar("Smin", "CamShift Demo", &smin, 256);
100
101    cv::Mat frame, histimg(200, 320, CV_8UC3, cv::Scalar::all(0));
102    cv::UMat hsv, hist, hue, mask, backproj;
103    bool paused = false;
104
105    for ( ; ; )
106    {
107        if (!paused)
108        {
109            cap >> frame;
110            if (frame.empty())
111                break;
112        }
113
114        frame.copyTo(image);
115
116        if (!paused)
117        {
118            cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
119
120            if (trackObject)
121            {
122                int _vmin = vmin, _vmax = vmax;
123
124                cv::inRange(hsv, cv::Scalar(0, smin, std::min(_vmin, _vmax)),
125                        cv::Scalar(180, 256, std::max(_vmin, _vmax)), mask);
126
127                int fromTo[2] = { 0,0 };
128                hue.create(hsv.size(), hsv.depth());
129                cv::mixChannels(std::vector<cv::UMat>(1, hsv), std::vector<cv::UMat>(1, hue), fromTo, 1);
130
131                if (trackObject < 0)
132                {
133                    cv::UMat roi(hue, selection), maskroi(mask, selection);
134                    cv::calcHist(std::vector<cv::Mat>(1, roi.getMat(cv::ACCESS_READ)), std::vector<int>(1, 0),
135                                 maskroi, hist, std::vector<int>(1, hsize), std::vector<float>(hranges, hranges + 2));
136                    cv::normalize(hist, hist, 0, 255, cv::NORM_MINMAX);
137
138                    trackWindow = selection;
139                    trackObject = 1;
140
141                    histimg = cv::Scalar::all(0);
142                    int binW = histimg.cols / hsize;
143                    cv::Mat buf (1, hsize, CV_8UC3);
144                    for (int i = 0; i < hsize; i++)
145                        buf.at<cv::Vec3b>(i) = cv::Vec3b(cv::saturate_cast<uchar>(i*180./hsize), 255, 255);
146                    cv::cvtColor(buf, buf, cv::COLOR_HSV2BGR);
147
148                    {
149                        cv::Mat _hist = hist.getMat(cv::ACCESS_READ);
150                        for (int i = 0; i < hsize; i++)
151                        {
152                            int val = cv::saturate_cast<int>(_hist.at<float>(i)*histimg.rows/255);
153                            cv::rectangle(histimg, cv::Point(i*binW, histimg.rows),
154                                       cv::Point((i+1)*binW, histimg.rows - val),
155                                       cv::Scalar(buf.at<cv::Vec3b>(i)), -1, 8);
156                        }
157                    }
158                }
159
160                cv::calcBackProject(std::vector<cv::UMat>(1, hue), std::vector<int>(1, 0), hist, backproj,
161                                    std::vector<float>(hranges, hranges + 2), 1.0);
162                cv::bitwise_and(backproj, mask, backproj);
163
164                cv::RotatedRect trackBox = cv::CamShift(backproj, trackWindow,
165                                    cv::TermCriteria(cv::TermCriteria::EPS | cv::TermCriteria::COUNT, 10, 1));
166                if (trackWindow.area() <= 1)
167                {
168                    int cols = backproj.cols, rows = backproj.rows, r = (std::min(cols, rows) + 5)/6;
169                    trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r,
170                                       trackWindow.x + r, trackWindow.y + r) &
171                                  cv::Rect(0, 0, cols, rows);
172                }
173
174                if (backprojMode)
175                    cv::cvtColor(backproj, image, cv::COLOR_GRAY2BGR);
176
177                {
178                    cv::Mat _image = image.getMat(cv::ACCESS_RW);
179                    cv::ellipse(_image, trackBox, cv::Scalar(0, 0, 255), 3, cv::LINE_AA);
180                }
181            }
182        }
183        else if (trackObject < 0)
184            paused = false;
185
186        if (selectObject && selection.width > 0 && selection.height > 0)
187        {
188            cv::UMat roi(image, selection);
189            cv::bitwise_not(roi, roi);
190        }
191
192        cv::imshow("CamShift Demo", image);
193        if (showHist)
194            cv::imshow("Histogram", histimg);
195
196        char c = (char)cv::waitKey(10);
197        if (c == 27)
198            break;
199
200        switch(c)
201        {
202        case 'b':
203            backprojMode = !backprojMode;
204            break;
205        case 't':
206            trackObject = 0;
207            histimg = cv::Scalar::all(0);
208            break;
209        case 'h':
210            showHist = !showHist;
211            if (!showHist)
212                cv::destroyWindow("Histogram");
213            else
214                cv::namedWindow("Histogram", cv::WINDOW_AUTOSIZE);
215            break;
216        case 'p':
217            paused = !paused;
218            break;
219        case 'c':
220            cv::ocl::setUseOpenCL(!cv::ocl::useOpenCL());
221        default:
222            break;
223        }
224    }
225
226    return EXIT_SUCCESS;
227}
228