【问题标题】:Mask to filter the area of ​interest (OpenCV)过滤感兴趣区域的掩码(OpenCV)
【发布时间】:2020-04-08 13:38:03
【问题描述】:

我需要一个蒙版来使这个image 中的圆圈从背景中脱颖而出,接收二值图像,其中白色是感兴趣的区域(圆圈),而黑色是其他所有区域。所以我可以在视频捕捉中应用这个蒙版,在那里只能看到球体。 注意:背景通常是白色的。

我已经使用阈值或 inRange 创建了代码,使用简单的算法,从用户手动进行的选择中,标记圆的区域,它会删除最小和最大 rgb 值,从而创建一个要应用的参数在 inRange 或阈值内。然而,由于背景通常是白色和清晰的,与球体的颜色非常相似,二进制掩码包括背景,使得代码失败。 还有其他方法吗?

import cv2
import numpy as np
ix,iy = 0,0
def selection_area(event,x,y,flags,param):
    global ix,iy
    global vx,vy
    if event == cv2.EVENT_LBUTTONDBLCLK:
        cv2.rectangle(img,(x-5,y-5),(x+5,y+5),(255,255,0),-1)
        if ix!=0 and iy!=0:
            cv2.rectangle(img,(x,y),(ix,iy),(255,0,0),1)
            vx=[x,ix]
            vy=[y,iy]
        ix,iy = x,y

def analyzeRGB(cimg):
    b=[];g=[];r=[];
    for j in cimg:
        for i in j:
            b.append(i[0])
            g.append(i[1])
            r.append(i[2])
    lower_blue= np.array([min(b),min(g),min(r)])
    upper_blue= np.array([max(b),max(g),max(r)])
    return lower_blue,upper_blue


cap = cv2.VideoCapture(0)
while(True):
    ret, frame = cap.read()
    cv2.imshow('frame',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        img=frame
        break
cap.release()
cv2.destroyAllWindows()

cv2.imshow('Analyze',img)

cv2.setMouseCallback('Analyze',selection_area)

while(1):
    cv2.imshow('Analyze',img)
    k = cv2.waitKey(20) & 0xFF
    if k == ord('q'):
        print (vx,vy)
        break
cv2.destroyAllWindows()
cut = img[min(vy)+5:max(vy)-5,min(vx)+5:max(vx)-5]

cv2.imshow("Cut",cut)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(0)

filter_RGB =analyzeRGB(cut)
img =  cv2.inRange(img, filter_RGB[0],filter_RGB[1])

cv2.imshow("Ready",img)
cv2.imshow("Cut",cut)
cv2.waitKey(0)
cv2.destroyAllWindows()

cap = cv2.VideoCapture(0)
while(True):
    ret, frame = cap.read()
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY);

    frame =cv2.inRange(frame,filter_RGB[0],filter_RGB[1])

    cv2.imshow("Frame",frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

【问题讨论】:

    标签: python-3.x opencv


    【解决方案1】:

    寻找球具有挑战性,因为颜色接近背景,而且是手。
    球的反射和不均匀性使其更具挑战性。

    如果您知道球的确切半径,您可以使用cv2.HoughCircles 搜索具有确切半径的圆。

    我的解决方案使用cv2.HoughCircles,但首先“清理”图像。
    有一个很好的变化是解决方案对您发布的图像过于具体,并且不适用于一般情况。

    解决方案使用以下阶段:

    • 将图像转换为灰色。
    • 应用中值过滤器。
    • 使用cv2.adaptiveThreshold - 找到强度接近背景强度的边缘。
    • 掩盖暗像素 - 假设手比球更暗,并且从背景来看。
      为了避免手上出现“假圆圈”,我们需要遮住手。
    • 使用“开放”形态学操作来清理小簇。
    • 使用cv2.HoughCircles 查找圈子。
      我使用的参数只找到一个圆圈。
      当找到多个圆圈时,您可能会想到一些消除其他圆圈的逻辑。

    代码如下:

    import cv2
    import numpy as np
    
    # Read input image
    img = cv2.imread('ball_in_hand.png')
    
    # Convert to gray
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # Apply median filter
    gray = cv2.medianBlur(gray, 5)
    
    # Apply adaptive threshold with gaussian size 15x15
    thresh = cv2.adaptiveThreshold(gray, 255, adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C, thresholdType=cv2.THRESH_BINARY, blockSize=15, C=0)
    
    # Use threshold for finding dark pixels - needs to be masked
    _, dark_mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # Mask the dark pixels.
    thresh = thresh & dark_mask
    
    # Use "opening" morphological operation - cleaning up.
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)))
    
    rows, cols = thresh.shape
    
    # Use HoughCircles for finding circles
    circles = cv2.HoughCircles(thresh, cv2.HOUGH_GRADIENT, 1, minDist=rows//8, param1=50, param2=30, minRadius=rows//8, maxRadius=rows//2)
    
    # mask will be the desired mask (filled circle)
    mask = np.zeros_like(gray)
    
    # Iterate circles
    for c in circles[0,:]:
        # Draw green circle on the image for testing
        cv2.circle(img, (c[0], c[1]), c[2], (0, 255, 0), 2)
    
        # Draw filled circle for creating the mask
        cv2.circle(mask, (c[0], c[1]), c[2], 255, cv2.FILLED)
    
    # Show images for testing
    cv2.imshow('img', img)
    cv2.imshow('gray', gray)
    cv2.imshow('thresh', thresh)
    cv2.imshow('dark_mask', dark_mask)
    cv2.imshow('mask', mask)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    图片:

    mask(解决方案):

    img:

    gray:

    dark_mask:

    thresh:

    【讨论】:

    • 谢谢,我有了更多的工作机会。但是,我还没有取得令人愉快的结果。这个球将在一般白色的环境中与其他几个球一起被识别。我只需要知道球是在屏幕的右侧还是左侧,因此精度不需要准确。我只需要消除外部噪音。
    • 有手还是没有手?
    • 没有手。
    • 没有手,我认为cv2.adaptiveThreshold 会给出更好的结果。如果你可以选择不同的球,你可以让它变得更容易。
    • 是的,但不幸的是,球必须是那种颜色和白色背景。如果它是彩色的,我已经有了解决方案。仅使用 cv2.adaptiveThereshold 我得到了一些结果,但它仍然有很多噪音,cv2.HoughCircles 仍然无法正常工作
    猜你喜欢
    • 2013-03-03
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 2013-02-28
    • 2017-09-28
    • 2011-08-10
    • 1970-01-01
    相关资源
    最近更新 更多