Reputation: 1005
I was trying to detect the color of the ball from my webcam feed. The colors i was trying are Red Green Blue and yellow. I wrote this code given below. But it shows blue ball detected randomly even when no ball is there. And also when green or red color is shown, blue ball deteced pops up in between. Please suggest some way to make it more accurate and how to include yellow.
enter code here
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
lower_green = np.array([45,140,50])
upper_green = np.array([75,255,255])
lower_red = np.array([160,140,50])
upper_red = np.array([180,255,255])
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
foundred = False
while(True):
success,frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
hsv = cv2.medianBlur(hsv,5)
imgThreshHighred = cv2.inRange(hsv, lower_red, upper_red)
imgThreshHighgreen = cv2.inRange(hsv, lower_green, upper_green)
imgThreshHighblue = cv2.inRange(hsv, lower_blue, upper_blue)
circlesred = cv2.HoughCircles(imgThreshHighred,cv2.HOUGH_GRADIENT,1,20,param1=50,param2=30,minRadius=0,maxRadius=0)
circlesblue = cv2.HoughCircles(imgThreshHighblue,cv2.HOUGH_GRADIENT,1,20,param1=50,param2=30,minRadius=0,maxRadius=0)
circlesgreen = cv2.HoughCircles(imgThreshHighgreen,cv2.HOUGH_GRADIENT,1,20,param1=50,param2=30,minRadius=0,maxRadius=0)
if circlesred is not None:
print "found red"
# print circlesred
if circlesgreen is not None:
print "found green"
# print circlesgreen
if circlesblue is not None:
print "found blue"
# print circlesblue
else:
print "no ball"
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
Upvotes: 0
Views: 2142
Reputation: 823
You are observing false positives, and as flamelite pointed out they are caused by other regions in your images that fall within the HSV range of your targets. This is normal with your current approach. Detection based on colour region detection will almost certainly generate false positives in natural images. To reduce or eliminate false positives you have two strategies.
1. Use a more specific colour model. You can either do this using a tighter HSV range as flamelite suggested, or you could train a Gaussian model for each ball using OpenCV's Gaussian Mixture Modelling methods with the EM
class. This can be used to segment, and would replace your 3 lines of code calling inRange
. In both approaches, you must be careful that your training images match your test images (in particular that lighting is similar and colour variation from auto white balance, if active, represented in the training images).
2. Use additional features/information. If you are still left with false positives you need to eliminate them using properties other than colour. For example, is the ball's radius approximately constant in the videos? If so you can reject regions that are clearly too small or too large. This can be very effective. Is the background not moving? If so you can attempt to use OpenCV's background subtraction methods to eliminate false positives. Do you only ever see one ball at a time? If so you can reject all but the most likely 'ball' region using for example the average of the Gaussian colour model's log likelihood over each region.
Upvotes: 1
Reputation: 2854
I guess at some point in your image frame there must be some small components with hue value in the blue range that is why you are getting blue color as false positive. Here is what i would suggest:
Maximum of all three classes of pixels will give you true color of ball.
I hope that helps.
Upvotes: 1