//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 #include #include "Fruit.h" 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 = 40*40; 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(vector theFruits,Mat &frame){ for(int i =0; i apples; Mat temp; threshold.copyTo(temp); //these two vectors needed for output of findContours vector< vector > 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){ Fruit apple; apple.setXPos(moment.m10/area); apple.setYPos(moment.m01/area); apples.push_back(apple); objectFound = true; }else objectFound = false; } //let user know you found an object if(objectFound ==true){ //draw object location on screen drawObject(apples,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[]) { //if we would like to calibrate our filter values, set to true. bool calibrationMode = true; //Matrix to store each frame of the webcam feed Mat cameraFeed; Mat threshold; Mat HSV; if(calibrationMode){ //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); if(calibrationMode==true){ //if in calibration mode, we track objects based on the HSV slider values. cvtColor(cameraFeed,HSV,COLOR_BGR2HSV); inRange(HSV,Scalar(H_MIN,S_MIN,V_MIN),Scalar(H_MAX,S_MAX,V_MAX),threshold); morphOps(threshold); imshow(windowName2,threshold); trackFilteredObject(threshold,HSV,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; }