Проект удаления фона с использованием OpenCV. По сути, это простая, но интересная функция, которая очень часто используется в большинстве сервисов потокового видео, таких как Zoom, Hangouts и т. д. Это очень простая аналогия, и я хотел бы упомянуть, как легко это можно сделать.

Так над чем конкретно работает этот проект. Итак, у нас есть фон, и у нас есть передний план. Этот проект поможет нам удалить наш фон и заменить его любым видео или изображением, как это делается в приложениях для видеочата/стриминга.

Поскольку я уже обсуждал использование OpenCV и его основы ранее, я собираюсь погрузиться прямо в код и его объяснение.

По сути, мы собираемся использовать метод ФОНОВОЕ ВЫЧИТАНИЕ. Таким образом, это, по сути, включает в себя вычитание фона, который находится позади меня, а затем вычитание переднего плана, который находится передо мной. Это, по сути, вся идея проекта, и она станет более осмысленной, как только мы начнем ее реализовывать. Итак, приступим непосредственно к реализации.

Итак, первым шагом будет импорт всех необходимых библиотек, необходимых для этого, и я бы рекомендовал использовать pip для установки любых библиотек, которые у вас не установлены.

#Importing libraries
import cv2
import numpy as np
import sys

Следующим шагом будет включение камеры и импорт видео, которое я буду использовать в качестве фона. Вы можете установить любое видео и сохранить его в той же папке, что и блокнот, или просто указать путь к видеофайлу.

video = cv2.VideoCapture(1)
oceanVideo = cv2.VideoCapture("ocean.mp4")
success, ref_img = video.read()
flag = 0
  • Первая строка включает вашу камеру.
  • Вторая строка открывает видеофайл с помощью opencv.
  • Третья строка позволяет камере захватить фон и сохранить его в качестве эталона. Это называется ref_img.
  • Флаг используется для ручного управления программой и замены фона изображением или видео, которое вы поймете в следующих строках.

Следующим важным шагом является запуск цикла while или бесконечного цикла до тех пор, пока не будет нажата последовательность Escape, в результате чего мы считываем ввод с видеокамеры. Следующим шагом будет чтение ввода из второго видео в цикле while.

success, img = video.read()
success2, bg = oceanVideo.read()

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

#Resize function
def resize(dst,img):
  width = img.shape[1]
  height = img.shape[0]
  dim = (width, height)
  resized = cv2.resize(dst, dim, interpolation = cv2.INTER_AREA)
  return resized
#Use inside while loop to resize video to reference background
bg = resize(bg,ref_img)

Концептуально очень важно понимать, что все изображения хранятся в виде матриц и каждую из этих матриц можно складывать или вычитать друг из друга, только если они имеют одинаковую размерность. Вот почему важно, чтобы они оба были в одном измерении.

Затем выполняется один из самых важных шагов, когда мы создаем маску.

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

#create a mask
diff1=cv2.subtract(img,ref_img)
diff2=cv2.subtract(ref_img,img)

Следующим важным шагом будет добавление этих двух различий и их сохранение, а затем создание порога. Это связано с тем, что шума так много, что очень легко потерять детали. Итак, мы берем абсолютное значение матрицы изображения, которое мы получили, а затем устанавливаем для него пороговое значение. Это пороговое значение будет отличаться от человека к человеку, поскольку мы должны понимать, что порог будет основываться на количестве шума, создаваемого вашей камерой, и четкости. Таким образом, я бы рекомендовал поиграть с этим значением, чтобы понять его функциональность.

diff = diff1+diff2
diff[abs(diff)<13.0]=0

Следующим шагом является преобразование извлеченного изображения в оттенки серого с помощью встроенной функции opencv под названием cvtColor. Затем мы преобразуем абсолютное значение серого цвета в ноль. Что он делает, так это то, что там, где есть разница, он становится белым, а там, где нет разницы, он становится черным.

gray = cv2.cvtColor(diff.astype(np.uint8), cv2.COLOR_BGR2GRAY)
gray[np.abs(gray) < 10] = 0

Это этап, на котором мы закончили создание нашей маски и преобразуем ее обратно в черно-белую стадию, используя следующие строки кода (внутри основного цикла while). По сути, все значения, которые являются белыми и черными, необходимо преобразовать в значение 255, чтобы оно могло помочь нам в вычислениях.

fgmask = gray.astype(np.uint8)
fgmask[fgmask>0]=255

Следующим шагом будет инвертировать маску. Вы можете спросить, зачем мы это делаем.
Сейчас мы сосредоточимся на переднем плане маски и на заднем плане маски. Таким образом, используя этот фоновый маси, мы собираемся заменить исходное изображение/видеопоток. Это будет сделано с помощью оператора bitwise_not в opencv. Это вынесет только то, что необходимо, с переднего плана на задний план. Но весь смысл инвертирования в том, чтобы мы могли использовать его в качестве переднего плана.

#invert the mask
fgmask_inv = cv2.bitwise_not(fgmask)

ПРИМЕЧАНИЕ. ПОСКОЛЬКУ В ОТНОШЕНИИ ПЕРЕДНЕГО И ФОНОВОГО ОБРАЗОВ ПОЛУЧИЛОСЬ НЕМНОГО ЗАБЛУЖДЕНИЯ, наберитесь терпения и прочитайте весь код в конце блога, и он станет понятнее.

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

#use the masks to extract the relevant parts from FG and BG
fgimg = cv2.bitwise_and(img,img,mask = fgmask)
bgimg = cv2.bitwise_and(bg,bg,mask = fgmask_inv)

Далее следует простое добавление этих извлеченных функций.

#combine both the BG and the FG images
dst = cv2.add(bgimg,fgimg)

Последний и последний шаг нашего основного цикла while — отображение изображения с помощью нашего cv2.imshow. Просто скопируйте следующий фрагмент кода в конец цикла как есть.

cv2.imshow('Background Removal',dst)
key = cv2.waitKey(5) & 0xFF
if ord('q') == key:
    break
elif ord('d') == key:
    flag = 1
    print("Background Captured")
elif ord('r') == key:
    flag = 0
    print("Ready to Capture new Background")
cv2.destroyAllWindows()
video.release()

Ниже приведены несколько скриншотов реализации вышеописанного алгоритма.

Если вы заметили на скриншотах, там огромная пустота из-за того, что там была моя голова, которая была идентифицирована как фон. Я приложил исходный код и ссылку на мой github ниже для исходного кода следующего проекта.

Это все на сегодня. Спасибо за чтение.

Ваше здоровье.