Как получить маску переднего плана, когда уже есть фоновое изображение
Я знаю что с cv2.createBackgroundSubtractorMOG2()
мы можем вычесть маску переднего плана, используя метод оценки фона на основе каждых 500 кадров (по умолчанию). Но как насчет того, чтобы у меня уже была фоновая картинка и я просто хотел вычесть передний план, используя эту картинку в каждом кадре? То, что я извлекаю, это так:
import numpy as np
import cv2
video = "xx.avi"
cap = cv2.VideoCapture(video)
bg = cv2.imread("bg.png")
while True:
ret, frame = cap.read()
original_frame = frame.copy()
if ret:
# get foremask?
fgmask = frame - bg
# filter kernel for denoising:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
opening = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
# Dilate to merge adjacent blobs
dilation = cv2.dilate(closing, kernel, iterations = 2)
# show fg:dilation
cv2.imshow('fg mask', dilation)
cv2.imshow('original', original_frame)
k = cv2.waitKey(30) & 0xff
if k == 27:
cap.release()
cv2.destroyAllWindows()
break
else:
break
Тем не менее, я получил красочные рамки при выполнении frame = frame - bg
, Как я могу получить правильную маску переднего плана?
1 ответ
Вы получаете красочные изображения, потому что вы вычитаете 2 цветных изображения, поэтому цвет, который вы получаете на каждом пикселе, представляет собой разницу на каждом канале (B,G и R) между обоими изображениями. Чтобы выполнить вычитание фона, как отмечает dhanushka, самый простой вариант - использовать MOG2 и переслать ему свое фоновое изображение на несколько (500) кадров, чтобы он запомнил это как фон. MOG2 предназначен для изучения изменчивости цвета каждого пикселя с помощью гауссовой модели, поэтому, если вы подаете всегда одно и то же изображение, он не будет изучать это. Во всяком случае, я думаю, что это должно работать для того, что вы собираетесь делать. Хорошая особенность этого подхода в том, что MOG2 позаботится о многих других вещах, таких как обновление модели с течением времени, работа с тенями и так далее.
Другой вариант - реализовать собственный метод вычитания фона, как вы пытались это сделать. Так что, если вы хотите проверить его, вам нужно преобразовать цветное изображение fgmask во что-то, что вы можете легко портировать и решить для каждого пикселя, является ли он фоном или передним планом. Простым вариантом было бы преобразовать его в оттенки серого, а затем применить простой порог: чем ниже порог, тем более "чувствителен" ваш метод вычитания (играть со значением порога), т.е.
...
# get foremask?
fgmask = frame - bg
gray_image = cv2.cvtColor(fgmask, cv2.COLOR_BGR2GRAY)
thresh = 20
im_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1]
# filter kernel for denoising:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
opening = cv2.morphologyEx(im_bw, cv2.MORPH_OPEN, kernel)
...