Проект удаления фона с использованием 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 ниже для исходного кода следующего проекта.
Это все на сегодня. Спасибо за чтение.
Ваше здоровье.