1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/core/utility.hpp" 2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/core/ocl.hpp" 3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/video/tracking.hpp" 4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/imgproc/imgproc.hpp" 5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/videoio/videoio.hpp" 6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "opencv2/highgui/highgui.hpp" 7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <iostream> 9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include <cctype> 10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic cv::UMat image; 12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic bool backprojMode = false; 13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic bool selectObject = false; 14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int trackObject = 0; 15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic bool showHist = true; 16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic cv::Rect selection; 17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic int vmin = 10, vmax = 256, smin = 30; 18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void onMouse(int event, int x, int y, int, void*) 20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{ 21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler static cv::Point origin; 22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (selectObject) 24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selection.x = std::min(x, origin.x); 26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selection.y = std::min(y, origin.y); 27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selection.width = std::abs(x - origin.x); 28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selection.height = std::abs(y - origin.y); 29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selection &= cv::Rect(0, 0, image.cols, image.rows); 31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler switch (event) 34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler case cv::EVENT_LBUTTONDOWN: 36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler origin = cv::Point(x, y); 37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selection = cv::Rect(x, y, 0, 0); 38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selectObject = true; 39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler case cv::EVENT_LBUTTONUP: 41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler selectObject = false; 42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (selection.width > 0 && selection.height > 0) 43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler trackObject = -1; 44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler default: 46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerstatic void help() 51793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{ 52793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler std::cout << "\nThis is a demo that shows mean-shift based tracking using Transparent API\n" 53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "You select a color objects such as your face and it tracks it.\n" 54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "This reads from video camera (0 by default, or the camera number the user enters\n" 55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "Usage: \n" 56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler " ./camshiftdemo [camera number]\n"; 57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler std::cout << "\n\nHot keys: \n" 59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "\tESC - quit the program\n" 60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "\ts - stop the tracking\n" 61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "\tb - switch to/from backprojection view\n" 62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "\th - show/hide object histogram\n" 63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "\tp - pause video\n" 64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "\tc - use OpenCL or not\n" 65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler "To initialize tracking, select the object with mouse\n"; 66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerint main(int argc, const char ** argv) 69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{ 70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler help(); 71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::VideoCapture cap; 73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Rect trackWindow; 74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int hsize = 16; 75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler float hranges[2] = { 0, 180 }; 76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler const char * const keys = { "{@camera_number| 0 | camera number}" }; 78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::CommandLineParser parser(argc, argv, keys); 79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int camNum = parser.get<int>(0); 80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cap.open(camNum); 82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (!cap.isOpened()) 84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler help(); 86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler std::cout << "***Could not initialize capturing...***\n"; 88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler std::cout << "Current parameter's value: \n"; 89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler parser.printMessage(); 90793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return EXIT_FAILURE; 92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::namedWindow("Histogram", cv::WINDOW_NORMAL); 95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::namedWindow("CamShift Demo", cv::WINDOW_NORMAL); 96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::setMouseCallback("CamShift Demo", onMouse); 97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::createTrackbar("Vmin", "CamShift Demo", &vmin, 256); 98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::createTrackbar("Vmax", "CamShift Demo", &vmax, 256); 99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::createTrackbar("Smin", "CamShift Demo", &smin, 256); 100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Mat frame, histimg(200, 320, CV_8UC3, cv::Scalar::all(0)); 102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::UMat hsv, hist, hue, mask, backproj; 103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler bool paused = false; 104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for ( ; ; ) 106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (!paused) 108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cap >> frame; 110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (frame.empty()) 111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler frame.copyTo(image); 115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (!paused) 117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV); 119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (trackObject) 121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int _vmin = vmin, _vmax = vmax; 123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::inRange(hsv, cv::Scalar(0, smin, std::min(_vmin, _vmax)), 125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Scalar(180, 256, std::max(_vmin, _vmax)), mask); 126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int fromTo[2] = { 0,0 }; 128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler hue.create(hsv.size(), hsv.depth()); 129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::mixChannels(std::vector<cv::UMat>(1, hsv), std::vector<cv::UMat>(1, hue), fromTo, 1); 130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (trackObject < 0) 132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::UMat roi(hue, selection), maskroi(mask, selection); 134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::calcHist(std::vector<cv::Mat>(1, roi.getMat(cv::ACCESS_READ)), std::vector<int>(1, 0), 135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler maskroi, hist, std::vector<int>(1, hsize), std::vector<float>(hranges, hranges + 2)); 136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::normalize(hist, hist, 0, 255, cv::NORM_MINMAX); 137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler trackWindow = selection; 139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler trackObject = 1; 140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler histimg = cv::Scalar::all(0); 142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int binW = histimg.cols / hsize; 143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Mat buf (1, hsize, CV_8UC3); 144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (int i = 0; i < hsize; i++) 145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler buf.at<cv::Vec3b>(i) = cv::Vec3b(cv::saturate_cast<uchar>(i*180./hsize), 255, 255); 146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::cvtColor(buf, buf, cv::COLOR_HSV2BGR); 147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Mat _hist = hist.getMat(cv::ACCESS_READ); 150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler for (int i = 0; i < hsize; i++) 151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int val = cv::saturate_cast<int>(_hist.at<float>(i)*histimg.rows/255); 153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::rectangle(histimg, cv::Point(i*binW, histimg.rows), 154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Point((i+1)*binW, histimg.rows - val), 155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Scalar(buf.at<cv::Vec3b>(i)), -1, 8); 156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::calcBackProject(std::vector<cv::UMat>(1, hue), std::vector<int>(1, 0), hist, backproj, 161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler std::vector<float>(hranges, hranges + 2), 1.0); 162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::bitwise_and(backproj, mask, backproj); 163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::RotatedRect trackBox = cv::CamShift(backproj, trackWindow, 165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::TermCriteria(cv::TermCriteria::EPS | cv::TermCriteria::COUNT, 10, 1)); 166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (trackWindow.area() <= 1) 167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler int cols = backproj.cols, rows = backproj.rows, r = (std::min(cols, rows) + 5)/6; 169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r, 170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler trackWindow.x + r, trackWindow.y + r) & 171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Rect(0, 0, cols, rows); 172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (backprojMode) 175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::cvtColor(backproj, image, cv::COLOR_GRAY2BGR); 176793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 177793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 178793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::Mat _image = image.getMat(cv::ACCESS_RW); 179793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::ellipse(_image, trackBox, cv::Scalar(0, 0, 255), 3, cv::LINE_AA); 180793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 181793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 182793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 183793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler else if (trackObject < 0) 184793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler paused = false; 185793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 186793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (selectObject && selection.width > 0 && selection.height > 0) 187793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 188793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::UMat roi(image, selection); 189793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::bitwise_not(roi, roi); 190793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 191793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 192793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::imshow("CamShift Demo", image); 193793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (showHist) 194793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::imshow("Histogram", histimg); 195793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 196793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler char c = (char)cv::waitKey(10); 197793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (c == 27) 198793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 199793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 200793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler switch(c) 201793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler { 202793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler case 'b': 203793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler backprojMode = !backprojMode; 204793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 205793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler case 't': 206793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler trackObject = 0; 207793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler histimg = cv::Scalar::all(0); 208793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 209793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler case 'h': 210793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler showHist = !showHist; 211793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler if (!showHist) 212793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::destroyWindow("Histogram"); 213793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler else 214793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::namedWindow("Histogram", cv::WINDOW_AUTOSIZE); 215793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 216793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler case 'p': 217793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler paused = !paused; 218793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 219793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler case 'c': 220793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler cv::ocl::setUseOpenCL(!cv::ocl::useOpenCL()); 221793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler default: 222793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler break; 223793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 224793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler } 225793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler 226793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler return EXIT_SUCCESS; 227793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler} 228