Ask Your Question

How to set inRange() bounds properly when converting color with CV_BGR2HLS ?

asked 2016-04-23 18:27:41 -0600

Major Squirrel gravatar image

updated 2020-10-29 17:32:59 -0600

Good evening,

I'm trying to use inRange() function, in line with cvtColor() but I'm a little bit confused as to the type of inRange() bounds.

I am converting an image from BGR to HLS (which, I don't know why, isn't HSL...), that is :

cv::cvtColor(original, converted, CV_BGR2HLS)

I would like to extract the white/beige pixels from the converted image. My questions are the following:

  • Why it is BGR2HLS and not BGR2HSL, which would be more obvious ?
  • What values should I put into my cv::Scalar bounds to get these white/beige pixels ? (in which order more precisely : Hue, Saturation and Lightness or Hue, Lightness and Saturation ?)

I am confused about the second question, because when I adjust the trackbars' values this way :

cv::Scalar(0, 115, 0) // lower bound
cv::Scalar(180, 255, 255) // upper bound

I can get white and beige pixels, but these values ​​do not seem to match the HSL range at all.

Thank you for your time !

EDIT: I changed the wording of the question and added some code. The code below is a little helper for me, to adjust HSL bounds.

EDIT2: I am an oyster, I forgot to change the title.

/*                  Taken from stackoverflow */
std::string         typeToString(int type) {
    std::string     ret;
    uchar           depth = type & CV_MAT_DEPTH_MASK;
    uchar           chans = 1 + (type >> CV_CN_SHIFT);

    ret = "CV_";
    switch (depth) {
        case CV_8U:  ret += "8U"; break;
        case CV_8S:  ret += "8S"; break;
        case CV_16U: ret += "16U"; break;
        case CV_16S: ret += "16S"; break;
        case CV_32S: ret += "32S"; break;
        case CV_32F: ret += "32F"; break;
        case CV_64F: ret += "64F"; break;
        default:     ret += "User"; break;
    ret += "C";
    ret += (chans + '0');
    return (ret);

int                 launchHelper() {
    cv::Mat         colorConvertedFrame, firstFilterFrame;
    int             minH = 0, minS = 0, minL = 0;
    int             maxH = 180, maxS = 255, maxL = 255;
    cv::Scalar      minBound, maxBound;

    colorConvertedFrame = cv::imread(IMAGE_PATH);
    if (colorConvertedFrame.empty()) {
        std::cerr << "Frame is empty." << std::endl;
        return (-1);
    std::cout << "Your image has type " << typeToString(colorConvertedFrame.type()) << " !" << std::endl;
    std::cout << "Your image has " << colorConvertedFrame.channels() << " channel(s) !" << std::endl;
    cv::namedWindow("Frame with converted color");
    cv::namedWindow("First filter");
    cv::namedWindow("Color panel");
    cv::createTrackbar("Min H", "Color panel", &minH, 180);
    cv::createTrackbar("Max H", "Color panel", &maxH, 180);
    cv::createTrackbar("Min S", "Color panel", &minS, 255);
    cv::createTrackbar("Max S", "Color panel", &maxS, 255);
    cv::createTrackbar("Min L", "Color panel", &minL, 255);
    cv::createTrackbar("Max L", "Color panel", &maxL, 255);
    while (cv::waitKey(1) != 27) {
        minBound = cv::Scalar(minH, minS, minL);
        maxBound = cv::Scalar(maxH, maxS, maxL);
        cv::inRange(colorConvertedFrame, minBound, maxBound, firstFilterFrame);
        cv::imshow("Frame with converted color", colorConvertedFrame);
        cv::imshow("First filter", firstFilterFrame);
    return (0);

int                 main(int ac, char **av) {
    return (launchHelper());
edit retag flag offensive close merge delete

1 answer

Sort by » oldest newest most voted

answered 2016-04-26 02:37:53 -0600

Major Squirrel gravatar image

Well, I'm so dumb.

Converting a frame from one palette to another one and using cv::inRange are two things completely different. I thought there was a link between the method used to convert the frame and the bounds of inRange() function, but there are absolutely not.

I hope that my answer will help some people that are confused using those functions together.

Converting a frame from one palette to another one is a thing. Whether you use a particular method, the result is the same : the pixels will be color-converted and the colors will be situated in RGB palette (BGR on OpenCV). Whether you use BGR2HSV or BGR2HLS, pixels will be color-converted to another color.

Using cv::inRange to thresh your frame is another thing. I had originally thought that depending on the method used to color-convert pixels, the bounds of the inRange() function would be different: absolutely not. Since the results of the color-conversion remain in the RGB palette, the bounds must be defined in RGB too (BGR on OpenCV).

cv::Scalar(minimum_blue, minimum_green, minimum_red)
cv::Scalar(maximum_blue, maximum_green, maximum_red)

So, for example, if you only want to retrieve some purple, this would be :

cv::Scalar(135, 0, 65)
cv::Scalar(200, 70, 130)

(NB: this is an example. These bounds are correctly set for purple but they're not an absolute reference for the purple you would consider to retrieve by yourself)

edit flag offensive delete link more

Question Tools

1 follower


Asked: 2016-04-23 18:27:41 -0600

Seen: 2,546 times

Last updated: Apr 26 '16