Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Ideal motion/object tracking method

Hi all,

I would like to get an idea of the best way to go about tracking people with an ceiling-mounted IP camera. Ultimately, I would like to have an application that does the following:

  • identifies moving objects then assigns them with an identifier of some kind (object1, object2, etc.)
  • draw a rectangle around each object and add the object ID to it as a tag
  • capture the x and y coordinates of the object or rectangle, preferably the center (it seems that this can be done using the moments() method)
  • draw a line from the previous x,y coordinates of each object to the current coordinates

I have been playing with BackgroundSubtractorMOG2, but before I move on I would like to know if there's a better way of going about this. I'm working in C++ on a Win7 machine. I've just started working with OpenCV, and my C++ skills are fairly limited. In fact my only real C experience is with Objective-C, so any advice on how to achieve the above tasks would be greatly appreciated.

My code to date:

#include <sstream>
#include <string>
#include <iostream>
#include <opencv\highgui.h>
#include <opencv\cv.h>
#include <vector>
#include <background_segm.hpp>
#include <opencv2/opencv.hpp>

using namespace cv;

int nmixtures = 25;
int bShadowDetection = 1;
int history = 25;

const string trackbarWindowName = "Trackbars";

void on_trackbar( int, void* ){
//This function gets called whenever a trackbar position is changed
}

void createTrackbars(){
//create window for trackbars
namedWindow(trackbarWindowName,0);
//create memory to store trackbar name on window
char TrackbarName[50];
sprintf_s( TrackbarName, "nmixtures", nmixtures);
sprintf_s( TrackbarName, "bShadowDetection", bShadowDetection);
sprintf_s( TrackbarName, "history", history);
//create trackbars and insert them into window    
createTrackbar( "nmixtures", trackbarWindowName, &nmixtures, nmixtures, on_trackbar );
createTrackbar( "bShadowDetection", trackbarWindowName, &bShadowDetection, bShadowDetection, on_trackbar );
createTrackbar( "history", trackbarWindowName, &history, history, on_trackbar );
}

int main(int argc, char *argv[])
{
//if we would like to calibrate our values, set to true.
bool calibrationMode = true;

cv::Mat frame;
cv::Mat back;
cv::Mat fore;
const bool boolShadowDetection = false;

if(calibrationMode){
    //create slider bars for HSV filtering
    createTrackbars();
    if(bShadowDetection == 1){
        const bool boolShadowDetection = true;
    } else if (bShadowDetection == 0){
        const bool boolShadowDetection = false;
    }
}

cv::VideoCapture cap("IPCamAddress");

float fltHistory = (float)history;
float fltNmixtures = (float)nmixtures;

cv::BackgroundSubtractorMOG2 bg (history,fltNmixtures,boolShadowDetection);

std::vector<std::vector<cv::Point> > contours;

cv::namedWindow("Frame");
cv::namedWindow("Background");

for(;;)
{
    cap >> frame;
    bg.operator ()(frame,fore);
    bg.getBackgroundImage(back);
    cv::erode(fore,fore,cv::Mat());
    cv::dilate(fore,fore,cv::Mat());
    cv::findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
    cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
    cv::imshow("Frame",frame);
    cv::imshow("Background",back);
    if(cv::waitKey(30) >= 0) break;
}
return 0;
}

Ideal motion/object tracking method

Hi all,

I would like to get an idea of the best way to go about tracking people with an ceiling-mounted IP camera. Ultimately, I would like to have an application that does the following:

  • show the video feed in a primary window
  • identifies moving objects then assigns them with an identifier of some kind (object1, object2, etc.)
  • in the primary window, draw a rectangle around each object and add the object ID to it as a tag
  • capture the x and y coordinates of the object or rectangle, preferably the center (it seems that this can be done using the moments() method)
  • in a second window show a binary image of blobs/people in black and everything else in white
  • on the binary image, draw a line from the previous x,y coordinates of each object to the current coordinates

I have been playing with BackgroundSubtractorMOG2, but before I move on I would like to know if there's a better way of going about this. I'm working in C++ on a Win7 machine. I've just started working with OpenCV, and my C++ skills are fairly limited. In fact my only real C experience is with Objective-C, so any advice on how to achieve the above tasks would be greatly appreciated.

My code to date:

#include <sstream>
#include <string>
#include <iostream>
#include <opencv\highgui.h>
#include <opencv\cv.h>
#include <vector>
#include <background_segm.hpp>
#include <opencv2/opencv.hpp>

using namespace cv;

int nmixtures = 25;
int bShadowDetection = 1;
int history = 25;

const string trackbarWindowName = "Trackbars";

void on_trackbar( int, void* ){
//This function gets called whenever a trackbar position is changed
}

void createTrackbars(){
//create window for trackbars
namedWindow(trackbarWindowName,0);
//create memory to store trackbar name on window
char TrackbarName[50];
sprintf_s( TrackbarName, "nmixtures", nmixtures);
sprintf_s( TrackbarName, "bShadowDetection", bShadowDetection);
sprintf_s( TrackbarName, "history", history);
//create trackbars and insert them into window    
createTrackbar( "nmixtures", trackbarWindowName, &nmixtures, nmixtures, on_trackbar );
createTrackbar( "bShadowDetection", trackbarWindowName, &bShadowDetection, bShadowDetection, on_trackbar );
createTrackbar( "history", trackbarWindowName, &history, history, on_trackbar );
}

int main(int argc, char *argv[])
{
//if we would like to calibrate our values, set to true.
bool calibrationMode = true;

cv::Mat frame;
cv::Mat back;
cv::Mat fore;
const bool boolShadowDetection = false;

if(calibrationMode){
    //create slider bars for HSV filtering
    createTrackbars();
    if(bShadowDetection == 1){
        const bool boolShadowDetection = true;
    } else if (bShadowDetection == 0){
        const bool boolShadowDetection = false;
    }
}

cv::VideoCapture cap("IPCamAddress");

float fltHistory = (float)history;
float fltNmixtures = (float)nmixtures;

cv::BackgroundSubtractorMOG2 bg (history,fltNmixtures,boolShadowDetection);

std::vector<std::vector<cv::Point> > contours;

cv::namedWindow("Frame");
cv::namedWindow("Background");

for(;;)
{
    cap >> frame;
    bg.operator ()(frame,fore);
    bg.getBackgroundImage(back);
    cv::erode(fore,fore,cv::Mat());
    cv::dilate(fore,fore,cv::Mat());
    cv::findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
    cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
    cv::imshow("Frame",frame);
    cv::imshow("Background",back);
    if(cv::waitKey(30) >= 0) break;
}
return 0;
}

Ideal motion/object tracking method

Hi all,

I would like to get an idea of the best way to go about tracking people with an ceiling-mounted IP camera. Ultimately, I would like to have an application that does the following:

  • show the video feed in a primary window
  • identifies moving objects then assigns them with an identifier of some kind (object1, object2, etc.)
  • in the primary window, draw a rectangle around each object and add the object ID to it as a tag
  • capture the x and y coordinates of the object or rectangle, preferably the center (it seems that this can be done using the moments() method)
  • in a second window show a binary image of blobs/people in black and everything else in white
  • on the binary image, draw a line from the previous x,y coordinates of each object to the current coordinates

I have been playing with BackgroundSubtractorMOG2, but before I move on I would like to know if there's a better way of going about this. I'm working in C++ on a Win7 machine. I've just started working with OpenCV, and my C++ skills are fairly limited. In fact my only real C experience is with Objective-C, so any advice on how to achieve the above tasks would be greatly appreciated.

My code to date:

#include <sstream>
#include <string>
#include <iostream>
#include <opencv\highgui.h>
#include <opencv\cv.h>
#include <vector>
#include <background_segm.hpp>
#include <opencv2/opencv.hpp>

using namespace cv;

int nmixtures = 25;
int bShadowDetection = 1;
int history = 25;

const string trackbarWindowName = "Trackbars";

void on_trackbar( int, void* ){
//This function gets called whenever a trackbar position is changed
}

void createTrackbars(){
//create window for trackbars
namedWindow(trackbarWindowName,0);
//create memory to store trackbar name on window
char TrackbarName[50];
sprintf_s( TrackbarName, "nmixtures", nmixtures);
sprintf_s( TrackbarName, "bShadowDetection", bShadowDetection);
sprintf_s( TrackbarName, "history", history);
//create trackbars and insert them into window    
createTrackbar( "nmixtures", trackbarWindowName, &nmixtures, nmixtures, on_trackbar );
createTrackbar( "bShadowDetection", trackbarWindowName, &bShadowDetection, bShadowDetection, on_trackbar );
createTrackbar( "history", trackbarWindowName, &history, history, on_trackbar );
}

int main(int argc, char *argv[])
{
//if we would like to calibrate our values, set to true.
bool calibrationMode = true;

cv::Mat frame;
cv::Mat back;
cv::Mat fore;
const bool boolShadowDetection = false;

if(calibrationMode){
    //create slider bars for HSV filtering
    createTrackbars();
    if(bShadowDetection == 1){
        const bool boolShadowDetection = true;
    } else if (bShadowDetection == 0){
        const bool boolShadowDetection = false;
    }
}

cv::VideoCapture cap("IPCamAddress");

float fltHistory = (float)history;
float fltNmixtures = (float)nmixtures;

cv::BackgroundSubtractorMOG2 bg (history,fltNmixtures,boolShadowDetection);

std::vector<std::vector<cv::Point> > contours;

cv::namedWindow("Frame");
cv::namedWindow("Background");

for(;;)
{
    cap >> frame;
    bg.operator ()(frame,fore);
    bg.getBackgroundImage(back);
    cv::erode(fore,fore,cv::Mat());
    cv::dilate(fore,fore,cv::Mat());
    cv::findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
    cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
    cv::imshow("Frame",frame);
    cv::imshow("Background",back);
    if(cv::waitKey(30) >= 0) break;
}
return 0;
}

Ideal motion/object tracking method

Hi all,

I would like to get an idea of the best way to go about tracking people with an ceiling-mounted IP camera. Ultimately, I would like to have an application that does the following:

  • show the video feed in a primary window
  • identifies moving objects then assigns them with an identifier of some kind (object1, object2, etc.)
  • in the primary window, draw a rectangle around each object and add the object ID to it as a tag
  • capture the x and y coordinates of the object or rectangle, preferably the center (it seems that this can be done using the moments() method)
  • in a second window show a binary image of blobs/people in black and everything else in white
  • on the binary image, draw a line from the previous x,y coordinates of each object to the current coordinates

EDIT: I am currently getting far too much noise in my image, and cannot limit it with the filters I'm using. I'm also unable to track multiple objects. This may be the result of the example I borrowed from, in which only the object with the largest area is tagged. Unfortunately, I have not been playing with BackgroundSubtractorMOG2, but before I move on I would like able to know if there's a better way of going about this. I'm working in C++ on a Win7 machine. I've just started working with OpenCV, and my C++ skills are fairly limited. In fact my only real C experience is with Objective-C, so any advice on how to achieve the above tasks would be greatly appreciated.fix this.

My code to date:

#include <sstream>
<opencv2/opencv.hpp>
#include <string>
"opencv2/imgproc/imgproc.hpp"
#include <iostream>
"opencv2/highgui/highgui.hpp"
#include <opencv\highgui.h>
"highgui.h"
#include <opencv\cv.h>
<stdlib.h>
#include <vector>
<stdio.h>
#include <background_segm.hpp>
"opencv2\video\background_segm.hpp"

#include <opencv2/opencv.hpp>
<Windows.h>

using namespace cv;
 using namespace std;

/// Global variables
int nmixtures = 25;
hist = 0;
int bShadowDetection const histMax = 10;
int thresh = 0;
int const threshMax = 5000;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;

int lowerH=0;
int lowerS=0;
int lowerV=0;
int upperH=180;
int upperS=256;
int upperV=256;

int MIN_NUM_OBJECTS = 1;
int history = 25;

const string trackbarWindowName = "Trackbars";

MAX_NUM_OBJECTS=100;
int MIN_OBJECT_AREA = 1*1;
int MAX_OBJECT_AREA = 5000*5000;

Mat curVid;         // live feed from IP Cam
Mat imgHSV;
Mat erosion_dst;
Mat dilation_dst;
Mat blur_dst;
Mat mask;           // final filtered image
Mat test;           // test for draw objects

/** Function Headers */
void on_trackbar( setwindowSettings();
void HSV();
void Erosion( int, void* ){
//This function gets called whenever a trackbar position is changed
}

);
void createTrackbars(){
//create window for trackbars
namedWindow(trackbarWindowName,0);
//create memory to store trackbar name on window
char TrackbarName[50];
sprintf_s( TrackbarName, "nmixtures", nmixtures);
sprintf_s( TrackbarName, "bShadowDetection", bShadowDetection);
sprintf_s( TrackbarName, "history", history);
//create trackbars and insert them into window    
createTrackbar( "nmixtures", trackbarWindowName, &nmixtures, nmixtures, on_trackbar Dilation( int, void* );
createTrackbar( "bShadowDetection", trackbarWindowName, &bShadowDetection, bShadowDetection, on_trackbar void Blur( int, void* );
createTrackbar( "history", trackbarWindowName, &history, history, on_trackbar );
}
IplImage* GetThresholdedImage(IplImage* imgHSV);
void trackFilteredObject();
void drawObject(int x,int y,Mat &frame);
string intToString(int number);


int main(int argc, char *argv[])
{
//if we would like     // get cam feed and show in new window
    VideoCapture cap(0);
     if (!cap.isOpened())  // if not success, exit program
    {
         cout << "Cannot open the video file" << endl;
         return -1;
    }

    setwindowSettings();

    // background subtraction init
    BackgroundSubtractorMOG2 bg = BackgroundSubtractorMOG2(hist,thresh,false);

    cap.read(curVid);

    Sleep(5000);

    // show images in windows
    while(1)
    {
        // show camera feed
        bool bSuccess = cap.read(curVid); // read a new frame from video
        if (!bSuccess) // if not success, break loop
        {
            cout << "Cannot read a frame from video file" << endl;
            break;
        }

        // start morph functions then draw
        HSV();
        Erosion( 0, 0 );
        Dilation( 0, 0 );

        // background subtraction
            bg(dilation_dst,mask,-1);
        imshow("mask",mask);

        // draw to calibrate our values, set to true.
bool calibrationMode = true;

cv::Mat frame;
cv::Mat back;
cv::Mat fore;
const bool boolShadowDetection = false;

if(calibrationMode){
    //create slider bars curVid
        trackFilteredObject();

        imshow("test", test);

        // escape program with keystroke
        if (waitKey(30) == 27) //wait for HSV filtering
    createTrackbars();
    if(bShadowDetection == 1){
        const bool boolShadowDetection = true;
    } else if (bShadowDetection == 0){
        const bool boolShadowDetection = false;
'esc' key press for 30ms. If 'esc' key is pressed, break loop
        {
            cout << "esc key is pressed by user" << endl;
            break; 
        }
 }

cv::VideoCapture cap("IPCamAddress");

float fltHistory = (float)history;
float fltNmixtures = (float)nmixtures;

cv::BackgroundSubtractorMOG2 bg (history,fltNmixtures,boolShadowDetection);

std::vector<std::vector<cv::Point> > contours;

cv::namedWindow("Frame");
cv::namedWindow("Background");

for(;;)
{
    cap >> frame;
    bg.operator ()(frame,fore);
    bg.getBackgroundImage(back);
    cv::erode(fore,fore,cv::Mat());
    cv::dilate(fore,fore,cv::Mat());
    cv::findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
    cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
    cv::imshow("Frame",frame);
    cv::imshow("Background",back);
    if(cv::waitKey(30) >= 0) break;
}
 return 0;
}


void setwindowSettings()
{
    namedWindow("Settings", CV_WINDOW_AUTOSIZE);
    resizeWindow("Settings",500,600);
    namedWindow("mask", CV_WINDOW_AUTOSIZE);
    namedWindow("test", CV_WINDOW_AUTOSIZE);

    // Create Erosion Trackbar
    createTrackbar( "EroElem", "Settings",
                    &erosion_elem, max_elem,
                    Erosion );
    createTrackbar( "EroSize", "Settings",
                    &erosion_size, max_kernel_size,
                    Erosion );

    /// Create Dilation Trackbar
    createTrackbar( "DialElem", "Settings",
                    &dilation_elem, max_elem,
                    Dilation );
    createTrackbar( "DialSize", "Settings",
                    &dilation_size, max_kernel_size,
                    Dilation );

    /*/// Create GaussianBlur Trackbars
    createTrackbar( "blurType", "Settings",
                    &blurType, max_blurType,
                    Blur );*/

    /// Create History Trackbar
    createTrackbar( "ImgHist", "Settings",
                    &hist, histMax );

    /// Create Threshold Trackbar
    createTrackbar( "Threshold", "Settings",
                    &thresh, threshMax );

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_NUM_OBJECTS", "Settings", 
                    &MIN_NUM_OBJECTS, 100);
    createTrackbar("MAX_NUM_OBJECTS", "Settings", 
                    &MAX_NUM_OBJECTS, 100);

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_OBJECT_AREA", "Settings", 
                    &MIN_OBJECT_AREA, 5000*5000);
    createTrackbar("MAX_OBJECT_AREA", "Settings", 
                    &MAX_OBJECT_AREA, 5000*5000);

}

/**  @function HSV  */
void HSV()
{
    //cvGetSize(curVid);
    //Mat* img_HSV = cvCreateImage(cvGetSize(curVid), IPL_DEPTH_8U, 3); 
    cvtColor(curVid,imgHSV,CV_BGR2HSV);
    //imgHSV = GetThresholdImage(img_HSV);
    //imshow("HSV", imgHSV);
}

/**  @function Erosion  */
void Erosion( int, void* )
{
  int erosion_type;
  if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
  else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
  else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( erosion_type,
                                       Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                       Point( erosion_size, erosion_size ) );

  /// Apply the erosion operation
  erode( imgHSV, erosion_dst, element );
}

/** @function Dilation */
void Dilation( int, void* )
{
  int dilation_type;
  if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
  else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
  else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( dilation_type,
                                       Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                                       Point( dilation_size, dilation_size ) );
  /// Apply the dilation operation
  dilate( erosion_dst, dilation_dst, element );
}

void trackFilteredObject(){

    int x,y;

    Mat temp;
    mask.copyTo(temp);
    //inRange(mask,Scalar(MIN_OBJECT_AREA),Scalar(MAX_OBJECT_AREA),temp);
    curVid.copyTo(test);
    //these two vectors needed for output of findContours
    vector< vector<Point> > contours;
    vector<Vec4i> hierarchy;
    //find contours of filtered image using openCV findContours function
    findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );


    // iterate through all the top-level contours,
    // draw each connected component with its own random color
    int idx = 0;
    for( ; idx >= 0; idx = hierarchy[idx][0] )
    {
        Scalar color( rand()&0, rand()&0, rand()&255 );
        drawContours( test, contours, idx, color, CV_FILLED, 8, hierarchy );
    }


    //use moments method to find our filtered object
    double refArea = 0;
    bool objectFound = false;
    cout << hierarchy.size() << endl;
    if (hierarchy.size() > 0) {
        int numObjects = hierarchy.size();
        //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
        if(numObjects<MAX_NUM_OBJECTS){
            for (int index = 0; index >= 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
                //this is setup to get the object with the largest area so we safe a reference area each
                //iteration and compare it to the area in the next iteration. DO NOT WANT THIS!
                if(area>MIN_OBJECT_AREA){
                    x = moment.m10/area;
                    y = moment.m01/area;



                    objectFound = true;

                }else objectFound = false;


            }
            //let user know you found an object
            if(objectFound ==true){
                //draw object location on screen
                drawObject(x,y,test);}

        }else putText(test,"TOO MUCH NOISE! ADJUST FILTER",Point(0,50),1,2,Scalar(0,0,255),2);
    }
}


void drawObject(int x,int y,Mat &frame){

    circle(frame,cv::Point(x,y),10,cv::Scalar(0,0,255),3);
    putText(frame,intToString(x)+ " , " + intToString(y),cv::Point(x,y+20),1,1,Scalar(0,255,0));

}

string intToString(int number){


    std::stringstream ss;
    ss << number;
    return ss.str();
}
click to hide/show revision 5
New issues with code

Ideal motion/object tracking method

Hi all,

I would like to get an idea of the best way to go about tracking people with an ceiling-mounted IP camera. Ultimately, I would like to have an application that does the following:

  • show the video feed in a primary window
  • identifies moving objects then assigns them with an identifier of some kind (object1, object2, etc.)
  • in the primary window, draw a rectangle around each object and add the object ID to it as a tag
  • capture the x and y coordinates of the object or rectangle, preferably the center (it seems that this can be done using the moments() method)
  • in a second window show a binary image of blobs/people in black and everything else in white
  • on the binary image, draw a line from the previous x,y coordinates of each object to the current coordinates

EDIT: I am currently getting far too much noise in my binary image, and cannot have not been able to limit it with the filters I'm using. I'm also unable to track and tag multiple objects. This may be the result of the example I borrowed from, in which only the object with the largest area is tagged. Unfortunately, I have not been able to fix this.

My code to date:

#include <opencv2/opencv.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
#include "opencv2\video\background_segm.hpp"

#include <Windows.h>

using namespace cv;
using namespace std;

/// Global variables
int hist = 0;
int const histMax = 10;
int thresh = 0;
int const threshMax = 5000;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;

int lowerH=0;
int lowerS=0;
int lowerV=0;
int upperH=180;
int upperS=256;
int upperV=256;

int MIN_NUM_OBJECTS = 1;
int MAX_NUM_OBJECTS=100;
int MIN_OBJECT_AREA = 1*1;
int MAX_OBJECT_AREA = 5000*5000;

Mat curVid;         // live feed from IP Cam
Mat imgHSV;
Mat erosion_dst;
Mat dilation_dst;
Mat blur_dst;
Mat mask;           // final filtered image
Mat test;           // test for draw objects

/** Function Headers */
void setwindowSettings();
void HSV();
void Erosion( int, void* );
void Dilation( int, void* );
void Blur( int, void* );
IplImage* GetThresholdedImage(IplImage* imgHSV);
void trackFilteredObject();
void drawObject(int x,int y,Mat &frame);
string intToString(int number);


int main(int argc, char *argv[])
{
    // get cam feed and show in new window
    VideoCapture cap(0);
     if (!cap.isOpened())  // if not success, exit program
    {
         cout << "Cannot open the video file" << endl;
         return -1;
    }

    setwindowSettings();

    // background subtraction init
    BackgroundSubtractorMOG2 bg = BackgroundSubtractorMOG2(hist,thresh,false);

    cap.read(curVid);

    Sleep(5000);

    // show images in windows
    while(1)
    {
        // show camera feed
        bool bSuccess = cap.read(curVid); // read a new frame from video
        if (!bSuccess) // if not success, break loop
        {
            cout << "Cannot read a frame from video file" << endl;
            break;
        }

        // start morph functions then draw
        HSV();
        Erosion( 0, 0 );
        Dilation( 0, 0 );

        // background subtraction
            bg(dilation_dst,mask,-1);
        imshow("mask",mask);

        // draw to curVid
        trackFilteredObject();

        imshow("test", test);

        // escape program with keystroke
        if (waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
        {
            cout << "esc key is pressed by user" << endl;
            break; 
        }

    }
    return 0;
}


void setwindowSettings()
{
    namedWindow("Settings", CV_WINDOW_AUTOSIZE);
    resizeWindow("Settings",500,600);
    namedWindow("mask", CV_WINDOW_AUTOSIZE);
    namedWindow("test", CV_WINDOW_AUTOSIZE);

    // Create Erosion Trackbar
    createTrackbar( "EroElem", "Settings",
                    &erosion_elem, max_elem,
                    Erosion );
    createTrackbar( "EroSize", "Settings",
                    &erosion_size, max_kernel_size,
                    Erosion );

    /// Create Dilation Trackbar
    createTrackbar( "DialElem", "Settings",
                    &dilation_elem, max_elem,
                    Dilation );
    createTrackbar( "DialSize", "Settings",
                    &dilation_size, max_kernel_size,
                    Dilation );

    /*/// Create GaussianBlur Trackbars
    createTrackbar( "blurType", "Settings",
                    &blurType, max_blurType,
                    Blur );*/

    /// Create History Trackbar
    createTrackbar( "ImgHist", "Settings",
                    &hist, histMax );

    /// Create Threshold Trackbar
    createTrackbar( "Threshold", "Settings",
                    &thresh, threshMax );

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_NUM_OBJECTS", "Settings", 
                    &MIN_NUM_OBJECTS, 100);
    createTrackbar("MAX_NUM_OBJECTS", "Settings", 
                    &MAX_NUM_OBJECTS, 100);

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_OBJECT_AREA", "Settings", 
                    &MIN_OBJECT_AREA, 5000*5000);
    createTrackbar("MAX_OBJECT_AREA", "Settings", 
                    &MAX_OBJECT_AREA, 5000*5000);

}

/**  @function HSV  */
void HSV()
{
    //cvGetSize(curVid);
    //Mat* img_HSV = cvCreateImage(cvGetSize(curVid), IPL_DEPTH_8U, 3); 
    cvtColor(curVid,imgHSV,CV_BGR2HSV);
    //imgHSV = GetThresholdImage(img_HSV);
    //imshow("HSV", imgHSV);
}

/**  @function Erosion  */
void Erosion( int, void* )
{
  int erosion_type;
  if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
  else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
  else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( erosion_type,
                                       Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                       Point( erosion_size, erosion_size ) );

  /// Apply the erosion operation
  erode( imgHSV, erosion_dst, element );
}

/** @function Dilation */
void Dilation( int, void* )
{
  int dilation_type;
  if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
  else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
  else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( dilation_type,
                                       Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                                       Point( dilation_size, dilation_size ) );
  /// Apply the dilation operation
  dilate( erosion_dst, dilation_dst, element );
}

void trackFilteredObject(){

    int x,y;

    Mat temp;
    mask.copyTo(temp);
    //inRange(mask,Scalar(MIN_OBJECT_AREA),Scalar(MAX_OBJECT_AREA),temp);
    curVid.copyTo(test);
    //these two vectors needed for output of findContours
    vector< vector<Point> > contours;
    vector<Vec4i> hierarchy;
    //find contours of filtered image using openCV findContours function
    findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );


    // iterate through all the top-level contours,
    // draw each connected component with its own random color
    int idx = 0;
    for( ; idx >= 0; idx = hierarchy[idx][0] )
    {
        Scalar color( rand()&0, rand()&0, rand()&255 );
        drawContours( test, contours, idx, color, CV_FILLED, 8, hierarchy );
    }


    //use moments method to find our filtered object
    double refArea = 0;
    bool objectFound = false;
    cout << hierarchy.size() << endl;
    if (hierarchy.size() > 0) {
        int numObjects = hierarchy.size();
        //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
        if(numObjects<MAX_NUM_OBJECTS){
            for (int index = 0; index >= 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
                //this is setup to get the object with the largest area so we safe a reference area each
                //iteration and compare it to the area in the next iteration. DO NOT WANT THIS!
                if(area>MIN_OBJECT_AREA){
                    x = moment.m10/area;
                    y = moment.m01/area;



                    objectFound = true;

                }else objectFound = false;


            }
            //let user know you found an object
            if(objectFound ==true){
                //draw object location on screen
                drawObject(x,y,test);}

        }else putText(test,"TOO MUCH NOISE! ADJUST FILTER",Point(0,50),1,2,Scalar(0,0,255),2);
    }
}


void drawObject(int x,int y,Mat &frame){

    circle(frame,cv::Point(x,y),10,cv::Scalar(0,0,255),3);
    putText(frame,intToString(x)+ " , " + intToString(y),cv::Point(x,y+20),1,1,Scalar(0,255,0));

}

string intToString(int number){


    std::stringstream ss;
    ss << number;
    return ss.str();
}

Ideal motion/object tracking methodmethod - Problems with image noise

Hi all,

I would like to get an idea of the best way to go about tracking people with an ceiling-mounted IP camera. Ultimately, I would like to have an application that does the following:

  • show the video feed in a primary window
  • identifies moving objects then assigns them with an identifier of some kind (object1, object2, etc.)
  • in the primary window, draw a rectangle around each object and add the object ID to it as a tag
  • capture the x and y coordinates of the object or rectangle, preferably the center (it seems that this can be done using the moments() method)
  • in a second window show a binary image of blobs/people in black and everything else in white
  • on the binary image, draw a line from the previous x,y coordinates of each object to the current coordinates

EDIT: I am currently getting far too much noise in my binary image, and have not been able to limit it with the filters I'm using. I'm also unable to track and tag multiple objects. This may be the result of the example I borrowed from, in which only the object with the largest area is tagged. Unfortunately, I have not been able to fix this.

My code to date:

#include <opencv2/opencv.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
#include "opencv2\video\background_segm.hpp"

#include <Windows.h>

using namespace cv;
using namespace std;

/// Global variables
int hist = 0;
int const histMax = 10;
int thresh = 0;
int const threshMax = 5000;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;

int lowerH=0;
int lowerS=0;
int lowerV=0;
int upperH=180;
int upperS=256;
int upperV=256;

int MIN_NUM_OBJECTS = 1;
int MAX_NUM_OBJECTS=100;
int MIN_OBJECT_AREA = 1*1;
int MAX_OBJECT_AREA = 5000*5000;

Mat curVid;         // live feed from IP Cam
Mat imgHSV;
Mat erosion_dst;
Mat dilation_dst;
Mat blur_dst;
Mat mask;           // final filtered image
Mat test;           // test for draw objects

/** Function Headers */
void setwindowSettings();
void HSV();
void Erosion( int, void* );
void Dilation( int, void* );
void Blur( int, void* );
IplImage* GetThresholdedImage(IplImage* imgHSV);
void trackFilteredObject();
void drawObject(int x,int y,Mat &frame);
string intToString(int number);


int main(int argc, char *argv[])
{
    // get cam feed and show in new window
    VideoCapture cap(0);
     if (!cap.isOpened())  // if not success, exit program
    {
         cout << "Cannot open the video file" << endl;
         return -1;
    }

    setwindowSettings();

    // background subtraction init
    BackgroundSubtractorMOG2 bg = BackgroundSubtractorMOG2(hist,thresh,false);

    cap.read(curVid);

    Sleep(5000);

    // show images in windows
    while(1)
    {
        // show camera feed
        bool bSuccess = cap.read(curVid); // read a new frame from video
        if (!bSuccess) // if not success, break loop
        {
            cout << "Cannot read a frame from video file" << endl;
            break;
        }

        // start morph functions then draw
        HSV();
        Erosion( 0, 0 );
        Dilation( 0, 0 );

        // background subtraction
            bg(dilation_dst,mask,-1);
        imshow("mask",mask);

        // draw to curVid
        trackFilteredObject();

        imshow("test", test);

        // escape program with keystroke
        if (waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
        {
            cout << "esc key is pressed by user" << endl;
            break; 
        }

    }
    return 0;
}


void setwindowSettings()
{
    namedWindow("Settings", CV_WINDOW_AUTOSIZE);
    resizeWindow("Settings",500,600);
    namedWindow("mask", CV_WINDOW_AUTOSIZE);
    namedWindow("test", CV_WINDOW_AUTOSIZE);

    // Create Erosion Trackbar
    createTrackbar( "EroElem", "Settings",
                    &erosion_elem, max_elem,
                    Erosion );
    createTrackbar( "EroSize", "Settings",
                    &erosion_size, max_kernel_size,
                    Erosion );

    /// Create Dilation Trackbar
    createTrackbar( "DialElem", "Settings",
                    &dilation_elem, max_elem,
                    Dilation );
    createTrackbar( "DialSize", "Settings",
                    &dilation_size, max_kernel_size,
                    Dilation );

    /*/// Create GaussianBlur Trackbars
    createTrackbar( "blurType", "Settings",
                    &blurType, max_blurType,
                    Blur );*/

    /// Create History Trackbar
    createTrackbar( "ImgHist", "Settings",
                    &hist, histMax );

    /// Create Threshold Trackbar
    createTrackbar( "Threshold", "Settings",
                    &thresh, threshMax );

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_NUM_OBJECTS", "Settings", 
                    &MIN_NUM_OBJECTS, 100);
    createTrackbar("MAX_NUM_OBJECTS", "Settings", 
                    &MAX_NUM_OBJECTS, 100);

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_OBJECT_AREA", "Settings", 
                    &MIN_OBJECT_AREA, 5000*5000);
    createTrackbar("MAX_OBJECT_AREA", "Settings", 
                    &MAX_OBJECT_AREA, 5000*5000);

}

/**  @function HSV  */
void HSV()
{
    //cvGetSize(curVid);
    //Mat* img_HSV = cvCreateImage(cvGetSize(curVid), IPL_DEPTH_8U, 3); 
    cvtColor(curVid,imgHSV,CV_BGR2HSV);
    //imgHSV = GetThresholdImage(img_HSV);
    //imshow("HSV", imgHSV);
}

/**  @function Erosion  */
void Erosion( int, void* )
{
  int erosion_type;
  if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
  else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
  else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( erosion_type,
                                       Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                       Point( erosion_size, erosion_size ) );

  /// Apply the erosion operation
  erode( imgHSV, erosion_dst, element );
}

/** @function Dilation */
void Dilation( int, void* )
{
  int dilation_type;
  if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
  else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
  else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( dilation_type,
                                       Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                                       Point( dilation_size, dilation_size ) );
  /// Apply the dilation operation
  dilate( erosion_dst, dilation_dst, element );
}

void trackFilteredObject(){

    int x,y;

    Mat temp;
    mask.copyTo(temp);
    //inRange(mask,Scalar(MIN_OBJECT_AREA),Scalar(MAX_OBJECT_AREA),temp);
    curVid.copyTo(test);
    //these two vectors needed for output of findContours
    vector< vector<Point> > contours;
    vector<Vec4i> hierarchy;
    //find contours of filtered image using openCV findContours function
    findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );


    // iterate through all the top-level contours,
    // draw each connected component with its own random color
    int idx = 0;
    for( ; idx >= 0; idx = hierarchy[idx][0] )
    {
        Scalar color( rand()&0, rand()&0, rand()&255 );
        drawContours( test, contours, idx, color, CV_FILLED, 8, hierarchy );
    }


    //use moments method to find our filtered object
    double refArea = 0;
    bool objectFound = false;
    cout << hierarchy.size() << endl;
    if (hierarchy.size() > 0) {
        int numObjects = hierarchy.size();
        //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
        if(numObjects<MAX_NUM_OBJECTS){
            for (int index = 0; index >= 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
                //this is setup to get the object with the largest area so we safe a reference area each
                //iteration and compare it to the area in the next iteration. DO NOT WANT THIS!
                if(area>MIN_OBJECT_AREA){
                    x = moment.m10/area;
                    y = moment.m01/area;

                     objectFound = true;

                }else objectFound = false;
 
            }
            //let user know you found an object
            if(objectFound ==true){
                //draw object location on screen
                drawObject(x,y,test);}

        }else putText(test,"TOO MUCH NOISE! ADJUST FILTER",Point(0,50),1,2,Scalar(0,0,255),2);
    }
}

 void drawObject(int x,int y,Mat &frame){

    circle(frame,cv::Point(x,y),10,cv::Scalar(0,0,255),3);
    putText(frame,intToString(x)+ " , " + intToString(y),cv::Point(x,y+20),1,1,Scalar(0,255,0));

}

string intToString(int number){


    std::stringstream ss;
    ss << number;
    return ss.str();
}

Ideal motion/object tracking method - Problems with image noise

Hi all,

I would like to get an idea of the best way to go about tracking people with an ceiling-mounted IP camera. Ultimately, I would like to have an application that does the following:

  • show the video feed in a primary window
  • identifies moving objects then assigns them with an identifier of some kind (object1, object2, etc.)
  • in the primary window, draw a rectangle around each object and add the object ID to it as a tag
  • capture the x and y coordinates of the object or rectangle, preferably the center (it seems that this can be done using the moments() method)
  • in a second window show a binary image of blobs/people in black and everything else in white
  • on the binary image, draw a line from the previous x,y coordinates of each object to the current coordinates

EDIT: I am currently getting far too much noise in my binary image, and have not been able to limit it with the filters I'm using. I'm also unable to track and tag multiple objects. This may be the result of the example I borrowed from, in which only the object with the largest area is tagged. Unfortunately, I have not been able to fix this.

My main.cpp - full code to date:found in this Gist

#include <opencv2/opencv.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
#include "opencv2\video\background_segm.hpp"

#include <Windows.h>

using namespace cv;
using namespace std;

/// Global variables
int hist = 0;
int const histMax = 10;
int thresh = 0;
int const threshMax = 5000;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;

int lowerH=0;
int lowerS=0;
int lowerV=0;
int upperH=180;
int upperS=256;
int upperV=256;

int MIN_NUM_OBJECTS = 1;
int MAX_NUM_OBJECTS=100;
int MIN_OBJECT_AREA = 1*1;
int MAX_OBJECT_AREA = 5000*5000;

Mat curVid;         // live feed from IP Cam
Mat imgHSV;
Mat erosion_dst;
Mat dilation_dst;
Mat blur_dst;
Mat mask;           // final filtered image
Mat test;           // test for draw objects

/** Function Headers */
void setwindowSettings();
void HSV();
void Erosion( int, void* );
void Dilation( int, void* );
void Blur( int, void* );
IplImage* GetThresholdedImage(IplImage* imgHSV);
void trackFilteredObject();
void drawObject(int x,int y,Mat &frame);
string intToString(int number);


int main(int argc, char *argv[])
{
    // get cam feed and show in new window
    VideoCapture cap(0);
     if (!cap.isOpened())  // if not success, exit program
    {
         cout << "Cannot open the video file" << endl;
         return -1;
    }

    setwindowSettings();
setwindowSettings();   // create window with trackers that adjust filter settings

    // background subtraction init
    BackgroundSubtractorMOG2 bg = BackgroundSubtractorMOG2(hist,thresh,false);

    cap.read(curVid);

    Sleep(5000);

    // show images in windows
    while(1)
    {
        // show camera feed
        bool bSuccess = cap.read(curVid); // read a new frame from video
        if (!bSuccess) // if not success, break loop
        {
            cout << "Cannot read a frame from video file" << endl;
            break;
        }

        // start morph functions then draw
        HSV();
HSV();                             // apply cvtColor(curVid,imgHSV,CV_BGR2HSV);
        Erosion( 0, 0 );
);                   // choose erosion type and apply erode(imgHSV,erosion_dst,element); 
        Dilation( 0, 0 );
);                  // choose dilation type and apply dilate(erosion_dst,dilation_dst,element);

        // background subtraction
            bg(dilation_dst,mask,-1);
        imshow("mask",mask);

        // find and draw contours to curVid
Mat test
        trackFilteredObject();
         imshow("test", test);

        // escape program with keystroke
        if (waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
        {
            cout << "esc key is pressed by user" << endl;
            break; 
        }

    }
    return 0;
}


void setwindowSettings()
{
    namedWindow("Settings", CV_WINDOW_AUTOSIZE);
    resizeWindow("Settings",500,600);
    namedWindow("mask", CV_WINDOW_AUTOSIZE);
    namedWindow("test", CV_WINDOW_AUTOSIZE);

    // Create Erosion Trackbar
    createTrackbar( "EroElem", "Settings",
                    &erosion_elem, max_elem,
                    Erosion );
    createTrackbar( "EroSize", "Settings",
                    &erosion_size, max_kernel_size,
                    Erosion );

    /// Create Dilation Trackbar
    createTrackbar( "DialElem", "Settings",
                    &dilation_elem, max_elem,
                    Dilation );
    createTrackbar( "DialSize", "Settings",
                    &dilation_size, max_kernel_size,
                    Dilation );

    /// Create History Trackbar
    createTrackbar( "ImgHist", "Settings",
                    &hist, histMax );

    /// Create Threshold Trackbar
    createTrackbar( "Threshold", "Settings",
                    &thresh, threshMax );

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_NUM_OBJECTS", "Settings", 
                    &MIN_NUM_OBJECTS, 100);
    createTrackbar("MAX_NUM_OBJECTS", "Settings", 
                    &MAX_NUM_OBJECTS, 100);

    // Create NUM_OBJECTS Trackbar
    createTrackbar("MIN_OBJECT_AREA", "Settings", 
                    &MIN_OBJECT_AREA, 5000*5000);
    createTrackbar("MAX_OBJECT_AREA", "Settings", 
                    &MAX_OBJECT_AREA, 5000*5000);

}

/**  @function HSV  */
void HSV()
{
    cvtColor(curVid,imgHSV,CV_BGR2HSV);
}

/**  @function Erosion  */
void Erosion( int, void* )
{
  int erosion_type;
  if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
  else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
  else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( erosion_type,
                                       Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                       Point( erosion_size, erosion_size ) );

  /// Apply the erosion operation
  erode( imgHSV, erosion_dst, element );
}

/** @function Dilation */
void Dilation( int, void* )
{
  int dilation_type;
  if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
  else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
  else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( dilation_type,
                                       Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                                       Point( dilation_size, dilation_size ) );
  /// Apply the dilation operation
  dilate( erosion_dst, dilation_dst, element );
}

void trackFilteredObject(){

    int x,y;

    Mat temp;
    mask.copyTo(temp);
    //inRange(mask,Scalar(MIN_OBJECT_AREA),Scalar(MAX_OBJECT_AREA),temp);
    curVid.copyTo(test);
    //these two vectors needed for output of findContours
    vector< vector<Point> > contours;
    vector<Vec4i> hierarchy;
    //find contours of filtered image using openCV findContours function
    findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );


    // iterate through all the top-level contours,
    // draw each connected component with its own random color
    int idx = 0;
    for( ; idx >= 0; idx = hierarchy[idx][0] )
    {
        Scalar color( rand()&0, rand()&0, rand()&255 );
        drawContours( test, contours, idx, color, CV_FILLED, 8, hierarchy );
    }


    //use moments method to find our filtered object
    double refArea = 0;
    bool objectFound = false;
    cout << hierarchy.size() << endl;
    if (hierarchy.size() > 0) {
        int numObjects = hierarchy.size();
        //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
        if(numObjects<MAX_NUM_OBJECTS){
            for (int index = 0; index >= 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
                //this is setup to get the object with the largest area so we safe a reference area each
                //iteration and compare it to the area in the next iteration. DO NOT WANT THIS!
                if(area>MIN_OBJECT_AREA){
                    x = moment.m10/area;
                    y = moment.m01/area;

                    objectFound = true;

                }else objectFound = false;

            }
            //let user know you found an object
            if(objectFound ==true){
                //draw object location on screen
                drawObject(x,y,test);}

        }else putText(test,"TOO MUCH NOISE! ADJUST FILTER",Point(0,50),1,2,Scalar(0,0,255),2);
    }
}

void drawObject(int x,int y,Mat &frame){

    circle(frame,cv::Point(x,y),10,cv::Scalar(0,0,255),3);
    putText(frame,intToString(x)+ " , " + intToString(y),cv::Point(x,y+20),1,1,Scalar(0,255,0));

}

string intToString(int number){


    std::stringstream ss;
    ss << number;
    return ss.str();
}