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

Posted

技术标签:

【中文标题】使用`cv::inRange` (OpenCV) 为颜色检测选择正确的 HSV 上下边界【英文标题】:Choosing the correct upper and lower HSV boundaries for color detection with`cv::inRange` (OpenCV) 【发布时间】:2012-06-12 11:56:52 【问题描述】:

我有一张带有橙色盖子位置的咖啡罐的图像,我想找到它。 这是。

gcolor2 实用程序显示盖子中心的 HSV 为 (22, 59, 100)。 问题是如何选择颜色的界限呢?我试过 min = (18, 40, 90) 和 max = (27, 255, 255),但得到了意想不到的

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

【问题讨论】:

我检查了值 (22, 59, 100) 作为 HSV,它们似乎与任何类似于盖子的颜色都不匹配。但作为 BGR,它们是有道理的。您是如何检索这些值的? 这里是 gcolor2 imageshack.us/photo/my-images/23/rgb2hsv.png 的截图。然后我检查了yafla.com/yaflaColor/ColorRGBHSL.aspx?RGB=&Colors=上的颜色编号#FFA069,,,,,,,,,转换是一样的。 这可能是由于OpenCV中的HSV范围不同,即H:0 - 180,S:0 - 255,V:0 - 255。 【参考方案1】:

问题 1: 不同的应用程序对 HSV 使用不同的尺度。例如 gimp 使用H = 0-360, S = 0-100 and V = 0-100。但是 OpenCV 使用H: 0-179, S: 0-255, V: 0-255。在这里,我在 gimp 中得到了 22 的色调值。所以我拿了一半,11,并为此定义了范围。即(5,50,50) - (15,255,255)

问题 2: 而且,OpenCV 使用 BGR 格式,而不是 RGB。因此,如下更改将 RGB 转换为 HSV 的代码:

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

现在运行它。我得到如下输出:

希望这是您想要的。有一些错误检测,但它们很小,因此您可以选择最大的轮廓,即您的盖子。

编辑:

正如 Karl Philip 在他的评论中所说,添加新代码会很好。但是只有一行的变化。所以,我想添加在新的cv2 模块中实现的相同代码,以便用户可以比较新的cv2 模块的易用性和灵活性。

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)

它给出与上面相同的结果。但是代码要简单得多。

【讨论】:

+1 太棒了,再一次。如果您可以在修改后添加完整的源代码,那就太棒了。 谢谢。但我不认为这里有什么过人之处。:)(好吧,我会做的) 太棒了!它现在也适用于我,虽然我相信你的 S 和 V 最小-最大范围太宽松了。最小(5、100、255)和最大(15、200、255)的盖子覆盖率也很好。 很高兴知道。我取 S,V 值只是为了显示结果,以显示此解决方案有效。很好,你找到了更好的。也尝试移动到cv2 界面。它更简单,更快捷。你可以在这里找到一些很好的教程:opencvpython.blogspot.com。如果它解决了您的问题,请接受答案并关闭此会话。 这是每个OpenCv新手都会犯错误的地方。【参考方案2】:

我创建了这个简单的程序来实时获取 HSV 代码

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

【讨论】:

大声笑,我编写了相同的代码来打印使用的最终 HSV 值 github.com/saurabheights/ImageProcessingExperimentScripts/blob/…【参考方案3】:

OpenCV HSV 范围是: 高:0 到 179 小号:0 到 255 V:0 到 255

在 Gimp(或其他照片处理软件)上,Hue 范围从 0 到 360,由于 opencv 将颜色信息放在单个字节中,因此单个字节中的最大数值为 255,因此 openCV Hue 值等同于 gimp 中的 Hue 值除以 2。

我在尝试基于 HSV 颜色空间进行对象检测时发现,5 的范围(opencv 范围)足以过滤掉特定的颜色。我建议您使用 HSV 色板来确定最适合您的应用的范围。

【讨论】:

【参考方案4】:

好的,在HSV 空间中查找颜色是一个古老但常见的问题。我做了一个hsv-colormap 来快速查找特殊颜色。这里是:

x轴代表Hue在[0,180]中,y轴1代表Saturation在[0,255]中,y轴2代表S = 255,同时保持V = 255

要查找颜色,通常只需查找HS 的范围,并将v 设置为范围(20, 255)。

要找到橙色,我们查找地图并找到最佳范围:H :[10, 25], S: [100, 255], and V: [20, 255]。所以掩码是cv2.inRange(hsv,(10, 100, 20), (25, 255, 255) )

然后我们使用找到的范围寻找橙色,结果如下:


方法简单但常用:

#!/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()

类似的答案:

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

    Choosing correct HSV values for OpenCV thresholding with InRangeS

【讨论】:

第二个链接行为异常? @jtlz2:他们只是简单地链接回 this answer。也许是错误的。 有点晚了,但想知道您是如何确定 V 值的。在我的应用程序中,我使用直方图来确定 H/S 值,但不确定 V。关于 0-100% 是暗/亮,我猜在一个光线充足的房间里,我们只需要一个中值?跨度> 【参考方案5】:

要查找绿色的 HSV 值,请尝试在 Python 终端中执行以下命令

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

【讨论】:

【参考方案6】:

这是一个简单的 HSV 颜色阈值脚本,用于使用磁盘上任何图像的轨迹栏来确定下/上色范围。只需更改cv2.imread()中的图片路径

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 范围的速度提高了 20 倍。许多 mahalos! 哇!正如已经评论的那样,非常有帮助。感谢分享! 纯真棒!非常感谢 只想呼应上面的cmets,说这个colorpicker厉害。非常有助于获得 90% 的准确 HSV 阈值,非常感谢。【参考方案7】:

您可以使用 GIMP 或 PaintDotNet 获得 HSV 的准确范围。但问题是图形软件中的 HSV 范围与 OpenCV 中的相同范围不同,因此您需要一个函数来为您纠正这个问题。为此,您可以使用以下函数。

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)

例如,您可以像这样使用它:

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)

【讨论】:

【参考方案8】:

为此,我使用 opencv-python 创建了一个简单(更合适)的工具。认为这对像我今年早些时候一样在这里偶然发现的人很有用

由于该工具本身是使用 python cv2 编写的,因此可以保证使用相同的范围。还有一个用于erodedilate 的滑块,因为通常计算机视觉项目需要这两个功能

你可以从这里克隆工具https://github.com/hariangr/HsvRangeTool

【讨论】:

很棒的工具,感谢分享,复制按钮是做什么的?,我期待复制值 @JoeCabezas 我完全忘记了这个按钮,我只是实现了它来将 hsv 范围打印到控制台。谢谢。【参考方案9】:

上面提到的大多数方法通常需要对特定颜色的颜色范围有所了解,然后通过反复试验来获得正确的范围。但是 OpenCV 的官方文档提出了一种更好的方法来找到 HSV 下限和上限,即使对于不常见的颜色也是如此。

如何找到要跟踪的 HSV 值?

这是在 ***.com 中发现的一个常见问题。它非常简单,您可以使用相同的函数 cv.cvtColor()。您只需传递所需的 BGR 值,而不是传递图像。例如,要查找 Green 的 HSV 值,请在 Python 终端中尝试以下命令:

您可以找到所需对象的确切像素值 (BGR) 并使用它们,例如绿色 (0, 255, 0)

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

现在您将 [H-10, 100,100][H+10, 255, 255] 分别作为下限和上限。除此方法外,您还可以使用任何图像编辑工具(如 GIMP)或任何在线转换器来查找这些值,但不要忘记调整 HSV 范围。

来源:OpenCV Colorspaces and Object TrackingGIMP - Image Manipulating Tool

【讨论】:

以上是关于使用`cv::inRange` (OpenCV) 为颜色检测选择正确的 HSV 上下边界的主要内容,如果未能解决你的问题,请参考以下文章

opencv函数之cv.InRange函数

OpenCV更好地检测红色?

在卫星图像上使用 opencv 检测植被

opencv的掩膜案例

初识OpenCV-Python - 005: 识别视频中的蓝色

将条件应用于opencv图像