Tracking colored objects in OpenCV

If you’re new to image processing, you’ll enjoy this project. What we’ll attempt to achieve in this tutorial is tracking the location of a coloured object in an image. In our case, it’ll be a yellow colored ball. Once we’re finished, we’ll have something like this:

Looks great right? So lets dive right in!

Creating the project

First, create a Win32 console application. Choose any name you like, and accept the default wizard options. You’ll get an empty project with a main function. First, add these header files to the code:

#include "cv.h"
#include "highgui.h"

Next, add the library files to the project. Go to Project > Properties > Configuration > Linker > Input and write cv.lib cxcore.lib cvaux.lib highgui.lib in Additional Dependencies.

If you have any problems with setting this up, I suggest you go through Using OpenCV with Window.

The plan of action

Before diving right into the code, its always a good idea to put a little insight into what we’re doing. Our program flow should go something like this:

  • Get an image from the camera
  • Figure out where the yellow ball is
  • Add the current position to an array of some sort

To get an image from the camera, we’ll use code from Capturing Images, that is, we’ll use inbuilt OpenCV functions that let you access camera.

For figuring out where the ball is, we’ll first threshold the image and use zero order and first order moments.

To keep a track of where the ball has been, we’ll use another image. We’ll keep drawing wherever the ball goes, and combine this image with the original frame. That way, we’ll get a “scribble” like effect. You’ll see what I mean when we implement it in code.

The dive into code

We’ll start off by writing the thresholding function:

IplImage* GetThresholdedImage(IplImage* img)
{

This function will take an image, and return a binary image (where yellow will be white and the rest will be black). Here’s a sample of what might be a scenario:

Thresholding with the Hue-Saturation-Value channels

To achieve this thresholding, we’ll be using the HSV colour space, instead of the more common RGB colour space. In HSV, each “tint” of colour is assigned a particular number (the Hue). The “amount” of colour is assigned another number (the Saturation) and the brightness of the colour is assigned another number (the Intensity or Value).

This gives us the advantage of having a single number (hue) for the yellow ball despite multiple shades of yellow (all the way from dark yellow to a bright yellow). For more information you might want to read up Colour spaces – Grayscale, RGB, HSV and Y’CrCb.

Back to the code now. Firstly, we convert the image into an HSV image:

    // Convert the image into an HSV image
    IplImage* imgHSV = cvCreateImage(cvGetSize(img), 8, 3);
    cvCvtColor(img, imgHSV, CV_BGR2HSV);

We keep the original image (img) intact, for future uses. The image is originally stored in the BGR format, so we convert BGR into HSV.

Now, create a new image that will hold the threholded image (which will be returned).

    IplImage* imgThreshed = cvCreateImage(cvGetSize(img), 8, 1);

Now we do the actual thresholding:

    cvInRangeS(imgHSV, cvScalar(20, 100, 100), cvScalar(30, 255, 255), imgThreshed);

Here, imgHSV is the reference image. And the two cvScalars represent the lower and upper bound of values that are yellowish in colour. (These bounds should work in almost all conditions. If they don’t, try experimenting with the last two values).

Consider any pixel. If all three values of that pixel (H, S and V, in that order) like within the stated ranges, imgThreshed gets a value of 255 at that corresponding pixel. This is repeated for all pixels. So what you finally get is a thresholded image.

And finally, release the temporary HSV image and return this thresholded image:

    cvReleaseImage(&imgHSV);
    return imgThreshed;
}

That finishes up our thresholding function.

Next we’ll get to the main function:

int main()
{

First, we initialize the capturing device. If we don’t get a device, we simply exit… no questions asked.

    // Initialize capturing live feed from the camera
    CvCapture* capture = 0;
    capture = cvCaptureFromCAM(0);
 
    // Couldn't get a device? Throw an error and quit
    if(!capture)
    {
        printf("Could not initialize capturing...\n");
        return -1;
    }

And then we setup windows that will display the live images:

    // The two windows we'll be using
    cvNamedWindow("video");
    cvNamedWindow("thresh");

video will display the actual output of the program (like the one you saw in the video at the top of this image). thresh will display the thresholded image, just to aid debugging if its needed.

Now we initialize the image that will hold the “scribble” data.

    // This image holds the "scribble" data...
    // the tracked positions of the ball
    IplImage* imgScribble = NULL;

We’ll keep updating imgScribble with appropriate lines. And we’ll add this image to the current frame.. and we’ll get the final output. Here’s a possible situation:

A sample of the tracking being done

I hope it makes sense.

Moving on, we create an infinite loop (we’re working on a realtime project here):

    // An infinite loop
    while(true)
    {
        // Will hold a frame captured from the camera
        IplImage* frame = 0;
        frame = cvQueryFrame(capture);

We capture a frame from the camera, and store it in frame.

Just in case, if we won’t get a frame, we simply quit.

        // If we couldn't grab a frame... quit
        if(!frame)
            break;

If you noticed, we just created imgScribble. We didn’t allocate any memory to it. The first frame would be a good place to do so. And to determine if its the first frame, we can check if imgScribble is currently NULL or not:

        // If this is the first frame, we need to initialize it
        if(imgScribble == NULL)
        {
            imgScribble = cvCreateImage(cvGetSize(frame), 8, 3);
        }

If the code reaches this far, we’re sure that a frame was captured, and the imgScribble is a valid image. So we get down to business, and generate the thresholded image using the function we wrote above:

        // Holds the yellow thresholded image (yellow = white, rest = black)
        IplImage* imgYellowThresh = GetThresholdedImage(frame);

Now imgYellowThresh holds a binary image similar to the ones shown above. Now we use mathematics based calculations to figure out the position of the yellow ball.

NOTE: I’m assuming that there will be only one yellow object on screen. If you have multiple objects, this code won’t work.

        // Calculate the moments to estimate the position of the ball
        CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
        cvMoments(imgYellowThresh, moments, 1);
 
        // The actual moment values
        double moment10 = cvGetSpatialMoment(moments, 1, 0);
        double moment01 = cvGetSpatialMoment(moments, 0, 1);
        double area = cvGetCentralMoment(moments, 0, 0);

You first allocate memory to the moments structure, and then you calculate the various moments. And then using the moments structure, you calculate the two first order moments (moment10 and moment01) and the zeroth order moment (area).

Dividing moment10 by area gives the X coordinate of the yellow ball, and similarly, dividing moment01 by area gives the Y coordinate.

Now, we need some mechanism to be able to store the previous position. We do that using static variables:

        // Holding the last and current ball positions
        static int posX = 0;
        static int posY = 0;
 
        int lastX = posX;
        int lastY = posY;
 
        posX = moment10/area;
        posY = moment01/area;

The current position of the ball is stored in posX and posY, and the previous location is stored in lastX and lastY.

We’ll just print out the current position for debugging purposes:

        // Print it out for debugging purposes
        printf("position (%d,%d)\n", posX, posY);

Now, we do some scribbling:

        // We want to draw a line only if its a valid position
        if(lastX>0 && lastY>0 && posX>0 && posY>0)
        {
            // Draw a yellow line from the previous point to the current point
            cvLine(imgScribble, cvPoint(posX, posY), cvPoint(lastX, lastY), cvScalar(0,255,255), 5);
        }

We simply create a line from the previous point to the current point, of yellow colour and a width of 5 pixels.

The if condition prevents any invalid points from being drawn on the screen. (Just try taking the yellow object out of the screen once the program is done… you’ll see what I mean).

Once all of this processing is over, we combine the scribble and the captured frame:

        // Add the scribbling image and the frame...
        cvAdd(frame, imgScribble, frame);
        cvShowImage("thresh", imgYellowThresh);
        cvShowImage("video", frame);

After displaying the images, we check if a key was pressed:

        // Wait for a keypress
        int c = cvWaitKey(10);
        if(c!=-1)
        {
            // If pressed, break out of the loop
            break;
        }

If a key was pressed, break out of the loop.

And finally, we release the thresholded image. We don’t want to accumulate multiple thresholded images…

        // Release the thresholded image+moments... we need no memory leaks.. please
        cvReleaseImage(&imgYellowThresh);
        delete moments;
    }

And finally, once the loop gets over, we release the camera so that other program can use it:

    // We're done using the camera. Other applications can now use it
    cvReleaseCapture(&capture);
    return 0;
}

Thats it! Try running the program now, it should work, just like in the video!

Tracking different colors

If you want to try some different color, you’ll have to figure out it’s hue. There are two ways to do that. First – hit and trial. Go through all possible values and you’ll hopefully end up getting a good value.

The other method requires using some photo manipulation software (MS Paint will do). Open the color selection palette. Go through the colors and you should see a text box labeled Hue.

The color selection dialog box

Go through all possible Hues to find the range of values. For example, in MS Paint, it is 0-239. But OpenCV’s hue values range from 0-179. So you need to scale any hue value you take from MS Paint (multiple the hue from MS Paint by 180/240).

Wrap up

Hope you learned something from this little project! Got any questions? Criticism? Suggestions? Leave a comment, or contact me.

Back to top

Summary

  • To track a single blob, you can use moments.
  • The tracking can be shaky, depending on the camera quality
  • The HSV colour space can be helpful when segmenting based on colour.

174 Comments

  1. SJ
    Posted July 20, 2010 at 10:51 pm | Permalink

    Thanks for the excellent walk-thru and useful comments!!

    Curious, doesn’t CvMoments *moments need to be free’d after it is used (after the area moment is calculated)??

    • Posted July 21, 2010 at 1:34 am | Permalink

      Ha! Nice catch!

      While checking again, I found yet another memory leak with imgHSV ;) Thanks for pointing out!

      Just fixed it.

  2. SJ
    Posted July 21, 2010 at 3:10 am | Permalink

    Thanks for the quick update/fix!! :)

    Two minor suggestions:
    1) In the name of simplicity and speed, don’t malloc/delete the moment data (18 doubles) as this information is needed on each pass of the while loop. Instead, just declare the moment var at the top of main() as so: CvMoments moments;

    2) Replace the constant value 8 in calls to cvCreateImage with: IPL_DEPTH_8U – Unsigned 8-bit integer (8u)
    For me, this define has more meaning and reduces the mystery of unexplained constants in code.

    • Posted July 22, 2010 at 6:09 am | Permalink

      1) Yes, that would be better
      2) Hmm… Makes sense… though just out of personal preference I use the “8″. I’ll try and use the defined constants from now on..

  3. SJ
    Posted July 22, 2010 at 4:47 am | Permalink

    I don’t know if this matters or not, but should you release the scribble image too before returning after the releasing the capture.
    cvReleaseImage( &imgScribble );

    • Posted July 22, 2010 at 6:10 am | Permalink

      It won’t really matter.. you’re ending the program… all memory allocated would be released automatically.

  4. jacob kalkan
    Posted August 1, 2010 at 11:06 pm | Permalink

    hi Utkarsh,
    first of all, i would like to thank you for that artical.
    my question is about the following code
    cvInRangeS(imgHSV, cvScalar(20, 100, 100), cvScalar(30, 255, 255), imgThreshed);
    i didn’t understand how you find the lower and upper bound of values that are yellowish in colour.
    i have not found those number in the hsi colour scale. for example, i tryed to find blue coloured object and wrote the following code
    cvInRangeS(imgHSV, cvScalar(182, 255, 255), cvScalar(255, 255, 255), imgThreshed);
    but the program did’t recognize the object.
    could you help me please?

  5. jacob kalkan
    Posted August 2, 2010 at 9:14 pm | Permalink

    forget it
    i solve ;-)

    • hirak
      Posted September 15, 2010 at 7:16 pm | Permalink

      How do you solve it ?

  6. hirak
    Posted September 15, 2010 at 7:03 pm | Permalink

    I am eager to know how do you find the upper and lower values for yellow

    • Posted September 20, 2010 at 12:20 am | Permalink

      For this demo, I used hit and trial… manually setting threshold values. There are techniques that automatically generate these values too… I think I’ll write about them here someday! Thanks for the tip!

    • Yakup Kalkan
      Posted September 23, 2010 at 4:35 pm | Permalink

      hi hirak,
      i saw your question on this tutorial and i know it is so late. so sorry!
      i am using now a program for finding upper and lower values for a colors. its name is hvs color . it is free of charge and you can find and download easily. it serves with hvs and rgb color space to find range of color’s boundries.
      regards
      yakup kalkan

      • hirak
        Posted September 23, 2010 at 10:14 pm | Permalink

        Yakup,
        Can you give me the link

  7. aeriq
    Posted September 23, 2010 at 10:00 am | Permalink

    hi Utkarsh,
    Great article and it help me a lot as i’m new to OpenCv.
    I have a question, i tried to change the scribble to rectangle shape to make it like a search window.The rectangle will follow the object.I tried several ways but failed,the rectangle appears continuously.Please help me,how to do it?

    • Posted September 23, 2010 at 11:11 am | Permalink

      The rectangle appears continuously because you’re not clearing the scribble image. Try storing the first position and then drawing one rectangle onto scribble -> display image -> clear scribble

      • aeriq
        Posted September 23, 2010 at 12:44 pm | Permalink

        i’m sorry.i didn’t get it.how to clear the scribble image?can you explain it?

        • Posted September 23, 2010 at 1:53 pm | Permalink

          You can use cvZero to set all pixels to zero.

  8. santhosh
    Posted September 28, 2010 at 5:09 pm | Permalink

    Hie utkarsh, I had gone through your colour object tracking tutorial and trying to implement it.I want to track different colours as part of my project .Plzz provide me site link or data ,how to get the RGB color ranges for other colours like pink ,blue etc.I tried google search but didnt get it.

    • Posted September 28, 2010 at 6:09 pm | Permalink

      To get the RGB or HSV values of colours, use the palette in MS Paint. Choose whatever color you want and you’ll the R,G, B, H, S, and V values there.

      • santhosh
        Posted September 28, 2010 at 6:23 pm | Permalink

        I am unable to find the values you posted in the article i.e; range for yellow colour(20 100 100) and (30 255 255) in MS paint or in photoshop.Plz help how to get these ranges for other colours also. and one more doubt.
        i modified the code in the article as below
        /////////////////////////
        IplImage* GetThresholdedImage(IplImage* img)
        {
        IplImage* imgHSV = cvCreateImage(cvGetSize(img), 8, 3);
        IplImage* imgThreshed = cvCreateImage(cvGetSize(img), 8, 1);
        cvInRangeS(imgHSV, cvScalar(255, 0, 0), cvScalar(139, 139, 0), imgThreshed);
        cvReleaseImage(&imgHSV);
        return imgThreshed;
        }
        /////////////////////////////

        and rest of the part is same as it is.
        Insted of taking in HSV color space i am finding the InRangeS in RGB color space itself.But in output i m unable to segment yellow color .,I provided yeloow color ranges (w r t to RGB space )in the function still unable to segment yellow color.plzzz tell where i did the mistake in the code.

        • santhosh
          Posted September 28, 2010 at 6:28 pm | Permalink

          I had given the values in correct order only but mistakeny wrritten above in wrong order
          i.e;
          In the program which i compiled ,supplied the arguements as below
          cvInRangeS(imgHSV, cvScalar(139, 139, 0), cvScalar(255,255, 0), imgThreshed);
          still not working…..

          • Posted October 2, 2010 at 10:57 am | Permalink

            Sent you a mail!

          • Fifty
            Posted December 29, 2010 at 8:21 pm | Permalink

            Hi, i’m playing with openCV a little bit and this tutorial is just amazing, and right now i’m trying to figure out the exact same thing, how to change those color values so they would work. I cannot make sense of those HSV values right now, can anyone help me with that?

  9. Norberto
    Posted October 2, 2010 at 4:09 am | Permalink

    Excelent!!!

  10. ferros
    Posted October 12, 2010 at 11:19 pm | Permalink

    Hi Utkarsh
    I wish to ask is it able to detect multiple similar color in the same time? Like for the example above, can the camera detect more than one yellow color in the same time? If able can you show me how? Thanks.

  11. abhi
    Posted October 13, 2010 at 10:27 am | Permalink

    If you know the the threshold for color in RGB space, its just a matter of conversion of it in HSV space : use formulas from :

    http://en.literateprograms.orgRGB_to_HSV_color_space_conversion_%28C%29#chunk%20def:compute%20hue

  12. amit
    Posted October 19, 2010 at 1:56 am | Permalink

    i wanted to know how to do rectangle detection using opencv…..

    • Posted October 19, 2010 at 10:49 am | Permalink

      Have a look at this: http:/www.aishack.in/2010/01/an-introduction-to-contours

  13. Yogi
    Posted October 21, 2010 at 7:35 am | Permalink

    hi utkars.
    what if I want to detect parts of the body, where each body part was given different colors, what is the same as the example??,
    thanks before…

  14. amit
    Posted October 23, 2010 at 2:39 am | Permalink

    hello
    thanx for your help…
    there is also a fuction square.c in sample of the opencv which helps in identifying rectangles,…but am not able to get the 4 corner points of a square…….,i.e their x and yc ordinates of 4 coener only of rectangle

    need help.

  15. Matt
    Posted October 23, 2010 at 12:11 pm | Permalink

    Hi, love the tutorial.
    Question, is there an easy way to take the x,y coordinates of the ball and maybe output them to a log file or keep them in a variable.
    Im doing a “Mouse” cam thing, (using the camera to move a mouse on the computer screen) using a red glove.

    Is this possible/easy to implement.

    Thanks

    • Posted October 23, 2010 at 1:46 pm | Permalink

      Yes, it should be possible and i think easy too. You’ll have to use some system calls to your OS to reposition the mouse. But, I think the result will not be smooth.

      • Matt
        Posted October 23, 2010 at 2:17 pm | Permalink

        Ya I’ve seen a few people do it and it was “decently” smooth.
        I was planning on using the QT library…..but I guess it’ll just be trial and error. Either way thanks a ton for posting the tutorial of this!

      • Posted October 25, 2010 at 11:23 am | Permalink

        I have already tried this and the mouse movement is not smooth.

        For Linux (Ubuntu10.04, LUCID Lynx)
        Here is the sample code for repositioning the mouse cursor.

        int main(int argc,char *argv[]) {
        Display *dpy;
        Window root_window;

        dpy = XOpenDisplay(0);
        root_window = XRootWindow(dpy, 0);
        XSelectInput(dpy, root_window, KeyReleaseMask);

        XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, 100, 100); //100,100 is the repositioned mouse position
        XFlush(dpy);
        return 0;
        }

  16. Matt
    Posted October 23, 2010 at 2:19 pm | Permalink

    Also I forgot to add, are u compiling this under Unix or Windows?

    • Posted October 25, 2010 at 7:05 am | Permalink

      I used Windows. And it should work with QT as well.

  17. Uni
    Posted October 24, 2010 at 2:51 pm | Permalink

    Again same error. Blank display on both windows (video and thresh).. I have no idea why that’s happening.

    :(

    • Anup
      Posted March 26, 2011 at 12:16 pm | Permalink

      Try this, Add
      cvWaitKey ( 33 ) ;
      jsut before the code segment that says:

      // Wait for a keypress
      int c = cvWaitKey(10);
      if(c!=-1)
      {
      // If pressed, break out of the loop
      break;
      }

  18. Rajesh
    Posted October 25, 2010 at 11:13 am | Permalink

    Jacob/Utkarsh,

    Can you please explain me how you find the lower and upper bound of values that are yellowish in colour.

    Or You can also point me where I can read about those informations.

    I tried changing the values but couldn’t get any idea.

    Thanks in advance,

    • Posted October 31, 2010 at 4:27 am | Permalink

      Try opening MS Paint. Double click on a color… you’ll see a color selection dialog box. Expand it… you’ll see the R,G,B value and the H,S,V value for any color you select.

  19. yogesh
    Posted October 25, 2010 at 11:48 pm | Permalink

    thanks Utkarsh.
    I m using ubuntu n gcc compiler to run this program. For the first time it gave some output but next time its giving an error “Corrupt JPEG data: premature end of data segment”.
    The first time also it didnt display the trace its just gave the positions on the terminal. I am new to opencv. Can you tell whts wrong?

    thanks

    • Posted October 31, 2010 at 4:20 am | Permalink

      Hmm… Are you using a camera to capture images? Or are you loading from a file? If you’re loading from a file, it’s probably because the file is corrupt.

  20. Newbie
    Posted November 1, 2010 at 4:43 pm | Permalink

    Hi Utkarsh,

    Jz want to express my appreciation and than you so much. I have been looking for this piece of code in pass few month and i have no progress yet in my research project -.-”’. Really thanks alot…

  21. JorgeSG
    Posted November 2, 2010 at 6:29 am | Permalink

    Very good the tutorial… :)

  22. amit
    Posted November 3, 2010 at 7:20 pm | Permalink

    hiiii

    gr88 tutorial……..

    i am interested in real time colour rectangle detection. i want to detect a green rectangle….
    wat i do is colour detection and then use contours to get squares…but as we know in real time detection wont give us perfect rectangles….there may be holes inside……or not perfect shape….due to which am not getting rectangle detection properly…..

    wat should i do????
    is there any method to improve images for colour detection????

    • Posted November 12, 2010 at 1:53 am | Permalink

      It depends on where you intend to use your application. You could try filling those holes, though.

  23. Janet
    Posted November 28, 2010 at 6:37 pm | Permalink

    What a nice tutorail!! And it helps me a lot on my computer vision project.
    But I got a question…..
    Why the image in the “thres” window is upside down? How can I fix it?

    Thanks a lot. : )

    • Janet
      Posted November 28, 2010 at 10:02 pm | Permalink

      I got another question this time, it is about the code below:

      cvInRangeS(imgHSV, cvScalar(0, 0, 255), cvScalar(100, 100, 255), imgThreshed);

      I found that if I changed the BGR code, for example I changed from cvScalar(0, 0, 255), cvScalar(100, 100, 255) to cvScalar(100, 100, 255), cvScalar(0, 0, 255) as I want to track red colour object. But it doesn’t work!!

      What should I do? How can I fix it?

      Thanks a lot! : )

      • Posted December 9, 2010 at 12:18 pm | Permalink

        You interchanged he parameters? For red on BGR images, the parameters should be like – cvScalar(0, 0, 240), cvScalar(10, 10, 255). You’re allowing small amounts to come through the blue and green channels, but only the very high intensities of red will come through.

    • Posted December 9, 2010 at 11:55 am | Permalink

      If the image is upside down, probably your camera is delivering images that way. You can use cvFlip to flip the image correct!

  24. chandan
    Posted December 24, 2010 at 11:45 pm | Permalink

    hi utkarsh,
    great post..i am new to computer vision and have been asked to carry out project in tracking..this helped me a lot..can u explain why the moments were taken?? ie the logic of using them here??

    • Posted December 25, 2010 at 1:34 pm | Permalink

      Well… moments are mathematical thing. They are integrals over the image. For example, first order moments are integralof(x) or integralof(y), over the entire image. Similarly a second order moment can be integralof(x^2) over the image. I think I should write an article on moments here.

  25. Jerwin
    Posted December 28, 2010 at 1:04 pm | Permalink

    how can i get the intensity value of HSV if im using color histogram method?because in my project im using color histogram method, i didnt know how to get the intensity value of HSV

    • Posted January 11, 2011 at 8:06 pm | Permalink

      The intensity? You can get the intensity at any pixel in the V channel – Value. Does that help?

  26. Sofuz
    Posted January 15, 2011 at 1:57 am | Permalink

    Hi, Utkarsh!
    Thank’s for the tutrorial! It’s really simple cool and just-in-time, because I was recently trying to do nearly the same, but for IR led (from IR remote control) and with IR filter on webcam (made from a piece of film paper) This construction filter noises very good (from lamps which lit with IR light) and only spots the light from IR led.
    Anyway, the problem was to detect coordinates of the spot. And I see you solving it using
    “spatial moments”. Please, give me an idea of this algorithm and/or reference to the literature to read further, because I’m not native English speaker and just tired of googling to figure out what it really is ><

    • Posted February 8, 2011 at 5:15 pm | Permalink

      A moment is an integral – integral(integral(I(x,y) * x^x_order * y^y_order * dx) *dy) So, moment of order 0 is the number of white pixels, A moment with x_order=1 is the sum of the x coordinates of the white pixels.

      I(x, y) is the pixel intensity at position (x,y).

  27. integral
    Posted January 15, 2011 at 2:19 am | Permalink

    Hello,
    Could you please explain what moments are or make a page about them?
    Thanks

  28. Subhash
    Posted January 21, 2011 at 8:18 am | Permalink

    hi Utkarsh,

    cvInRangeS(imgHSV, cvScalar(20, 100, 100), cvScalar(30, 255, 255), imgThreshed);

    How did you arrive at those values for lower and upper bounds of yellow, If i want to get blue, green or orange how can i get those values. I have used MSpaint HSV but it is not working.

    Could please give me the base rules for calculating lower and upper bounds of a color.

    • Posted January 25, 2011 at 4:54 am | Permalink

      The Hue in mspaint varies from 0-239. The hue in OpenCV varies from 0-179. You’ll have to scale values appropriately to get it to work.

  29. Subhash
    Posted January 22, 2011 at 10:34 am | Permalink

    I got the rules….now it is working perfect…..Thanks for the help.

  30. Posted January 25, 2011 at 5:12 am | Permalink

    I’ve added a section (towards the end) on detecting colors with different hues! Got a lot of questions about that.

  31. ferros
    Posted February 15, 2011 at 7:53 pm | Permalink

    Hi Utkarsh
    I tried out the tutorial but i faced little problems, I can’t get the background as the picture you display, what i mean is the black window, besides the object i wish to track, it also include many noise in the background, this make me difficult to track the object precisely. I tried to make the video blur but still cannot get rid of it…is it any ways?

    thanks

    • ferros
      Posted February 15, 2011 at 7:57 pm | Permalink

      Yes, still wanna ask your opinion is it any precise way to segment out the color object that i wanna track besides this? I wish to track segment out four same color markers in a video, is they any functions in openCV that can track more precisely…??

      thanks again..

      • Posted February 15, 2011 at 8:41 pm | Permalink

        Not really. Perfect segmentation is achieved only rarely (in perfect lighting, camera, etc) You can improve the quality though, by intelligent pre-processing and post-processing (morphology, blurring, etc). Or you can go with some advanced techniques like haar classifiers, maybe corners/sift/surf/etc.

  32. noveenia
    Posted February 15, 2011 at 8:58 pm | Permalink

    Go to Wikipedia to get the table of HSV values for each color.
    See the bottom of the page.
    http://en.wikipedia.org/wiki/HSL_and_HSV

  33. Giorgio Tedesco
    Posted February 15, 2011 at 10:30 pm | Permalink

    I can’t understand cvScalar() …. the values inside its could be RGB, BGR or HSV?!?!?!
    Because I’ve some problems with selection of color….

    RGB = (0-255, 0-255, 0-255)
    BGR = (0-255, 0-255, 0-255)
    HSV = (0-179, 0-???, 0-???)

    • Posted February 15, 2011 at 10:52 pm | Permalink

      Yes, it can be anything insid cvScalar. Even IplImage doesn’t care if your data is in BGR or HSV. After all, its just a sequence of bytes. It’s how you use those numbers.

      For HSV it is 0-179, 0-255, 0-255

      • Giorgio Tedesco
        Posted February 15, 2011 at 11:13 pm | Permalink

        yes, but inside InRangeS(srcHSV, cvScalarLower, cvScalarUpper, dst_Gray) I have to choice cvScalar with HSV values… right?! If I’d like to take the Red color the function could be so: InRangeS(src, cvScalar(0, 255, 70), cvScalar(10, 255, 255), dst)… right?? Because in this way I cannot see anything…

        ps: I’m working with Python binding, not C++/C

        • Posted February 15, 2011 at 11:38 pm | Permalink

          Yes, you use HSV values. Try cvScalar(0, 0, 70) to cvScalar(10,255,255). You never know if the red is fully saturated in the image or not.

  34. ferros
    Posted February 19, 2011 at 1:27 pm | Permalink

    Still cannot figure out how to fill in the BGR value in cvScalar..i tried to reduce the yellow ranges to cvScalar(20, 254, 254), cvScalar(30, 255, 255), but why it does not work? since my HUE value is still the same, which are 40 shown in MS paint. Can you show one example here on how to calculate and fill in the BGR value in cvScalar?

    millions thanks

    • Posted February 22, 2011 at 6:15 pm | Permalink

      If you want to use BGR values, your image has to be in BGR format (and not HSV). You can use the cvCvtColor command to convert between various color spaces. Does this help?

  35. Luu Tinh
    Posted March 1, 2011 at 1:26 pm | Permalink

    This’s a great tutorial. But how can we know when the object’s going far from the camera and how to do this. Please tell me, i really want to know. And could you explain some about cvmoments(). I’ve read on book but don’t understand this much because i’m not very good in English. Thank you !!!

    • Posted March 4, 2011 at 9:49 am | Permalink

      When an object is going away, you can check if its area is shrinking over a few milliseconds of time. If the area is increasing, it coming closer. A cvMoments tutorial is on the todo list! Should be up soon hopefully.

  36. Richard
    Posted March 7, 2011 at 5:51 pm | Permalink

    Hi Utkarsh,

    I am trying to complete a project where by the the balls on a pool table can be found as well is the cue.
    I think what you have done may well be helpful for me when finding the balls on the table but I have two inquires that you may be able to help me with.

    Could I use the HSV transform for multiple colours e.g. red, yellow, black and white?

    And if I was to use the HSV transform to find the balls how would you recommend I go about trying to find the cue when in the camera’s view?

    Thanks,

    Ric.

    • Posted March 9, 2011 at 1:51 pm | Permalink

      Yup its possible. Just figure out the right Hue values for each color. For black and white, use the V channel – if V > say 225it’s white and if V < 25 its black. Moments won’t work if you have two balls of the same color. So use contours or labelling instead.

  37. Sreevathsan
    Posted March 8, 2011 at 11:25 pm | Permalink

    hi dude,
    i want to track human eye ball.
    I am successful in detecting the eye region using Adaboost Algorithm.
    Is it possible to check whether the eyes are open or closed using this method.
    Can u suggest how can i proceed in my task.
    Thanks.

  38. antony
    Posted March 13, 2011 at 4:56 am | Permalink

    hi,
    its really gud…tank u very much

  39. sks
    Posted March 19, 2011 at 11:16 am | Permalink

    hiii utkarsh,
    ur tutorial z really great…it helpd me realy wel in ma project..i m tryng to change the line color whenever i want using keyboard handler..but it is showing d othr color nly when the key is pressed…cn i change this new color as default when i pres the key???pls help me wid ds..

    • Posted March 21, 2011 at 9:46 am | Permalink

      Well, make a global variable of type CvScalar. Initialize it to say CV_RGB(255,255,0). When a ’1′ is pressed, set it to CV_RGB(255,0,0). When ’2′ is pressed, set it to CV_RGB(255,255,0). Use this variable to color your line.

  40. Objectus Tracktocolorus
    Posted March 19, 2011 at 9:17 pm | Permalink

    Hi Utkarsh,
    I want to make up an circle around this ball,instead of your ltracking line, when detected (also while tracking) from cam . Besides, I want to track more than one different colored balls in the same time. What should i do? How can I implement this?

  41. KaiL
    Posted March 22, 2011 at 10:03 am | Permalink

    Hi
    Could you give me some tip on how I can do this?
    I am trying to filter out everything except the point that I am detecting.

  42. sajad
    Posted March 23, 2011 at 7:34 pm | Permalink

    hello
    I apologize becuse i can not write englesh good
    i do not understand this code
    can you explain me or introduce a link
    what is a structure of cvGetSpatialMoment?
    CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
    cvMoments(imgYellowThresh, moments, 1);
    double moment10 = cvGetSpatialMoment(moments, 1, 0);
    double moment01 = cvGetSpatialMoment(moments, 0, 1);
    double area = cvGetCentralMoment(moments, 0, 0);

  43. Fred
    Posted March 23, 2011 at 8:39 pm | Permalink

    Hi Utkarsh,

    First thanks for all the help you provide here! Fighting to try to track a red color…. I did try with that values but seems not ok : cvInRangeS(imgHSV, cvScalar(220, 120, 100), cvScalar(240, 240, 240), imgThreshed);

    Fred

    • Posted April 29, 2011 at 9:48 pm | Permalink

      The hue range from 0-180 and not 0-255. So I think you’ll have to change your hue numbers.

  44. Debyani
    Posted March 23, 2011 at 11:24 pm | Permalink

    Hie Utkarsh. Thanks a lot for this tutorial.It helped me a lot to complete my final year project i.e “Target coordinate identification in a video”.

    • Posted April 29, 2011 at 9:48 pm | Permalink

      Hi! It would be awesome if you can send me a video or some kind of information about it!

  45. KaiL
    Posted March 25, 2011 at 10:25 am | Permalink

    Something like Face detection . and when a face is detected , it gives out a square box and what I want is , i want to filter everything outside the box. sorry for my poor english

    • Posted March 31, 2011 at 10:24 am | Permalink

      You could just make everything outside the box, black.

  46. bryan
    Posted April 8, 2011 at 6:47 am | Permalink

    do you add the main function under the int _tmain(int argc, _TCHAR* argv[]) function?

    • Posted April 29, 2011 at 8:05 pm | Permalink

      Replace the _tmain function with the standard main function. It doesn’t really make a difference.

  47. Stehan
    Posted April 16, 2011 at 8:44 pm | Permalink

    Hi Utkarsh,

    I’m new to openCV (using v2.1 + VS2008) but I managed to get your project to work. Great stuff! I’d like to add two things:

    when I compile the project I get two warnings of the same type:
    warning C4244: ‘=’ : conversion from ‘double’ to ‘int’, possible loss of data

    this doesn’t make the program crash though and maybe it’s due to something I made wrong?

    another thing is that I’m currently working on an AviSynth script and for this purpose I need the output coordinates. So I’ve added a few lines to the project to get those coordinates in a text file. Now, if the object is ”out of reach” or outside the frame the returned ‘coordinates’ are:

    -2147483648 -2147483648

    how does this happen and could it be changed (inside your project) to

    0 0

    so I won’t need to replace them manually in the text file?

    Anyway, this is exactly what I needed for my AviSynth script.

    Cheers
    Stephan

  48. Lauren
    Posted April 18, 2011 at 9:50 pm | Permalink

    Hi Utkarsh,

    Your tutorial has been extremely helpful in my understanding of thresholding. I have been trying to get your code to work on a Mac platform without success. Do you have any suggestions in translating Windows code to Mac?

    Thank you!

    • Posted April 29, 2011 at 9:21 pm | Permalink

      I think it should work without problems. Are you sure your OpenCV installation works?

  49. joshua
    Posted April 19, 2011 at 3:09 am | Permalink

    Hi Utkarsh,

    This is an excellent tutorial– it has helped me a lot! I am sooo close to completing my goal, and was wondering if you could give me some input!

    I am definitely new at OpenCV– I have only used it for a few days now, and I am trying to use it for a school project. Your website has helped me solve the first 3/4 of it!

    I am trying to detect how much percentage of a color is in a particular frame. Specifically, I am trying to find how much white there is. I would like to have my program spit out a percentage, say 10 percent, or 37.65 percent of the picture contains white pixels.

    In order to do this, I have thought about looping through each of the pixels of the picture and if it is white, wPix++. Since this time, I have tried the code found here: http://stackoverflow.com/questions/1614912/opencv-grid-area

    This is not working, and my suspicion is because pixels in this type of image can be anywhere between 0 and 255 and unless it is exactly 255, it won’t recognize it as completely white.

    However, this is the type of code for which I am looking. From what I understand, in a binary file, the pixel values are either 0 or 1. Therefore, in theory, I *think* I should be able to use a similar code and open a binary image (black and white) and test if the pixel is 0 or 1 and then increment the count based on this. However, this is not working either!!

    do you have any tips? how can i do this? nothing i try works…

  50. Stephan
    Posted April 20, 2011 at 9:23 pm | Permalink

    Hi Utkarsh,

    here’s a video I made with the help of your program:

    http://www.youtube.com/watch?v=2jJw7-Siles

    Cheers
    Stephan

2 Trackbacks

  1. By Fun with OpenCV | Exploration in 3D Interfaces on February 23, 2012 at 10:41 pm

    [...] some sample code from AI Shack I was able to get a prototype working for tracking two colors.  In this case a red and yellow. [...]

  2. [...] .. (as in yellow actually) part of the image. You can find a tutorial explaining all this and more HERE.Written by a senior from my college … really great tutorial … must [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">