Choosing the correct upper and lower HSV boundaries for color detection with`cv::inRange` (OpenCV)

252,977

Solution 1

Problem 1 : Different applications use different scales for HSV. For example gimp uses H = 0-360, S = 0-100 and V = 0-100. But OpenCV uses H: 0-179, S: 0-255, V: 0-255. Here i got a hue value of 22 in gimp. So I took half of it, 11, and defined range for that. ie (5,50,50) - (15,255,255).

Problem 2: And also, OpenCV uses BGR format, not RGB. So change your code which converts RGB to HSV as follows:

cv.CvtColor(frame, frameHSV, cv.CV_BGR2HSV)

Now run it. I got an output as follows:

enter image description here

Hope that is what you wanted. There are some false detections, but they are small, so you can choose biggest contour which is your lid.

EDIT:

As Karl Philip told in his comment, it would be good to add new code. But there is change of only a single line. So, I would like to add the same code implemented in new cv2 module, so users can compare the easiness and flexibility of new cv2 module.

import cv2
import numpy as np

img = cv2.imread('sof.jpg')

ORANGE_MIN = np.array([5, 50, 50],np.uint8)
ORANGE_MAX = np.array([15, 255, 255],np.uint8)

hsv_img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

frame_threshed = cv2.inRange(hsv_img, ORANGE_MIN, ORANGE_MAX)
cv2.imwrite('output2.jpg', frame_threshed)

It gives the same result as above. But code is much more simpler.

Solution 2

Ok, find color in HSV space is an old but common question. I made a hsv-colormap to fast look up special color. Here it is:

enter image description here

The x-axis represents Hue in [0,180), the y-axis1 represents Saturation in [0,255], the y-axis2 represents S = 255, while keep V = 255.

To find a color, usually just look up for the range of H and S, and set v in range(20, 255).

To find the orange color, we look up for the map, and find the best range: H :[10, 25], S: [100, 255], and V: [20, 255]. So the mask is cv2.inRange(hsv,(10, 100, 20), (25, 255, 255) )

Then we use the found range to look for the orange color, this is the result:

enter image description here


The method is simple but common to use:

#!/usr/bin/python3
# 2018.01.21 20:46:41 CST
import cv2

img = cv2.imread("test.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv,(10, 100, 20), (25, 255, 255) )
cv2.imshow("orange", mask);cv2.waitKey();cv2.destroyAllWindows()

Similar answers:

  1. How to define a threshold value to detect only green colour objects in an image :Opencv

  2. Choosing correct HSV values for OpenCV thresholding with InRangeS

Solution 3

Here's a simple HSV color thresholder script to determine the lower/upper color ranges using trackbars for any image on the disk. Simply change the image path in cv2.imread(). Example to isolate orange:

enter image description here

import cv2
import numpy as np

def nothing(x):
    pass

# Load image
image = cv2.imread('1.jpg')

# Create a window
cv2.namedWindow('image')

# Create trackbars for color change
# Hue is from 0-179 for Opencv
cv2.createTrackbar('HMin', 'image', 0, 179, nothing)
cv2.createTrackbar('SMin', 'image', 0, 255, nothing)
cv2.createTrackbar('VMin', 'image', 0, 255, nothing)
cv2.createTrackbar('HMax', 'image', 0, 179, nothing)
cv2.createTrackbar('SMax', 'image', 0, 255, nothing)
cv2.createTrackbar('VMax', 'image', 0, 255, nothing)

# Set default value for Max HSV trackbars
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)

# Initialize HSV min/max values
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0

while(1):
    # Get current positions of all trackbars
    hMin = cv2.getTrackbarPos('HMin', 'image')
    sMin = cv2.getTrackbarPos('SMin', 'image')
    vMin = cv2.getTrackbarPos('VMin', 'image')
    hMax = cv2.getTrackbarPos('HMax', 'image')
    sMax = cv2.getTrackbarPos('SMax', 'image')
    vMax = cv2.getTrackbarPos('VMax', 'image')

    # Set minimum and maximum HSV values to display
    lower = np.array([hMin, sMin, vMin])
    upper = np.array([hMax, sMax, vMax])

    # Convert to HSV format and color threshold
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)
    result = cv2.bitwise_and(image, image, mask=mask)

    # Print if there is a change in HSV value
    if((phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
        print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
        phMin = hMin
        psMin = sMin
        pvMin = vMin
        phMax = hMax
        psMax = sMax
        pvMax = vMax

    # Display result image
    cv2.imshow('image', result)
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()

HSV lower/upper color threshold ranges

(hMin = 0 , sMin = 164, vMin = 0), (hMax = 179 , sMax = 255, vMax = 255)

Once you have determined your lower and upper HSV color ranges, you can segment your desired colors like this:

import numpy as np
import cv2

image = cv2.imread('1.png')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([0, 164, 0])
upper = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(image, image, mask=mask)

cv2.imshow('result', result)
cv2.waitKey()

Solution 4

I Created this simple program to get HSV Codes in realtime

import cv2
import numpy as np


cap = cv2.VideoCapture(0)

def nothing(x):
    pass
# Creating a window for later use
cv2.namedWindow('result')

# Starting with 100's to prevent error while masking
h,s,v = 100,100,100

# Creating track bar
cv2.createTrackbar('h', 'result',0,179,nothing)
cv2.createTrackbar('s', 'result',0,255,nothing)
cv2.createTrackbar('v', 'result',0,255,nothing)

while(1):

    _, frame = cap.read()

    #converting to HSV
    hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)

    # get info from track bar and appy to result
    h = cv2.getTrackbarPos('h','result')
    s = cv2.getTrackbarPos('s','result')
    v = cv2.getTrackbarPos('v','result')

    # Normal masking algorithm
    lower_blue = np.array([h,s,v])
    upper_blue = np.array([180,255,255])

    mask = cv2.inRange(hsv,lower_blue, upper_blue)

    result = cv2.bitwise_and(frame,frame,mask = mask)

    cv2.imshow('result',result)

    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break

cap.release()

cv2.destroyAllWindows()

Solution 5

I created a simple (more proper) tool using opencv-python for this purpose. Thought it would be useful for someone stumbled here like I did earlier this year

enter image description here

Since the tool itself is written using python cv2, it would be guaranteed to use the same range. Also there's a slider for erode and dilate since usually computer vision project need these two feature

You can clone the tool from here https://github.com/hariangr/HsvRangeTool

Share:
252,977
Student FourK
Author by

Student FourK

Updated on July 08, 2022

Comments

  • Student FourK
    Student FourK almost 2 years

    I have an image of a coffee can with an orange lid position of which I want to find. Here is it image.

    gcolor2 utility shows HSV at the center of the lid to be (22, 59, 100). The question is how to choose the limits of the color then? I tried min = (18, 40, 90) and max = (27, 255, 255), but have got unexpected result

    Here is the Python code:

    import cv
    
    in_image = 'kaffee.png'
    out_image = 'kaffee_out.png'
    out_image_thr = 'kaffee_thr.png'
    
    ORANGE_MIN = cv.Scalar(18, 40, 90)
    ORANGE_MAX = cv.Scalar(27, 255, 255)
    COLOR_MIN = ORANGE_MIN
    COLOR_MAX = ORANGE_MAX
    
    def test1():
        frame = cv.LoadImage(in_image)
        frameHSV = cv.CreateImage(cv.GetSize(frame), 8, 3)
        cv.CvtColor(frame, frameHSV, cv.CV_RGB2HSV)
        frame_threshed = cv.CreateImage(cv.GetSize(frameHSV), 8, 1)
        cv.InRangeS(frameHSV, COLOR_MIN, COLOR_MAX, frame_threshed)
        cv.SaveImage(out_image_thr, frame_threshed)
    
    if __name__ == '__main__':
        test1()
    
  • karlphillip
    karlphillip almost 12 years
    +1 Excellent, once again. If you could add the full source code with your modifications it would be awesome.
  • Abid Rahman K
    Abid Rahman K almost 12 years
    Thank you. But i don't think there is much excellency here.:) (OK, i will do it)
  • Student FourK
    Student FourK almost 12 years
    Great! It works for me now as well, although I believe your S and V min-max ranges are too relaxed. I also have got good lid coverage with min (5, 100, 255) and max (15, 200, 255).
  • Abid Rahman K
    Abid Rahman K almost 12 years
    Good to know. I took S,V values just to show the result, to show this solution works. Good you found better ones. Also try to move onto cv2 interface. It is more simpler and faster. You can find some good tutorials here: opencvpython.blogspot.com. And if it solves your problem, accept the answer and close this session.
  • nbsrujan
    nbsrujan over 10 years
    This is the place where every one commits mistakes when they are newbies to OpenCv.
  • Nine3KiD
    Nine3KiD almost 8 years
    I used this code to detect a green color line in an image.I gave the min and max (0,255,0).But nothing was detected.Does anyone know what happened there.
  • saurabheights
    saurabheights over 7 years
    LOL, I had written same code with printing the final HSV values used github.com/saurabheights/ImageProcessingExperimentScripts/bl‌​ob/…
  • Andy Rosenblum
    Andy Rosenblum over 7 years
    In terms of HSV, H (hue) is the color. If you use multiple images, you might need a fairly wide range for SV. Also, a color (pink for me) may wrap from the max value to zero.
  • jtlz2
    jtlz2 about 4 years
    second link behaving oddly?
  • Martijn Pieters
    Martijn Pieters about 4 years
    @jtlz2: They simply linked back to this answer. Perhaps in mistake.
  • DChaps
    DChaps about 4 years
    This was extremely helpful. Made figuring out an appropriate HSV range 20x faster. Many mahalos!
  • KlopDesign
    KlopDesign almost 4 years
    Wow! Extremely helpful as commented already. Thanks for sharing!
  • Seminko
    Seminko over 3 years
    Pure awesomeness! Thank you very much
  • Jacob David C. Cunningham
    Jacob David C. Cunningham over 3 years
    A bit late but wondering how you determined the V value. In my application I'm using histograms to determine H/S values but wasn't sure about V. Regarding 0-100% being dark/light I guess in a decently lit room we'd just go for a median value?
  • Joe Cabezas
    Joe Cabezas over 2 years
    awesome tool, thanks for sharing, what does the copy button does?, I was expecting to copy the values
  • Hari Anugrah
    Hari Anugrah over 2 years
    @JoeCabezas I completely forgot about the button, I just implemented it to print the hsv range to console. Thank you.
  • BeginnersMindTruly
    BeginnersMindTruly over 2 years
    Just want to echo the above comments and say that this colorpicker is amazing. Super helpful for getting 90% of the way to accurate HSV thresholding, many many thanks.