使用openCV从实时视频输入中检测球的颜色

时间:2018-01-15 17:52:28

标签: python opencv image-processing

我试图从我的网络摄像头Feed中检测出球的颜色。我尝试的颜色是红绿蓝和黄色。我写了下面给出的代码。但它显示即使没有球也随机检测到蓝色球。并且当显示绿色或红色时,在其间突然出现蓝色球。请建议一些方法,使其更准确,如何包括黄色。

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

2 个答案:

答案 0 :(得分:1)

你正在观察假阳性,并且正如flamelite所指出的那样,它们是由你的图像中属于目标的HSV范围内的其他区域引起的。对于您当前的方法,这是正常的。基于颜色区域检测的检测几乎肯定会在自然图像中产生误报。为了减少或消除误报,你有两种策略。

<强> 1。使用更具体的颜色模型。您可以使用更薄的HSV范围(如熔炉建议)来执行此操作,或者您可以使用OpenCV的高斯混合建模方法为#!/usr/bin/python3 # 2018.01.16 13:07:05 CST # 2018.01.16 13:54:39 CST import cv2 import numpy as np def alphaBlend(img1, img2, mask): """ alphaBlend img1 and img 2 (of CV_8UC3) with mask (CV_8UC1 or CV_8UC3) """ if mask.ndim==3 and mask.shape[-1] == 3: alpha = mask/255.0 else: alpha = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)/255.0 blended = cv2.convertScaleAbs(img1*(1-alpha) + img2*alpha) return blended img = cv2.imread("test.png") H,W = img.shape[:2] mask = np.zeros((H,W), np.uint8) cv2.circle(mask, (325, 350), 40, (255,255,255), -1, cv2.LINE_AA) mask = cv2.GaussianBlur(mask, (21,21),11 ) blured = cv2.GaussianBlur(img, (21,21), 11) blended1 = alphaBlend(img, blured, mask) blended2 = alphaBlend(img, blured, 255- mask) cv2.imshow("blened1", blended1); cv2.imshow("blened2", blended2); cv2.waitKey();cv2.destroyAllWindows() 类训练每个球的高斯模型。这可用于分段,并将替换调用EM的3行代码。在这两种方法中,您必须注意您的训练图像与您的测试图像相匹配(特别是光照类似,并且自动白平衡的颜色变化,如果有效,则在训练图像中表示)。

<强> 2。使用其他功能/信息。如果您仍然留下误报,则需要使用颜色以外的属性消除它们。例如,视频中球的半径是近似恒定的吗?如果是这样,您可以拒绝明显太小或太大的区域。这可能非常有效。背景不动吗?如果是这样,您可以尝试使用OpenCV的背景减法方法来消除误报。你一次只能看到一个球吗?如果是这样的话,你可以使用例如高斯颜色模型在每个区域的对数似然的平均值来拒绝除了最可能的“球”区域之外的所有区域。

答案 1 :(得分:0)

我想在你的图像框架中的某个点上必须有一些小部件,其色调值在蓝色范围内,这就是为什么你得到蓝色作为误报的原因。以下是我的建议:

  • 你可以在图像中分割球,然后检查球空间区域内的色调通道,但这可能不是时间效率。
  • 或者你可以通过使用相应的色调过滤器找到图像帧中存在的所有三类像素(红色,绿色,蓝色)的数量:
    • 蓝色:(95,0,0) - (145,255,255)
    • 绿色:(36,0,0),(70,255,255)
    • 红色:[(165,0,0) - (180,255,255)]和[(0,0,0) - (15,255,255)]

所有三类像素中的最大值将为您提供真实的球色。

我希望有所帮助。