Choosing the correct upper and lower HSV boundaries for color detection with`cv::inRange` (OpenCV)
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:
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:
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:
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:
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:
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
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
Student FourK
Updated on July 08, 2022Comments
-
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 .
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
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 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 almost 12 yearsThank you. But i don't think there is much excellency here.:) (OK, i will do it)
-
Student FourK almost 12 yearsGreat! 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 almost 12 yearsGood 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 over 10 yearsThis is the place where every one commits mistakes when they are newbies to OpenCv.
-
Nine3KiD almost 8 yearsI 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 over 7 yearsLOL, I had written same code with printing the final HSV values used github.com/saurabheights/ImageProcessingExperimentScripts/blob/…
-
Andy Rosenblum over 7 yearsIn 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 about 4 yearssecond link behaving oddly?
-
Martijn Pieters about 4 years@jtlz2: They simply linked back to this answer. Perhaps in mistake.
-
DChaps about 4 yearsThis was extremely helpful. Made figuring out an appropriate HSV range 20x faster. Many mahalos!
-
KlopDesign almost 4 yearsWow! Extremely helpful as commented already. Thanks for sharing!
-
Seminko over 3 yearsPure awesomeness! Thank you very much
-
Jacob David C. Cunningham over 3 yearsA 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 over 2 yearsawesome tool, thanks for sharing, what does the copy button does?, I was expecting to copy the values
-
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 over 2 yearsJust 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.