//objectTrackingTutorial.cpp //Written by Kyle Hounslow 2013 //Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software") //, to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, //and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: //The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS //IN THE SOFTWARE. #include #include #include #include #include using namespace cv; //initial min and max HSV filter values. //these will be changed using trackbars int H_MIN = 0; int H_MAX = 256; int S_MIN = 0; int S_MAX = 256; int V_MIN = 0; int V_MAX = 256; //default capture width and height const int FRAME_WIDTH = 640; const int FRAME_HEIGHT = 480; //max number of objects to be detected in frame const int MAX_NUM_OBJECTS=50; //minimum and maximum object area const int MIN_OBJECT_AREA = 20*20; const int MAX_OBJECT_AREA = FRAME_HEIGHT*FRAME_WIDTH/1.5; //names that will appear at the top of each window const string windowName = "Original Image"; const string windowName1 = "HSV Image"; const string windowName2 = "Thresholded Image"; const string windowName3 = "After Morphological Operations"; const string trackbarWindowName = "Trackbars"; void on_trackbar( int, void* ) {//This function gets called whenever a // trackbar position is changed } string intToString(int number){ std::stringstream ss; ss << number; return ss.str(); } void createTrackbars(){ //create window for trackbars namedWindow(trackbarWindowName,0); //create memory to store trackbar name on window char TrackbarName[50]; sprintf( TrackbarName, "H_MIN", H_MIN); sprintf( TrackbarName, "H_MAX", H_MAX); sprintf( TrackbarName, "S_MIN", S_MIN); sprintf( TrackbarName, "S_MAX", S_MAX); sprintf( TrackbarName, "V_MIN", V_MIN); sprintf( TrackbarName, "V_MAX", V_MAX); //create trackbars and insert them into window //3 parameters are: the address of the variable that is changing when the trackbar is moved(eg.H_LOW), //the max value the trackbar can move (eg. H_HIGH), //and the function that is called whenever the trackbar is moved(eg. on_trackbar) // ----> ----> ----> createTrackbar( "H_MIN", trackbarWindowName, &H_MIN, H_MAX, on_trackbar ); createTrackbar( "H_MAX", trackbarWindowName, &H_MAX, H_MAX, on_trackbar ); createTrackbar( "S_MIN", trackbarWindowName, &S_MIN, S_MAX, on_trackbar ); createTrackbar( "S_MAX", trackbarWindowName, &S_MAX, S_MAX, on_trackbar ); createTrackbar( "V_MIN", trackbarWindowName, &V_MIN, V_MAX, on_trackbar ); createTrackbar( "V_MAX", trackbarWindowName, &V_MAX, V_MAX, on_trackbar ); } void drawObject(int x, int y,Mat &frame){ //use some of the openCV drawing functions to draw crosshairs //on your tracked image! //UPDATE:JUNE 18TH, 2013 //added 'if' and 'else' statements to prevent //memory errors from writing off the screen (ie. (-25,-25) is not within the window!) circle(frame,Point(x,y),20,Scalar(0,255,0),2); if(y-25>0) line(frame,Point(x,y),Point(x,y-25),Scalar(0,255,0),2); else line(frame,Point(x,y),Point(x,0),Scalar(0,255,0),2); if(y+250) line(frame,Point(x,y),Point(x-25,y),Scalar(0,255,0),2); else line(frame,Point(x,y),Point(0,y),Scalar(0,255,0),2); if(x+25 > contours; vector hierarchy; //find contours of filtered image using openCV findContours function findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE ); //use moments method to find our filtered object double refArea = 0; bool objectFound = false; if (hierarchy.size() > 0) { int numObjects = hierarchy.size(); //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter if(numObjects= 0; index = hierarchy[index][0]) { Moments moment = moments((cv::Mat)contours[index]); double area = moment.m00; //if the area is less than 20 px by 20px then it is probably just noise //if the area is the same as the 3/2 of the image size, probably just a bad filter //we only want the object with the largest area so we safe a reference area each //iteration and compare it to the area in the next iteration. if(area>MIN_OBJECT_AREA && arearefArea){ x = moment.m10/area; y = moment.m01/area; objectFound = true; refArea = area; }else objectFound = false; } //let user know you found an object if(objectFound ==true){ putText(cameraFeed,"Tracking Object",Point(0,50),2,1,Scalar(0,255,0),2); //draw object location on screen drawObject(x,y,cameraFeed);} }else putText(cameraFeed,"TOO MUCH NOISE! ADJUST FILTER",Point(0,50),1,2,Scalar(0,0,255),2); } } int main(int argc, char* argv[]) { //some boolean variables for different functionality within this //program bool trackObjects = false; bool useMorphOps = false; //Matrix to store each frame of the webcam feed Mat cameraFeed; //matrix storage for HSV image Mat HSV; //matrix storage for binary threshold image Mat threshold; //x and y values for the location of the object int x=0, y=0; //create slider bars for HSV filtering createTrackbars(); //video capture object to acquire webcam feed VideoCapture capture; //open capture object at location zero (default location for webcam) capture.open(0); //set height and width of capture frame capture.set(CV_CAP_PROP_FRAME_WIDTH,FRAME_WIDTH); capture.set(CV_CAP_PROP_FRAME_HEIGHT,FRAME_HEIGHT); //start an infinite loop where webcam feed is copied to cameraFeed matrix //all of our operations will be performed within this loop while(1){ //store image to matrix capture.read(cameraFeed); //convert frame from BGR to HSV colorspace cvtColor(cameraFeed,HSV,COLOR_BGR2HSV); //filter HSV image between values and store filtered image to //threshold matrix inRange(HSV,Scalar(H_MIN,S_MIN,V_MIN),Scalar(H_MAX,S_MAX,V_MAX),threshold); //perform morphological operations on thresholded image to eliminate noise //and emphasize the filtered object(s) if(useMorphOps) morphOps(threshold); //pass in thresholded frame to our object tracking function //this function will return the x and y coordinates of the //filtered object if(trackObjects) trackFilteredObject(x,y,threshold,cameraFeed); //show frames imshow(windowName2,threshold); imshow(windowName,cameraFeed); imshow(windowName1,HSV); //delay 30ms so that screen can refresh. //image will not appear without this waitKey() command waitKey(30); } return 0; }