In this recipe we will show how to track objects with a specified color using the OpenCV library.
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.
We will create an application that tracks an object with a selected color.
#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"
Surface8u mImage;
vector<cv::Point2f> mCenters; vector<float> mRadius;
double mApproxEps; int mCannyThresh; ColorA mPickedColor; cv::Scalar mColorMin; cv::Scalar mColorMax;
Capture mCapture; gl::Texture mCaptureTex;
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; }
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" );
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);
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]); }
if
statement's body.}
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); }
mouseDown
event handler:void MainApp::mouseDown(MouseEvent event) { if( mImage&&mImage.getBounds().contains( event.getPos() ) ) { mPickedColor = mImage.getPixel( event.getPos() ); setTrackingHSV(); } }
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(); }
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.
3.138.123.106