基于OpenCV创建视频会议虚拟背景

2020-09-22 15:21:18 浏览数 (1)

本期我们将使用Python和OpenCV为频会议创建虚拟背景。

虚拟背景是当前远程工作的员工中的热门话题之一。由于Covid-19的流行,许多人必须通过视频通话以便继续工作。很多视频会议的软件可以设置虚拟背景,以便用户建立更友好的氛围来接听这些电话。

作为一名程序员,当我们第一次使用这样的虚拟背景时自然很感兴趣。我们都想知道它是如何工作的,可以自己建立这样的虚拟背景吗?

接下来,我们将尝试使用PythonOpenCV使用计算机视觉技术构建虚拟背景的基本方法。(虽然效果并不是很好~)

介绍

我们的目的是拍摄视频,尝试弄清楚视频的背景和前景,删除背景部分,并用图片(虚拟背景)代替。因为在此项目中,我们将使用简单的方法,假设前景通常具有与背景不同的颜色。首先,让我们看看我们的工具是什么。

计算机视觉

计算机视觉是一个跨学科领域,涉及计算机如何处理和(或)理解图像和视频。说这是一个跨学科的领域,因为它借鉴了不同学科(计算机科学,代数,几何等)的许多概念,并将它们组合起来以解决许多不同而复杂的任务,例如对象跟踪对象检测, 对象识别,图片和视频中的对象细分

OpenCV

OpenCV是一个用于解决计算机视觉任务的库。它是开源的,可用于多种编程语言,包括Python和C 。它具有大量的计算机视觉功能,其中一些基于数学和统计方法,而另一些则基于机器学习。

建立虚拟背景

我为此尝试的方法如下。我将显示每个步骤的代码片段,并在本文结尾处,您将获得完整的代码。

1. 导入依赖

代码语言:javascript复制
import numpy as np
import cv2

2.从本地环境加载视频并初始化数据

代码语言:javascript复制
ap = cv2.VideoCapture('video6.mp4')
ret = True
frameCounter = 0
previousFrame = None
nextFrame = None
iterations = 0

3.从本地环境加载替代背景图像

代码语言:javascript复制
backgroundImage = cv2.imread("image1.jpg")

4.逐帧分割视频

代码语言:javascript复制
while (ret):
ret, frame = cap.read()

5.每隔两帧拍摄一次

代码语言:javascript复制
if frameCounter % 2 == 1:
           nextFrame = frame        
if frameCounter % 2 == 0:
           frameCounter = 0
           previousFrame = frame       
frameCounter = frameCounter   1
           iterations = iterations   1

6.找到两个帧之间的绝对差并将其转换为灰度->获得蒙版

代码语言:javascript复制
if iterations > 2:
  diff = cv2.absdiff(previousFrame, nextFrame)
  mask = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)

每个图像都由像素组成,我们可以将其想象为具有行和列的2D矩阵,并且矩阵中的每个单元格都是图像中的像素(当然,对于彩色图像,我们拥有的尺寸比2大,但为简单起见,可以忽略)。

我们通过在第一个图像中逐个像素移动(因此在第一矩阵中一个单元一个像素)并从另一个图像中替换对应的像素(因此从另一个矩阵中替换对应的像素)来获得差异。

现在的诀窍是:如果在两帧之间,像素没有被修改,那么结果当然是0两帧之间的像素如何变化?如果视频是完全静态的(图像中没有任何动静),则所有像素的每一帧之间的差将为0,因为没有任何更改。但是,如果某物在图像中移动,那么我们可以通过检测像素差异来识别某物在图像中的移动位置。我们可以假设,在视频会议中,移动的事物位于前台(即您),而静态部分是背景。

那么0到底有什么重要呢?图像将为每个像素显示为0的黑色,我们将利用这一优势。

7.找到蒙版中超出阈值的单元格-我选择3作为阈值,当然也可以使用不同的值。较大的值将从背景中删除更多内容,但也可能从前景中删除更多内容

代码语言:javascript复制
th = 3
isMask = mask > th
nonMask = mask <= th

8.创建一个空白图像(每个单元格为0),其大小为两个框架中任何一个的大小

代码语言:javascript复制
result = np.zeros_like(nextFrame, np.uint8)

9.调整背景图像的大小,使其具有与框架相同的大小

代码语言:javascript复制
resized = cv2.resize(backgroundImage, (result.shape[1], result.shape[0]), interpolation = cv2.INTER_AREA)

10.对于蒙版中大于阈值的每个单元,请从原始帧进行复制

代码语言:javascript复制
result[isMask] = nextFrame[isMask]000000000000

11.对于蒙版中低于阈值的每个单元,请从替代背景图像进行复制

代码语言:javascript复制
result[nonMask] = resized[nonMask]

12.将结果框保存到本地环境

代码语言:javascript复制
cv2.imwrite("output"   str(iterations)   ".jpg", result)

结果与结论

那么结果如何呢?老实说,我对结果感到有些失望。然后,我做了更多的研究,其原因变得更加明显。为此,您需要一种更高级的方法,并且大公司在此类问题上投入了大量资源也就不足为奇了。

这是我尝试的视频的屏幕截图。这基本上是我的手在墙前移动的视频。

虚拟背景Python和OpenCV教程-输入

这是输出图像的屏幕截图。作为背景,我在罗马尼亚的拉斯诺夫使用了我的照片。

虚拟背景Python和OpenCV教程-输出

结果并不满意,但是我们也从这个项目中学到的东西。

创建虚拟背景的其他方法

如果认为问题非常复杂,并且需要的智能水平,那么答案可能是机器学习。

已有深度学习模型可以执行此类任务。但是,这样的模型需要训练大量的数据集和大量的处理能力,在撰写本文时,我还没有这些能力做这种尝试。这种深度学习模型要解决的任务称为图像分割。

另一种方法是计算机视觉方法,用于查找相机和图像中的对象之间的距离。然后,建立一个阈值,以将前景与背景分开。之后,可以使用与移除背景相同的蒙版,并引入一个新的蒙版。

0 人点赞