You are on page 1of 2

8/18/2018 motionTracking.

cpp

1 //motionTracking.cpp
2
3 //Written by Kyle Hounslow, December 2013
4
5 //Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software")
6 //, to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 //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:
8
9 //The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
13 //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
14 //IN THE SOFTWARE.
15
16 #include <opencv\cv.h>
17 #include <opencv\highgui.h>
18
19 using namespace std;
20 using namespace cv;
21
22 //our sensitivity value to be used in the absdiff() function
23 const static int SENSITIVITY_VALUE = 20;
24 //size of blur used to smooth the intensity image output from absdiff() function
25 const static int BLUR_SIZE = 10;
26 //we'll have just one object to search for
27 //and keep track of its position.
28 int theObject[2] = {0,0};
29 //bounding rectangle of the object, we will use the center of this as its position.
30 Rect objectBoundingRectangle = Rect(0,0,0,0);
31
32
33 //int to string helper function
34 string intToString(int number){
35
36 //this function has a number input and string output
37 std::stringstream ss;
38 ss << number;
39 return ss.str();
40 }
41
42 void searchForMovement(Mat thresholdImage, Mat &cameraFeed){
43 //notice how we use the '&' operator for objectDetected and cameraFeed. This is because we wish
44 //to take the values passed into the function and manipulate them, rather than just working with a copy.
45 //eg. we draw to the cameraFeed to be displayed in the main() function.
46 bool objectDetected = false;
47 Mat temp;
48 thresholdImage.copyTo(temp);
49 //these two vectors needed for output of findContours
50 vector< vector<Point> > contours;
51 vector<Vec4i> hierarchy;
52 //find contours of filtered image using openCV findContours function
53 //findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );// retrieves all contours
54 findContours(temp,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE );// retrieves external contours
55
56 //if contours vector is not empty, we have found some objects
57 if(contours.size()>0)objectDetected=true;
58 else objectDetected = false;
59
60 if(objectDetected){
61 //the largest contour is found at the end of the contours vector
62 //we will simply assume that the biggest contour is the object we are looking for.
63 vector< vector<Point> > largestContourVec;
64 largestContourVec.push_back(contours.at(contours.size()-1));
65 //make a bounding rectangle around the largest contour then find its centroid
66 //this will be the object's final estimated position.
67 objectBoundingRectangle = boundingRect(largestContourVec.at(0));
68 int xpos = objectBoundingRectangle.x+objectBoundingRectangle.width/2;
69 int ypos = objectBoundingRectangle.y+objectBoundingRectangle.height/2;
70
71 //update the objects positions by changing the 'theObject' array values
72 theObject[0] = xpos , theObject[1] = ypos;
73 }
74 //make some temp x and y variables so we dont have to type out so much
75 int x = theObject[0];
76 int y = theObject[1];
77
78 //draw some crosshairs around the object
79 circle(cameraFeed,Point(x,y),20,Scalar(0,255,0),2);
80 line(cameraFeed,Point(x,y),Point(x,y-25),Scalar(0,255,0),2);
81 line(cameraFeed,Point(x,y),Point(x,y+25),Scalar(0,255,0),2);
82 line(cameraFeed,Point(x,y),Point(x-25,y),Scalar(0,255,0),2);
83 line(cameraFeed,Point(x,y),Point(x+25,y),Scalar(0,255,0),2);
84
85 //write the position of the object to the screen
86 putText(cameraFeed,"Tracking object at (" + intToString(x)+","+intToString(y)+")",Point(x,y),1,1,Scalar(255,0,0),2);
87
88
89
90 }
91 int main(){
92
93 //some boolean variables for added functionality
94 bool objectDetected = false;
95 //these two can be toggled by pressing 'd' or 't'
96 bool debugMode = false;
97 bool trackingEnabled = false;
98 //pause and resume code
99 bool pause = false;
100 //set up the matrices that we will need
101 //the two frames we will be comparing
102 Mat frame1,frame2;
103 //their grayscale images (needed for absdiff() function)
104 Mat grayImage1,grayImage2;
105 //resulting difference image
106 Mat differenceImage;
107 //thresholded difference image (for use in findContours() function)
108 Mat thresholdImage;
109 //video capture object.
110 VideoCapture capture;
111
112 while(1){
113
114 //we can loop the video by re-opening the capture every time the video reaches its last frame
115
116 capture.open("bouncingBall.avi");
117
118 if(!capture.isOpened()){

https://www.dropbox.com/s/67gtew15zn2rpun/motionTracking.cpp?dl=0 1/2
8/18/2018 motionTracking.cpp
119 cout<<"ERROR ACQUIRING VIDEO FEED\n";
120 getchar();
121 return -1;
122 }
123
124 //check if the video has reach its last frame.
125 //we add '-1' because we are reading two frames from the video at a time.
126 //if this is not included, we get a memory error!
127 while(capture.get(CV_CAP_PROP_POS_FRAMES)<capture.get(CV_CAP_PROP_FRAME_COUNT)-1){
128
129 //read first frame
130 capture.read(frame1);
131 //convert frame1 to gray scale for frame differencing
132 cv::cvtColor(frame1,grayImage1,COLOR_BGR2GRAY);
133 //copy second frame
134 capture.read(frame2);
135 //convert frame2 to gray scale for frame differencing
136 cv::cvtColor(frame2,grayImage2,COLOR_BGR2GRAY);
137 //perform frame differencing with the sequential images. This will output an "intensity image"
138 //do not confuse this with a threshold image, we will need to perform thresholding afterwards.
139 cv::absdiff(grayImage1,grayImage2,differenceImage);
140 //threshold intensity image at a given sensitivity value
141 cv::threshold(differenceImage,thresholdImage,SENSITIVITY_VALUE,255,THRESH_BINARY);
142 if(debugMode==true){
143 //show the difference image and threshold image
144 cv::imshow("Difference Image",differenceImage);
145 cv::imshow("Threshold Image", thresholdImage);
146 }else{
147 //if not in debug mode, destroy the windows so we don't see them anymore
148 cv::destroyWindow("Difference Image");
149 cv::destroyWindow("Threshold Image");
150 }
151 //blur the image to get rid of the noise. This will output an intensity image
152 cv::blur(thresholdImage,thresholdImage,cv::Size(BLUR_SIZE,BLUR_SIZE));
153 //threshold again to obtain binary image from blur output
154 cv::threshold(thresholdImage,thresholdImage,SENSITIVITY_VALUE,255,THRESH_BINARY);
155 if(debugMode==true){
156 //show the threshold image after it's been "blurred"
157
158 imshow("Final Threshold Image",thresholdImage);
159
160 }
161 else {
162 //if not in debug mode, destroy the windows so we don't see them anymore
163 cv::destroyWindow("Final Threshold Image");
164 }
165
166 //if tracking enabled, search for contours in our thresholded image
167 if(trackingEnabled){
168
169 searchForMovement(thresholdImage,frame1);
170 }
171
172 //show our captured frame
173 imshow("Frame1",frame1);
174 //check to see if a button has been pressed.
175 //this 10ms delay is necessary for proper operation of this program
176 //if removed, frames will not have enough time to referesh and a blank
177 //image will appear.
178 switch(waitKey(10)){
179
180 case 27: //'esc' key has been pressed, exit program.
181 return 0;
182 case 116: //'t' has been pressed. this will toggle tracking
183 trackingEnabled = !trackingEnabled;
184 if(trackingEnabled == false) cout<<"Tracking disabled."<<endl;
185 else cout<<"Tracking enabled."<<endl;
186 break;
187 case 100: //'d' has been pressed. this will debug mode
188 debugMode = !debugMode;
189 if(debugMode == false) cout<<"Debug mode disabled."<<endl;
190 else cout<<"Debug mode enabled."<<endl;
191 break;
192 case 112: //'p' has been pressed. this will pause/resume the code.
193 pause = !pause;
194 if(pause == true){ cout<<"Code paused, press 'p' again to resume"<<endl;
195 while (pause == true){
196 //stay in this loop until
197 switch (waitKey()){
198 //a switch statement inside a switch statement? Mind blown.
199 case 112:
200 //change pause back to false
201 pause = false;
202 cout<<"Code Resumed"<<endl;
203 break;
204 }
205 }
206 }
207
208
209
210 }
211 }
212 //release the capture before re-opening and looping again.
213 capture.release();
214 }
215
216 return 0;
217
218 }

https://www.dropbox.com/s/67gtew15zn2rpun/motionTracking.cpp?dl=0 2/2

You might also like