Friday, 13 May 2011

Color and shape based tracking of a ball

In image processing, there are various color models like RGB, HSV, HSI, CMYK. For image proccessing regaurding color detection, RGB and HSV models are commonly used.

The HSV( Hue Saturation Value ) color model solves our purpose of color detection best. In RGB, to define a color, the ranges of red, blue and green must be defined, but in HSV model, for a color we need to define only the value of Hue, which is defined as the color descriptor, or the parameter for wavelength describing a particular color. The saturation is defined as the prominence of hue, and value is a parameter dependent upon the lighting conditions.

There are ranges of Hue values fixed for different colors.These values can be seen on
http://mkweb.bcgsc.ca/color_summarizer/?faq

We would be needing a software colorpic to check the hue saturation and value from images. It can be downloaded from
http://www.iconico.com/colorpic/



To detect a color ball, we need to go through color and then shape detection  

STEP1: Capture a frame from the camera

CvCapture* capture = cvCaptureFromCAM( 0 ); //0 is device id
 IplImage* frame = cvQueryFrame( capture ); //frame is captured

cvQueryFrame() is used to capture a frame from camera of device id specied in the object capture.

STEP2: Convert the color model of image from RGB to HSV

 cvCvtColor(frame, hsv_frame, CV_BGR2HSV);
It coverts the color model of the RGB image frame to HSV and stores it in hsv_frame without affecting frame.the format of this command is:

 cvCvtColor(imginit, imgfinal, color space conversion);

where,        imginit=image whose color space is to be changed
                  imgfinal=modified color space image
                  color space conversion =CV_BGR2HSV //for rgb to hsv
                                                      =CV_HSV2BGR//for hsv to rgb


STEP3: Specify the color to be detected by asigning the minimum and maximum values for hue saturation and value

 CvScalar hsv_min = cvScalar(35, 80, 170, 0);             //min value of h, s and v
 CvScalar hsv_max =  cvScalar(55, 130, 255, 0);         //max value of h, s and v

This is in accordance with the color to be detected. It is also highly dependent on lighting conditions. The values of Hue Saturation and Value can be checked by using the software colorpic

STEP4: Color detection

cvInRangeS(hsv_frame, hsv_min, hsv_max, thresholded);
This command checks for the regions in the image having the values of h, s and v within the permissible range, i.e. between hsv_min and hsv_max, and the binary image thus formed is stored in thresholded.

STEP5: Shape detection i.e. detection of circle

cvSmooth( thresholded, thresholded, CV_GAUSSIAN, 11, 11 );   //smoothing of image

This command is used to smooth a image using gaussian smoothing using a square of size 11x11. The area can range from 0x0 to 11x11, depending on whether the smoothing we require is used to detect small objects or not. The greater the area the better the detection of large objects.

         CvSeq* circles = cvHoughCircles(thresholded, storage, CV_HOUGH_GRADIENT, 2,thresholded->height/6, 100, 50, 10, 400);

This command is used to detect circle shape in the binary image thresholded. The format of the command is:

cvHoughCircles(IntPtr image,IntPtr circleStorage,HOUGH_TYPE method,double dp,double minDist,double param1,double param2,int minRadius,int maxRadius)

STEP6: Draw a circle of desired color around the detected circle

cvCircle(IntPtr img,Point center,int radius,MCvScalar color,int thickness,LINE_TYPE lineType,int shift)

It is used to draw a circle of radius r at centre x,y.


Now, you are ready to detect a color ball. :)


The complete code is:

#include <cvaux.h>
#include <highgui.h>
#include <cxcore.h>
#include <stdio.h>
#include<iostream>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
using namespace std;
int main(int argc, char* argv[])
 {
IplImage* frame = NULL;

     CvCapture* capture = cvCaptureFromCAM( 0 );

     if( !capture )
     {
             fprintf( stderr, "ERROR: capture is NULL \n" );
             getchar();
             return -1;
     }

    cvNamedWindow("video", CV_WINDOW_AUTOSIZE);
    cvNamedWindow("colordetect", CV_WINDOW_AUTOSIZE);

    CvScalar hsv_min = cvScalar(35, 80, 170, 0);
    CvScalar hsv_max =  cvScalar(55, 130, 255, 0);

    frame = cvQueryFrame( capture );
    CvSize size = cvGetSize(frame);

     IplImage*  hsv_frame    = cvCreateImage(size, IPL_DEPTH_8U, 3);

     IplImage*  thresholded   = cvCreateImage(size, IPL_DEPTH_8U, 1);


 while(1)
     {

        //capture image from cam
         frame = cvQueryFrame( capture );

         if( !frame )
         {
                 fprintf( stderr, "ERROR: frame is null...\n" );
                 getchar();
                 break;
         }

        //conversion of color model from rgb to hsv
        cvCvtColor(frame, hsv_frame, CV_BGR2HSV);

        //color detection
        cvInRangeS(hsv_frame, hsv_min, hsv_max, thresholded);

         // Memory for hough circles
         CvMemStorage* storage = cvCreateMemStorage(0);

        //Smoothing of image as cvHoughCircles works better on smoothed image
         cvSmooth( thresholded, thresholded, CV_GAUSSIAN, 11, 11 );

        //shape detection-circle shape
         CvSeq* circles = cvHoughCircles(thresholded, storage, CV_HOUGH_GRADIENT, 2,thresholded->height/6, 100, 50, 10, 400);

         cout<<"no. of circles="<<circles->total;

         //drawing circle around the detected circle
         for (int i = 0; i < circles->total; i++)
         {
             float* p = (float*)cvGetSeqElem( circles, i );
             cout<<"x= "<<p[0]<<"y= "<<p[1]<<"r= "<<p[2]<<endl;
             cvCircle( frame, cvPoint(cvRound(p[0]),cvRound(p[1])),cvRound(p[2]), CV_RGB(255,0,0), 3, 8, 0 );
         }

    //display image showing ball detected
 cvShowImage("video", frame);

    //color detected image
    cvShowImage("colordetect", thresholded);

    //release memry storage
    cvReleaseMemStorage(&storage);

    //wait for 10 sec and continue or break if "ESC"is pressed
    if( (cvWaitKey(10) & 255) == 27 ) break;
     }
      //release capture
      cvReleaseCapture( &capture );

      cvDestroyWindow( "mywindow" );
      return 0;
    }



No comments:

Post a Comment