Frederik Vanclooster
Frederik Vanclooster

Reputation: 513

OpenCV: Choosing HSV thresholds for color filtering

In order to filter a color out of an image, it's necessary to set boundaries as to which color needs to be detected. I have a feeling this is mostly a trial-and-error process. Are there any ways to quickly find the correct thresholds for a particular color? In this specific case I'm trying to detect the gray area of the graph in the picture below. This without detecting the dotted lines of course. For this example I need very specific boundaries. The question is, how can I find them easily?

hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)

lower = np.array([0, 0, 0], np.uint8)
upper = np.array([180, 255, 200], np.uint8)

mask = cv2.inRange(hsv, lower, upper)

enter image description here

Upvotes: 8

Views: 21123

Answers (2)

nathancy
nathancy

Reputation: 46610

You can use a HSV color thresholder script with trackbars to isolate the desired lower/upper HSV color range

import cv2
import sys
import numpy as np

def nothing(x):
    pass

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

# create trackbars for color change
cv2.createTrackbar('HMin','image',0,179,nothing) # Hue is from 0-179 for Opencv
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 to check if HSV min/max value changes
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0

img = cv2.imread('1.png')
output = img
waitTime = 33

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 max HSV values to display
    lower = np.array([hMin, sMin, vMin])
    upper = np.array([hMax, sMax, vMax])

    # Create HSV Image and threshold into a range.
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)
    output = cv2.bitwise_and(img,img, 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 output image
    cv2.imshow('image',output)

    # Wait longer to prevent freeze for videos.
    if cv2.waitKey(waitTime) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()

Upvotes: 23

Dima Mironov
Dima Mironov

Reputation: 575

Another option is to use online image color picker. You can upload your image and will get some values like HSV: 97.5° 5.1% 61.57% in your case. Note, you need to convert them to OpenCV scales of H, S and V.

H, hue in OpenCV varies from 0 to 180, but in the outer world it is usually measured in degrees from 0 to 360, so to get the H of your color h = 97.5° / 2 = 48.7

S and V are measured from 0 ( = 0% in outer world) to 255 ( = 100% in outer world), so

s = 255 * 5.1% = 13
v = 255 * 61.57% = 157

So, the target HSV color is (49, 13, 157). I suggest using ±10 for the range. Or being even more strict. I think it might be OK for your case to select only the pixels of the central graph, without any labels, and then apply morphological operation close, if needed.

Upvotes: 2

Related Questions