Question

I am trying to pass in a HSV frame from a video to the function, but the function does not seem to do anything to it. What am I doing wrong? The function is supposed to go through each pixel, and depending on its hue range supposed to make it black or white, leaving me with a binary image. Instead it doesn't seem to affect the HSV image at all....

Thanks PS sorry for the bad code formatting, StackOverflow isn't allowing me to post the original format.

void sort (IplImage *skinmask)
{
  for (int row=0; row<=skinmask->height;row++)
  {
    uchar* pixelrow=(uchar*)(skinmask->imageData+(row*(skinmask->widthStep)));
    for (int column=0; column<=skinmask->width; column++)
    {
        if (6<pixelrow[3*column]<36)
        {
            pixelrow[3*column]=256;
            pixelrow[(3*column)+1]=256;
            pixelrow[(3*column)+2]=256;
        }
        else
        {
            pixelrow[3*column]=0;
            pixelrow[(3*column)+1]=0;
            pixelrow[(3*column)+2]=0;
        }
        column++;
    }
    row++;
  }
  cvMorphologyEx(skinmask,skinmask,NULL,NULL,CV_MOP_CLOSE,1);
}
Was it helpful?

Solution

Doing an operation like thresholding pixel-by-pixel is usually the wrong way to go about achieving this in OpenCV - there are functions that work on whole image arrays that are simpler and are already optimized for speed.

In this case try first splitting the image to separate out the H/S/V channels, then threshold on the Hue channel to get a mask (you may have to use the intersection of two masks, which you can do using a multiply or "bitwise and") - the resulting mask is your black and white image.

(I realise I've linked to the C++ documentation, but I'm sure you can find the equivalent functions in the old-style OpenCV docs)

Update

Ok, I'll try to write some code to show what I mean. I also found the function I was looking for, which is better than Threshold, it is InRangeS. This lets you put upper and lower bounds on all the channels at once, and it applies them all into your mask for you.

void HSVImageToMask(IplImage * image, cvMat * mask)
/* mask should be the same size as image, and of type CV_8UC1            */
/* e.g. cvMat * mask = cvCreateMat(image->width, image->height, CV8UC1); */
{
  double hMin = 6;
  double hMax = 36;
  double sMin = 10;  /* not sure what value you need */
  double sMax = 245; /* not sure what value you need */
  double vMin = 0;
  double vMax = 255;

  CvScalar hsvMin = cvScalar(hMin, sMin, vMin);
  CvScalar hsvMax = cvScalar(hMax, sMax, vMax);

  cvInRangeS(image, hsvMin, hsvMax, mask);
}

PS. I figured out the problem with your original code - you should be using 255 instead of 256 as your "white" value. This method is still better though :)

PPS. We didn't need them after all but for future reference:

"bitwise and":

cvAnd(const CvArr* src1, const CvArr* src2, CvArr* dst)

If you have two black and white masks, this will give you the intersection. Use cvOr to get the Union.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top