使用‘ cv: : inRange’(OpenCV)为颜色检测选择正确的 HSV 上下边界

我有一个形象的咖啡罐与橙色的盖子的位置,我想找到。 这里是 < img src = “ https://i.stack.imgur.com/TGrDR.jpg”alt = “ image”> 。

Gcolor 2实用程序将盖子中心的 HSV 显示为(22,59,100)。 问题是如何选择颜色的极限呢?我尝试了 min = (18,40,90)和 max = (27,255,255) ,但得到了意想不到的 < img src = “ https://i.stack.imgur.com/Sku73.png”alt = “ result”>

下面是 Python 代码:

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()
289491 次浏览

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.

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()

OpenCV HSV range is: H: 0 to 179 S: 0 to 255 V: 0 to 255

On Gimp (or other photo manipulation sw) Hue range from 0 to 360, since opencv put color info in a single byte, the maximum number value in a single byte is 255 therefore openCV Hue values are equivalent to Hue values from gimp divided by 2.

I found when trying to do object detection based on HSV color space that a range of 5 (opencv range) was sufficient to filter out a specific color. I would advise you to use an HSV color palate to figure out the range that works best for your application.

HSV color palate with color detection in HSV space

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

To find the HSV value of Green, try following commands in Python terminal

green = np.uint8([[[0,255,0 ]]])
hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV)
print hsv_green
[[[ 60 255 255]]]

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()

You can use GIMP or PaintDotNet to get the exact range of HSV. But the problem is that the HSV range in graphics software is different from the same range in OpenCV, so you need a function to correct this for you. For this purpose, you can use the following function.

def fixHSVRange(h, s, v):
# Normal H,S,V: (0-360,0-100%,0-100%)
# OpenCV H,S,V: (0-180,0-255 ,0-255)
return (180 * h / 360, 255 * s / 100, 255 * v / 100)

enter image description here

For example you can use it something like this:

im=cv2.imread("image.jpg",1)
im_hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
color1 = fixHSVRange(h=10, s=20, v=0)
color2 = fixHSVRange(h=30, s=70, v=100)
mask = cv2.inRange(im_hsv, color1, color2)
cv2.imwrite("mask.jpg",mask)

enter image description here

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

Most of the methods mentioned above usually require some knowledge of the colour range for a particular colour followed by trial and error to get the right range. But the official documentation of OpenCV suggests a better way to find HSV lower and upper bounds even for the colours that are not very common.

How to find HSV values to track?

This is a common question found in stackoverflow.com. It is very simple and you can use the same function, cv.cvtColor(). Instead of passing an image, you just pass the BGR values you want. For example, to find the HSV value of Green, try the following commands in a Python terminal:

You can find the exact pixel values (BGR) of the required object and use them for example green (0, 255, 0)

green = np.uint8([[[0,255,0 ]]])
hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)
print(hsv_green)
[[[60 255 255]]]

Now you take [H-10, 100,100] and [H+10, 255, 255] as the lower bound and upper bound respectively. Apart from this method, you can use any image editing tools like GIMP or any online converters to find these values, but don't forget to adjust the HSV ranges.

Source:
OpenCV Colorspaces and Object Tracking
GIMP - Image Manipulating Tool