camshiftdemo.cpp 6.27 KB
Newer Older
1
#include <opencv2/core/utility.hpp>
2
#include "opencv2/video/tracking.hpp"
3
#include "opencv2/imgproc.hpp"
4
#include "opencv2/videoio.hpp"
5
#include "opencv2/highgui.hpp"
6

7
#include <iostream>
8 9
#include <ctype.h>

10 11 12 13 14 15 16 17 18 19 20
using namespace cv;
using namespace std;

Mat image;

bool backprojMode = false;
bool selectObject = false;
int trackObject = 0;
bool showHist = true;
Point origin;
Rect selection;
21 22
int vmin = 10, vmax = 256, smin = 30;

23
static void onMouse( int event, int x, int y, int, void* )
24
{
25
    if( selectObject )
26
    {
27 28
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
29 30 31 32
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);

        selection &= Rect(0, 0, image.cols, image.rows);
33 34 35 36
    }

    switch( event )
    {
37
    case EVENT_LBUTTONDOWN:
38 39 40
        origin = Point(x,y);
        selection = Rect(x,y,0,0);
        selectObject = true;
41
        break;
42
    case EVENT_LBUTTONUP:
43
        selectObject = false;
44
        if( selection.width > 0 && selection.height > 0 )
45
            trackObject = -1;
46 47 48 49
        break;
    }
}

ValeryTyumen's avatar
ValeryTyumen committed
50 51 52 53 54 55 56 57 58
string hot_keys =
    "\n\nHot keys: \n"
    "\tESC - quit the program\n"
    "\tc - stop the tracking\n"
    "\tb - switch to/from backprojection view\n"
    "\th - show/hide object histogram\n"
    "\tp - pause video\n"
    "To initialize tracking, select the object with mouse\n";

59
static void help()
60
{
61
    cout << "\nThis is a demo that shows mean-shift based tracking\n"
62 63 64 65
            "You select a color objects such as your face and it tracks it.\n"
            "This reads from video camera (0 by default, or the camera number the user enters\n"
            "Usage: \n"
            "   ./camshiftdemo [camera number]\n";
ValeryTyumen's avatar
ValeryTyumen committed
66
    cout << hot_keys;
67
}
Gary Bradski's avatar
Gary Bradski committed
68

69
const char* keys =
70
{
ValeryTyumen's avatar
ValeryTyumen committed
71
    "{help h | | show help message}{@camera_number| 0 | camera number}"
72
};
Gary Bradski's avatar
Gary Bradski committed
73

74
int main( int argc, const char** argv )
75
{
76 77 78 79 80
    VideoCapture cap;
    Rect trackWindow;
    int hsize = 16;
    float hranges[] = {0,180};
    const float* phranges = hranges;
81
    CommandLineParser parser(argc, argv, keys);
ValeryTyumen's avatar
ValeryTyumen committed
82 83 84 85 86
    if (parser.has("help"))
    {
        help();
        return 0;
    }
87
    int camNum = parser.get<int>(0);
88
    cap.open(camNum);
89

90
    if( !cap.isOpened() )
91
    {
92
        help();
93 94
        cout << "***Could not initialize capturing...***\n";
        cout << "Current parameter's value: \n";
95
        parser.printMessage();
96
        return -1;
97
    }
ValeryTyumen's avatar
ValeryTyumen committed
98
    cout << hot_keys;
99 100
    namedWindow( "Histogram", 0 );
    namedWindow( "CamShift Demo", 0 );
101 102 103 104
    setMouseCallback( "CamShift Demo", onMouse, 0 );
    createTrackbar( "Vmin", "CamShift Demo", &vmin, 256, 0 );
    createTrackbar( "Vmax", "CamShift Demo", &vmax, 256, 0 );
    createTrackbar( "Smin", "CamShift Demo", &smin, 256, 0 );
105

106 107
    Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
    bool paused = false;
108

109 110
    for(;;)
    {
111 112 113 114 115 116
        if( !paused )
        {
            cap >> frame;
            if( frame.empty() )
                break;
        }
117

118
        frame.copyTo(image);
119

120
        if( !paused )
121
        {
122
            cvtColor(image, hsv, COLOR_BGR2HSV);
123

124
            if( trackObject )
125
            {
126 127 128 129 130 131 132 133 134
                int _vmin = vmin, _vmax = vmax;

                inRange(hsv, Scalar(0, smin, MIN(_vmin,_vmax)),
                        Scalar(180, 256, MAX(_vmin, _vmax)), mask);
                int ch[] = {0, 0};
                hue.create(hsv.size(), hsv.depth());
                mixChannels(&hsv, 1, &hue, 1, ch, 1);

                if( trackObject < 0 )
135
                {
136 137
                    Mat roi(hue, selection), maskroi(mask, selection);
                    calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
138
                    normalize(hist, hist, 0, 255, NORM_MINMAX);
139

140 141 142 143 144 145 146 147
                    trackWindow = selection;
                    trackObject = 1;

                    histimg = Scalar::all(0);
                    int binW = histimg.cols / hsize;
                    Mat buf(1, hsize, CV_8UC3);
                    for( int i = 0; i < hsize; i++ )
                        buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180./hsize), 255, 255);
148
                    cvtColor(buf, buf, COLOR_HSV2BGR);
149

150 151 152 153 154 155 156
                    for( int i = 0; i < hsize; i++ )
                    {
                        int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);
                        rectangle( histimg, Point(i*binW,histimg.rows),
                                   Point((i+1)*binW,histimg.rows - val),
                                   Scalar(buf.at<Vec3b>(i)), -1, 8 );
                    }
157 158
                }

159 160 161
                calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
                backproj &= mask;
                RotatedRect trackBox = CamShift(backproj, trackWindow,
162
                                    TermCriteria( TermCriteria::EPS | TermCriteria::COUNT, 10, 1 ));
163 164 165 166 167 168 169
                if( trackWindow.area() <= 1 )
                {
                    int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
                    trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
                                       trackWindow.x + r, trackWindow.y + r) &
                                  Rect(0, 0, cols, rows);
                }
170

171
                if( backprojMode )
172 173
                    cvtColor( backproj, image, COLOR_GRAY2BGR );
                ellipse( image, trackBox, Scalar(0,0,255), 3, LINE_AA );
174
            }
175
        }
176 177
        else if( trackObject < 0 )
            paused = false;
178

179
        if( selectObject && selection.width > 0 && selection.height > 0 )
180
        {
181 182
            Mat roi(image, selection);
            bitwise_not(roi, roi);
183 184
        }

185 186
        imshow( "CamShift Demo", image );
        imshow( "Histogram", histimg );
187

188 189
        char c = (char)waitKey(10);
        if( c == 27 )
190
            break;
191
        switch(c)
192 193
        {
        case 'b':
194
            backprojMode = !backprojMode;
195 196
            break;
        case 'c':
197 198
            trackObject = 0;
            histimg = Scalar::all(0);
199 200
            break;
        case 'h':
201 202 203
            showHist = !showHist;
            if( !showHist )
                destroyWindow( "Histogram" );
204
            else
205
                namedWindow( "Histogram", 1 );
206
            break;
207 208 209
        case 'p':
            paused = !paused;
            break;
210 211 212 213 214 215 216
        default:
            ;
        }
    }

    return 0;
}