Reputation: 1243
Below is my python code for tracking white color objects. It works - but only for a few seconds and then the whole screen turns black and in some times it not work. I experimented with blue color and it works - but white and green are giving me problems:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
_, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of white color in HSV
# change it according to your need !
sensitivity = 15
lower_white = np.array([0,0,255-sensitivity])
upper_white = np.array([255,sensitivity,255])
# Threshold the HSV image to get only white colors
mask = cv2.inRange(hsv, lower_white, upper_white)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
Upvotes: 15
Views: 12573
Reputation: 41776
Well, first thing you should know what color space you are using.
Just a small tutorial of color spaces in OpenCV for Mat
of type CV_8UC3
. (Images from Wikipedia)
In the HSV (Hue, Saturation, Value) color space, H gives the color dominant color, S the saturation of the color, V the lightness. In OpenCV, the ranges are different. S,V are in [0,255], while H is in [0, 180]. Typically H is in range [0,360] (the full circle), but to fit in a byte (256 different values) it's value is halved.
In HSV space is easier to separate a single color, since you can simply set the proper range for H, and just take care that S is not too small (it will be almost white), and V is not too small (it will be dark).
So for example, if you need almost blue colors, you need H to be around the value 120 (say in [110,130]), and S,V not too small (say in [100,255]).
White is not a hue (the rainbow doesn't have white color in it), but is a combination of color.
In HSV, you need to take all range of H (H in [0, 180]), very small S values (say S in [0, 25]), and very high V values (say V in [230, 255]). This basically corresponds to the upper part of the central axis of the cone.
So to make it track white objects in HSV space, you need:
lower_white = np.array([0, 0, 230])
upper_white = np.array([180, 25, 255])
Or, since you defined a sensitivity value, like:
sensitivity = 15
lower_white = np.array([0, 0, 255-sensitivity])
upper_white = np.array([180, sensitivity, 255])
For other colors:
green = 60;
blue = 120;
yellow = 30;
...
sensitivity = 15
// Change color with your actual color
lower_color = np.array([color - sensitivity, 100, 100])
upper_color = np.array([color + sensitivity, 255, 255])
Red H value is 0, so you need to take two ranges and "OR" them together:
sensitivity = 15
lower_red_0 = np.array([0, 100, 100])
upper_red_0 = np.array([sensitivity, 255, 255])
lower_red_1 = np.array([180 - sensitivity, 100, 100])
upper_red_1 = np.array([180, 255, 255])
mask_0 = cv2.inRange(hsv, lower_red_0 , upper_red_0);
mask_1 = cv2.inRange(hsv, lower_red_1 , upper_red_1 );
mask = cv2.bitwise_or(mask_0, mask_1)
Now you should be able to track any color!
Upvotes: 24
Reputation: 46680
Instead of having to guess and check the HSV lower/upper color ranges, you can use a HSV color thresholder script to determine the ranges with trackbars. This makes it very easy to define the ranges for whatever color you're trying to segment. Just change the input image in cv2.imread
. Example to segment white
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(True):
# 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()
Upvotes: 3