I would like to build an application that detects blobs of a certain colour. For example, something that finds all blue spots in the image. I was looking at the OpenCV addon and noticed it does blob detection, but is there a way to specify which colour to look for?
I was thinking of something like grabbing the image, clearing the RED and GREEN channels, and I guess what’s left is the BLUE. Does that make sense? Is there a function that already does this in OpenCV or should I implement it?
the code jesus points out is a great starting point –
in addition, just wanted to mention that one of the next additions to the opencv addon will be ofCvColorImage convert back and forth to HSV / RGB. Color tracking works very well in HSV, and it means that you can say for example you interested in a hue between certain range, saturation of a certain range and it will usually help you get a wide range of a certain color, for example, the green of a green-screen including the shadows of someone present.
if anyone wants to experiment, you can add this code to ofCvColorImage (we will add it in the next revision of the cv addon):
in the "h"
void convertToHSV();
in the cpp:
void ofCvColorImage::convertToHSV(){
cvCvtColor( cvImage, cvImageTemp, CV_RGB2HSV );
swapTemp();
}
and then call it in order to convert the image to HSV – then, you could process the hue / saturation and brightness channels in order to label pixels as being of the desired color or not.
I saw jonkirk’s example right after posting. But I was thinking that maybe this was out-of-the-box functionality with OpenCV and that it hadn’t been implemented yet in the addon version. Kind of like trackColor(…) in the JMyron Processing library.
If that is the case, would anyone have a simple example on which functions to call?
About using HSV, does that convertToHSV() function mean that instead of having the pixels array hold the values BGRBGRBGRBGR… for all the pixels, it will hold HSVHSVHSVHSV…?
It also will be in the same range (0-255) so it is pretty simple to extract the data.
The only tricky thing for tracking a range of color is that the hue is circular so a hue of 20 is closer to a hue of 250 than a hue of 40.
If you are looking for a green color ( ~ 90.0 ) it is not so much a problem because the green is close to the center of the spectrum but the red range is kind of split between the bottom and top values of hue so you have to then check the other end as well.
I am slowly getting there but I am having some problems detecting the colour to track; it’s kind of doing the opposite than what it should and I’m not sure why…
Using that convertToHSV() function, are the pixel values stored as HSVHSVHSV… or VSHVSHVSH… ?
Aren’t the RGB pixel values stored as BGRBGRBGR… ? Does that mean that in the convertToHSV() function, the 3rd argument should be CV_BGR2HSV instead of CV_RGB2HSV ?
The way the hue works is that I specify the exact hue I want to track like 0.35 for example and then a threshold width around that point say of 0.2 which means then that any value between 0.25 and 0.45 (0.2 in total) is considered good enough.
Here I am getting the pixels back as HSVHSVHSV in a range of 0-255 and then filling a grayscale image with either white pixels or black pixels. The white pixels represent pixels that match the hue sat and val criteria.
If you have control over hue, hueThresh, sat and val the code bellow should work for you.
hsvFrame.rgbToHsv();
int totalPixels = W*H*3;
unsigned char * pix = hsvFrame.getPixels();
unsigned char * pre = new unsigned char[W*H*3];
//set these values your self
float h = hue * 255;
float ht = hueThresh * 255;
float s = sat * 255;
float v = value * 255;
//here we figure out what is the max allowed hue
//and the minimum allowed hue. because hue is
//continious we have to make sure we handle what happens
//if hueMax goes over 255
//or hueMin goes less than 0
float hueMax = h + ht*0.5;
float hueMin = h - ht*0.5;
int k = 0;
for(int i = 0; i < totalPixels-3; i+=3){
float pixHue = pix[i];
if( pix[i+1] >= s && pix[i+2] >= v){
//we do this to check the cases when the
//hue min could have wrapped
//or the hue max could have wrapped
//also if saturation is zero
//then hue doesn't matter hence (s == 0)
if( (s == 0) || (pixHue >= hueMin && pixHue <= hueMax) ||
(pixHue -255 >= hueMin && pixHue <= hueMax) ||
(pixHue >= hueMin && pixHue +255 <= hueMax) ){
//we have a white pixel
pre[k] = 255;
}
else pre[k] = 0;
}else pre[k] = 0;
k++;
}
Once you are finished with pre don’t forgot to delete it with:
I actually had something very similar but it was a little late last night and I was setting what should be white to 0 and what should be black to 255. Needed sleep…
I think there is a problem with your code in the cases where the hue overflows/underflows. Try tracing your code with h=254, ht=40, pixHue=10 and you’ll get a black pixel even though it should be white.
Here is a corrected version:
hsvFrame.rgbToHsv();
int totalPixels = W*H*3;
unsigned char * pix = hsvFrame.getPixels();
unsigned char * pre = new unsigned char[W*H*3];
//set these values your self
float h = hue * 255;
float ht = hueThresh * 255;
float s = sat * 255;
float v = value * 255;
//here we figure out what is the max allowed hue
//and the minimum allowed hue. because hue is
//continious we have to make sure we handle what happens
//if hueMax goes over 255
//or hueMin goes less than 0
float hueMax = h + ht*0.5;
float hueMin = h - ht*0.5;
int k = 0;
for(int i = 0; i < totalPixels-3; i+=3){
float pixHue = pix[i];
if( pix[i+1] >= s && pix[i+2] >= v){
//we do this to check the cases when the
//hue min could have wrapped
//or the hue max could have wrapped
//also if saturation is zero
//then hue doesn't matter hence (s == 0)
if( (s == 0) || (pixHue >= hueMin && pixHue <= hueMax) ||
(pixHue -255 >= hueMin && pixHue -255 <= hueMax) ||
(pixHue +255 >= hueMin && pixHue +255 <= hueMax) ){
//we have a white pixel
pre[k] = 255;
}
else pre[k] = 0;
}else pre[k] = 0;
k++;
}
I would like to build an application that detects blobs of a certain colour. For example, something that finds all blue spots in the image. I was looking at the OpenCV addon and noticed it does blob detection, but is there a way to specify which colour to look for?
I was thinking of something like grabbing the image, clearing the RED and GREEN channels, and I guess what’s left is the BLUE. Does that make sense? Is there a function that already does this in OpenCV or should I implement it?
Thanks.[/quote]
In OpenCV you usually pick a sample of the color, then you calculate an image histogram of those and finally backproject (convolute) the histogram over the image you want to process. After that you get a grayscale image, the whiter the most likely your color is there. But i cannot find those OpenCV functions in OF yet. It is not difficult to port, though, you may try or wait until i need them and i’ll port them.
Hey prisonerjohn do you happen to have any source code for detecting blobs based on a color. This is exactly what I am looking to do. If you could share I would be so thankful!
here’s an (0.06) example that allows you to click on a pixel to track and set the min / max saturation / hue / value for the color tracker. it works pretty well: