Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV inRange() is working for RGB but not HSV color space

Ive generated a scatter plot of my image in RGB and HSV format and am using inRange() to threshold a single color from eyeballing the plot.

To get exact RGB and HSV values I'm using paint.net's color picker to get the RGB value and then an RGB to HSV converter to get the HSV values.

enter image description here

The pixel colors and the scatter plot are generated by:

img = cv2.imread('C:\\b_.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)


pixel_colors = img.reshape((np.shape(img)[0]*np.shape(img)[1], 3))
norm = colors.Normalize(vmin=-1., vmax=1.)
norm.autoscale(pixel_colors)
pixel_colors = norm(pixel_colors).tolist()

h, s, v = cv2.split(img_hsv)
fig = plt.figure()
axis = fig.add_subplot(1, 1, 1, projection="3d")

axis.scatter(h.flatten(), s.flatten(), v.flatten(), facecolors=pixel_colors, marker=".")
axis.set_xlabel("Hue")
axis.set_ylabel("Saturation")
axis.set_zlabel("Value")
plt.show()

I need to extract the yellow from my image. As mentioned I am using paint.net color picker to get the RGB values of light yellow and dark yellow. And then use the converter to get the HSV values for the inRange() function.

light_yellow = (60, 89, 97)    # HSV VALUES
dark_yellow = (61, 36.6, 43.9)

mask = cv2.inRange(img_hsv, light_yellow, dark_yellow)
result = cv2.bitwise_and(img, img, mask=mask)

but the result generated is a black image, however if I use the RGB values directly of light and dark yellow and use the RGB image, not the HSV converted image, the segmentation works.

light_yellow = (249, 249, 125)    # RGB VALUES
dark_yellow = (111, 112, 71)

mask = cv2.inRange(img, light_yellow, dark_yellow)
result = cv2.bitwise_and(img, img, mask=mask)

enter image description here

Although the above is RGB segmentation, I feel it may be improved in HSV. Why is my HSV range not giving an output?

like image 370
StuckInPhDNoMore Avatar asked Jan 26 '23 02:01

StuckInPhDNoMore


1 Answers

As it is expressed in the documentation of cvtColor. When it is CV_8U the H value which normally goes from 0 to 360, it is divided by 2 and goes from 0-180. The S and V values are usually percentage (0-100%) and they go from 0-255.

So your value:

light_yellow = (60, 89, 97)    # HSV VALUES
dark_yellow = (61, 36.6, 43.9)

Should be more like:

# (H/2, (S/100) * 255, (V/100) * 255) 
light_yellow = (30, 227, 247)    # HSV VALUES
dark_yellow = (31, 93, 112)

Now you have another problem, inRanges looks for valus inside the low and high range, not by light and dark yellow. So your limits should be:

low = (30,93,112)
high = (31, 227,247)

mask = cv2.inRange(img_hsv, low, high)

One more thing, I would use a bigger range for the H color... 30-31 is quite small, maybe 20-32 is better?

like image 125
api55 Avatar answered Jan 31 '23 23:01

api55