Tracking an object based on color

In this recipe we will show how to track objects with a specified color using the OpenCV library.

Getting ready

In this recipe we will use OpenCV, so please refer to the Integrating with OpenCV recipe from Chapter 3, Using Image Processing Techniques. We will also need InterfaceGl which is covered in the Setting up a GUI for parameter tweaking recipe from Chapter 2, Preparing for Development.

How to do it…

We will create an application that tracks an object with a selected color.

  1. Include the necessary header files:
    #include "cinder/gl/gl.h"
    #include "cinder/gl/Texture.h"
    #include "cinder/Surface.h"
    #include "cinder/ImageIo.h"
    #include "cinder/Capture.h"
    #include "cinder/params/Params.h"
    #include  "CinderOpenCV.h"
  2. Add members to store the original and processed frame:
    Surface8u   mImage;
  3. Add members to store the tracked object's coordinates:
    vector<cv::Point2f> mCenters;
    vector<float> mRadius;
  4. Add members to store the parameters that will be passed to the tracking algorithms:
    double mApproxEps;
    int mCannyThresh;
    
    ColorA      mPickedColor;
    cv::Scalar  mColorMin;
    cv::Scalar  mColorMax;
  5. Add members to handle the capturing device and frame texture:
    Capture     mCapture;
    gl::Texture mCaptureTex;
  6. In the setup method we will set the window dimensions and initialize capturing device:
    setWindowSize(640, 480);
    
    try {
      mCapture = Capture( 640, 480 );
      mCapture.start();
    }
    catch( ... ) {
      console() <<"Failed to initialize capture"<<std::endl;
    }
  7. In the setup method we have to initialize variables and setup the GUI for a preview of the tracked color value:
    mApproxEps = 1.0;
    mCannyThresh = 200;
    
    mPickedColor = Color8u(255, 0, 0);
    setTrackingHSV();
    
    // Setup the parameters
    mParams = params::InterfaceGl( "Parameters", Vec2i( 200, 150 ) );
    mParams.addParam( "Picked Color", &mPickedColor, "readonly=1" );
  8. In the update method, check if there is any new frame to process and convert it to cv::Mat, which is necessary for further OpenCV operations:
    if( mCapture&&mCapture.checkNewFrame() ) {
      mImage = mCapture.getSurface();
      mCaptureTex = gl::Texture( mImage );
    
      cv::Mat inputMat( toOcv( mImage) );
      cv::resize(inputMat, inputMat, cv::Size(320, 240) );
    
      cv::Mat inputHSVMat, frameTresh;
      cv::cvtColor(inputMat, inputHSVMat, CV_BGR2HSV);
  9. Process the captured frame:
      cv::inRange(inputHSVMat, mColorMin, mColorMax, frameTresh);
    
      cv::medianBlur(frameTresh, frameTresh, 7);
    
      cv::Mat cannyMat;
      cv::Canny(frameTresh, cannyMat, mCannyThresh, mCannyThresh*2.f, 3 );
     vector< std::vector<cv::Point> >  contours;
     cv::findContours(cannyMat, contours, CV_RETR_LIST, 
      CV_CHAIN_APPROX_SIMPLE);
     mCenters = vector<cv::Point2f>(contours.size());
     mRadius = vector<float>(contours.size());
     for( int i = 0; i < contours.size(); i++ ) {
      std::vector<cv::Point> approxCurve;
      cv::approxPolyDP(contours[i], approxCurve, 
       mApproxEps, true);
      cv::minEnclosingCircle(approxCurve, mCenters[i], 
       mRadius[i]);
     }
  10. Close the if statement's body.
    }
  11. Implement the method setTrackingHSV, which sets color's values for tracking:
    void MainApp::setTrackingHSV()
    {
    void MainApp::setTrackingHSV() {
     Color8u col = Color( mPickedColor );
     Vec3f colorHSV = col.get(CM_HSV);
     colorHSV.x *= 179;
     colorHSV.y *= 255;
     colorHSV.z *= 255;
     mColorMin = cv::Scalar(colorHSV.x-5, colorHSV.y -50, 
      colorHSV.z-50);
     mColorMax = cv::Scalar(colorHSV.x+5, 255, 255);
    }
  12. Implement the mouseDown event handler:
    void MainApp::mouseDown(MouseEvent event) {
     if( mImage&&mImage.getBounds().contains( event.getPos() ) ) {
      mPickedColor = mImage.getPixel( event.getPos() );
      setTrackingHSV();
     } 
    }
  13. Implement the draw method as follows:
    void MainApp::draw()
    {
     gl::clear( Color( 0.1f, 0.1f, 0.1f ) );
     gl::color(Color::white());
     if(mCaptureTex) {
      gl::draw(mCaptureTex);
      gl::color(Color::white());
      for( int i = 0; i <mCenters.size(); i++ )
      {
       Vec2f center = fromOcv(mCenters[i])*2.f;
       gl::begin(GL_POINTS);
       gl::vertex( center );
       gl::end();
       gl::drawStrokedCircle(center, mRadius[i]*2.f );
      }
     }
     params::InterfaceGl::draw();
    }

How it works…

By preparing the captured frame for processing we are converting it into a hue, saturation, and value (HSV) color space description method, which will be very useful in this case. Those are the properties describing the color in the HSV color space in a more intuitive way for color tracking. We can set a fixed hue value for detection, while saturation and value can vary with in a specified range. This can eliminate a noise caused by constantly changing light in the camera view. Take a look at the first step of the frame image processing; we are using the cv::inRange function to get a mask of pixels that fits our tracking color range. The range of the tracking colors is calculated from the color value picked by clicking inside the window, which is implemented inside the mouseDown handler and the setTrackingHSV method.

As you can see inside setTrackingHSV, we are calculating mColorMin and mColorMax by simply widening the range. You may have to adjust these calculations depending on your camera noise and lighting conditions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.179.85