Маска для фильтрации интересующей области (OpenCV) - PullRequest
1 голос
/ 08 апреля 2020

Мне нужна маска, чтобы круг на этом изображении выделялся на заднем плане, получая двоичное изображение, где белый - это область интереса (круг), а черный - все остальное. Так что я могу применить эту маску в видео захвате, где можно увидеть только сферу. примечание: фон, как правило, будет белым.

Я уже создал коды, используя порог или 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()

1 Ответ

0 голосов
/ 09 апреля 2020

Найти мяч сложно, потому что цвет близок к фону, и из-за руки.
Отражения от шара и неравномерность делают его более сложным.

Если вы знаете точный радиус шара, вы можете использовать cv2.HoughCircles для поиска круга с точным радиусом.

Мое решение использует cv2.HoughCircles, но сначала "очищает" изображение.
Есть хорошее изменение, что решение слишком специфично c к опубликованному вами изображению и не собирается работать для общего случая.

В решении используются следующие этапы:

  • Преобразование изображения в серый.
  • Применение медианного фильтра.
  • Использование cv2.adaptiveThreshold - найти края с интенсивностью, близкой к интенсивности фона.
  • Маска темных пикселей - предположить, что рука темнее шара и фона.
    Нам нужно замаскируйте руку, чтобы избежать «ложных кругов» на руке.
  • Используйте морфологическую операцию «открытия» для очистки небольших скоплений.
  • Используйте cv2.HoughCircles для поиска кругов.
    Параметры, которые я использовал, находят только один круг.
    Вы можете подумать о некотором логике c для исключения других кругов, когда найдено более одного.

Вот код:

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 (решение):
enter image description here

img:
enter image description here

gray:
enter image description here

dark_mask:
enter image description here

thresh:
enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...