Rahul
Rahul

Reputation: 1005

Detecting color of ball using openCV from a live video feed

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

Answers (2)

Toby Collins
Toby Collins

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

flamelite
flamelite

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:

  • You can segment the ball in the image and then check hue channel inside of ball spatial region, but this might be not be time efficient.
  • Or else you can find number of all three classes of pixels(Red, green, blue color) present in image frames by using corresponding hue filters that is:
    • Blue color: (95, 0, 0) - (145, 255,255)
    • Green color: (36, 0, 0), (70, 255,255)
    • Red color: [(165, 0, 0) - (180, 255,255)] and [(0, 0, 0) - (15, 255,255)]

Maximum of all three classes of pixels will give you true color of ball.

I hope that helps.

Upvotes: 1

Related Questions