基于OpenCV创建视频会议虚拟背景
重磅干货,第一时间送达
本期我们将使用Python和OpenCV为视频会议创建虚拟背景。
虚拟背景是当前远程工作的员工中的热门话题之一。由于Covid-19的流行,许多人必须通过视频通话以便继续工作。很多视频会议的软件可以设置虚拟背景,以便用户建立更友好的氛围来接听这些电话。
作为一名程序员,当我们第一次使用这样的虚拟背景时自然很感兴趣。我们都想知道它是如何工作的,可以自己建立这样的虚拟背景吗?
接下来,我们将尝试使用Python和OpenCV使用计算机视觉技术构建虚拟背景的基本方法。(虽然效果并不是很好~)
介绍
我们的目的是拍摄视频,尝试弄清楚视频的背景和前景,删除背景部分,并用图片(虚拟背景)代替。因为在此项目中,我们将使用简单的方法,假设前景通常具有与背景不同的颜色。首先,让我们看看我们的工具是什么。
计算机视觉
计算机视觉是一个跨学科领域,涉及计算机如何处理和(或)理解图像和视频。说这是一个跨学科的领域,因为它借鉴了不同学科(计算机科学,代数,几何等)的许多概念,并将它们组合起来以解决许多不同而复杂的任务,例如对象跟踪,对象检测, 对象识别,图片和视频中的对象细分。
OpenCV
OpenCV是一个用于解决计算机视觉任务的库。它是开源的,可用于多种编程语言,包括Python和C ++。它具有大量的计算机视觉功能,其中一些基于数学和统计方法,而另一些则基于机器学习。
建立虚拟背景
我为此尝试的方法如下。我将显示每个步骤的代码片段,并在本文结尾处,您将获得完整的代码。
1. 导入依赖
import numpy as np
import cv2
2.从本地环境加载视频并初始化数据
ap = cv2.VideoCapture('video6.mp4')
ret = True
frameCounter = 0
previousFrame = None
nextFrame = None
iterations = 0
3.从本地环境加载替代背景图像
backgroundImage = cv2.imread("image1.jpg")
4.逐帧分割视频
while (ret):
ret, frame = cap.read()
5.每隔两帧拍摄一次
if frameCounter % 2 == 1:
nextFrame = frame
if frameCounter % 2 == 0:
frameCounter = 0
previousFrame = frame
frameCounter = frameCounter + 1
iterations = iterations + 1
6.找到两个帧之间的绝对差并将其转换为灰度->获得蒙版
if iterations > 2:
diff = cv2.absdiff(previousFrame, nextFrame)
mask = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
每个图像都由像素组成,我们可以将其想象为具有行和列的2D矩阵,并且矩阵中的每个单元格都是图像中的像素(当然,对于彩色图像,我们拥有的尺寸比2大,但为简单起见,可以忽略)。
我们通过在第一个图像中逐个像素移动(因此在第一矩阵中一个单元一个像素)并从另一个图像中替换对应的像素(因此从另一个矩阵中替换对应的像素)来获得差异。
现在的诀窍是:如果在两帧之间,像素没有被修改,那么结果当然是0。两帧之间的像素如何变化?如果视频是完全静态的(图像中没有任何动静),则所有像素的每一帧之间的差将为0,因为没有任何更改。但是,如果某物在图像中移动,那么我们可以通过检测像素差异来识别某物在图像中的移动位置。我们可以假设,在视频会议中,移动的事物位于前台(即您),而静态部分是背景。
那么0到底有什么重要呢?图像将为每个像素显示为0的黑色,我们将利用这一优势。
7.找到蒙版中超出阈值的单元格-我选择3作为阈值,当然也可以使用不同的值。较大的值将从背景中删除更多内容,但也可能从前景中删除更多内容
th = 3
isMask = mask > th
nonMask = mask <= th
8.创建一个空白图像(每个单元格为0),其大小为两个框架中任何一个的大小
result = np.zeros_like(nextFrame, np.uint8)
9.调整背景图像的大小,使其具有与框架相同的大小
resized = cv2.resize(backgroundImage, (result.shape[1], result.shape[0]), interpolation = cv2.INTER_AREA)
10.对于蒙版中大于阈值的每个单元,请从原始帧进行复制
result[isMask] = nextFrame[isMask]000000000000
11.对于蒙版中低于阈值的每个单元,请从替代背景图像进行复制
result[nonMask] = resized[nonMask]
12.将结果框保存到本地环境
cv2.imwrite("output" + str(iterations) + ".jpg", result)
结果与结论
那么结果如何呢?老实说,我对结果感到有些失望。然后,我做了更多的研究,其原因变得更加明显。为此,您需要一种更高级的方法,并且大公司在此类问题上投入了大量资源也就不足为奇了。
这是我尝试的视频的屏幕截图。这基本上是我的手在墙前移动的视频。
虚拟背景Python和OpenCV教程-输入
这是输出图像的屏幕截图。作为背景,我在罗马尼亚的拉斯诺夫使用了我的照片。
虚拟背景Python和OpenCV教程-输出
结果并不满意,但是我们也从这个项目中学到的东西。
创建虚拟背景的其他方法
如果认为问题非常复杂,并且需要的智能水平,那么答案可能是机器学习。
已有深度学习模型可以执行此类任务。但是,这样的模型需要训练大量的数据集和大量的处理能力,在撰写本文时,我还没有这些能力做这种尝试。这种深度学习模型要解决的任务称为图像分割。
另一种方法是计算机视觉方法,用于查找相机和图像中的对象之间的距离。然后,建立一个阈值,以将前景与背景分开。之后,可以使用与移除背景相同的蒙版,并引入一个新的蒙版。
交流群