3

I have the following BGR image (a car's front), I want to recognize its color

enter image description here

I converted it to HSV (I know imshow() doesn't understand the HSV and will print it as BGR) enter image description here

1: Now, I want to get the hue value and know in which range it lies to recognize the color

  • how to calculate the number or value of hue?
  • how to specify ranges? using scalar method gives me bgr ranges

Code

int main()
{
    Mat image;
    image = imread("carcolor.png", CV_LOAD_IMAGE_COLOR);

    if (!image.data)
    {
        cout << "Could not open or find the image" << std::endl;
        return -1;
    }

    // Create a new matrix to hold the HSV image
    Mat HSV;

    // convert RGB image to HSV
    cvtColor(image, HSV, CV_BGR2HSV);

    namedWindow("Display window", CV_WINDOW_AUTOSIZE);
    imshow("Display window", image);

    namedWindow("Result window", CV_WINDOW_AUTOSIZE);
    imshow("Result window", HSV);


    vector<Mat> hsv_planes;
    split(HSV, hsv_planes);
    Mat h = hsv_planes[0]; // H channel
    Mat s = hsv_planes[1]; // S channel
    Mat v = hsv_planes[2]; // V channel

    namedWindow("hue", CV_WINDOW_AUTOSIZE);
    imshow("hue", h);
    namedWindow("saturation", CV_WINDOW_AUTOSIZE);
    imshow("saturation", s);
    namedWindow("value", CV_WINDOW_AUTOSIZE);
    imshow("value", v);



    //// red color range
    Scalar hsv_l(170, 150, 150);
    Scalar hsv_h(180, 255, 255);
    Mat bw;
    inRange(HSV, hsv_l, hsv_h, bw);
    imshow("Specific Colour", bw);
    ////

    // hue value

    //define ranges

    waitKey(0);
    return 0;
}
Mike Szyndel
  • 10,461
  • 10
  • 47
  • 63
Maram
  • 37
  • 1
  • 1
  • 6
  • show an image of the "specific color" window, too please. Your inRange code looks ok, but maybe the ranges aren't right. Red has 2 hue ranges, 0 to x and 180-x to 180 – Micka Feb 20 '16 at 11:43
  • @Micka the inRange doesn't detect the whole red color in the original bgr .. it only detects the red touch in the HSV resultant image – Maram Feb 20 '16 at 12:30
  • as I said, the red color range is split becuase of circularity in the hue color space. See my answer, you need two ranges to exrract the whole red color range. Alternatively you could shift the whole hue channel by using `hueVal = (hueVal+50)%180` for each pixel, then red color will be centered around hue value 50. – Micka Feb 20 '16 at 13:18

1 Answers1

2

Hue is a circular range and red is exactly at the start/end of that circle, so red hue value is covered by two different ranges: [0 .. n] and [360-n .. 360]. As you used in your code, openCV additionally halfs the whole range to [0 .. 180] because of byte coverage.

So in addition to Scalar hsv_l(170, 150, 150); and Scalar hsv_h(180, 255,255); you'll need a second range.

Full code to find the range could be:

//// red color rangeS
int redRange = 10;

Scalar hsv_upper_l(180-n, 150, 150);
Scalar hsv_upper_h(180, 255, 255);
Mat red_hue_upper;
inRange(HSV, hsv_upper_l, hsv_upper_h, red_hue_upper);

Scalar hsv_lower_l(0, 150, 150);
Scalar hsv_lower_h(0+n, 255, 255);
Mat red_hue_lower;
inRange(HSV, hsv_lower_l, hsv_lower_h, red_hue_lower);

cv::Mat whole_red_hue = red_hue_lower | red_hue_upper;

imshow("Specific Colour", whole_red_hue);

Producing from this input that output:

enter image description here enter image description here

For different colors it is easier (since they aren't placed around circle's start/end):

int hueCenter = ...; // any hue value of the color
int hueRange = 10; // or any other range
cv::Mat hueMask;
inRange(HSV, Scalar(hueCenter-hueRange, 150, 150), Scalar(hueCenter+hueRange, 255, 255), hueMask);

hope this helps.

Micka
  • 19,585
  • 4
  • 56
  • 74
  • if you want to mask-out more of the white/black areas you'll have to increase the lower saturation range bound to 200 and the lower value range bound to 230. – Micka Feb 20 '16 at 13:15
  • what is "n" in your code? Sorry about the newbie question, I am very new to opencv. I too want to detect color in an image. – harsh May 11 '18 at 00:18