OpenCV-Python系列之背景分离
从本次教程开始,我们进入新的篇章,之前一直在讨论OpenCV的特征部分,这次我们来讨论OpenCV中的背景分离,又称背景减法模型。
背景分离(BS)是一种通过使用静态相机来生成前景掩码(即包含属于场景中的移动对象像素的二进制图像)的常用技术。
顾名思义,BS计算前景掩码,在当前帧与背景模型之间执行减法运算,其中包含场景的静态部分,或者更一般而言,考虑到所观察场景的特征,可以将其视为背景的所有内容。
背景建模包括两个主要步骤:
1. 背景初始化;
2. 背景更新。
初步,计算背景的初始模型,而在第二步中,更新模型以适应场景中可能的变化。
在本教程中,我们将学习如何使用OpenCV中的BS。
OpenCV中的使用
OpenCV 中已经包含了其中三种比较容易使用的方法,我们逐一来看。
BackgroundSubtractorMOG
这是一个以混合高斯模型为基础的前景/背景分割算法。它是 P.KadewTraKuPong 和 R.Bowden 在 2001 年提出的。
它使用 K(K=3 或 5)个高斯分布混合对背景像素进行建模。使用这些颜色(在整个视频中)存在时间的长短作为混合的权重。背景的颜色一般持续的时间最长,而且更加静止。
一个像素怎么会有分布呢?在 x,y平面上一个像素就是一个像素,没有分布,但是我们现在讲的背景建模是基于时间序列的,因此每一个像素点所在的位置在整个时间序列中就会有很多值,从而构成一个分布
在编写代码时,我们需要使用函数:cv2.createBackgroundSubtractorMOG() 创建一个背景对象。这个函数有些可选参数,比如要进行建模场景的时间长度,高斯混合成分的数量,阈值等。将他们全部设置为默认值。然后在整个视频中我们是需要使用backgroundsubtractor.apply() 就可以得到前景的掩模了
移动的物体会被标记为白色,背景会被标记为黑色的,前景的掩模就是白色的了。
不过目前这个方法已经被弃用了,OpenCV中也没有了相关函数的API。
BackgroundSubtractorMOG2
这个也是以高斯混合模型为基础的背景/前景分割算法。它是以 2004 年 和 2006 年 Z.Zivkovic 的两篇文章为基础的。这个算法的一个特点是它为每 一个像素选择一个合适数目的高斯分布。(上一个方法中我们使用是 K 高斯分布)。
这样就会对由于亮度等发生变化引起的场景变化产生更好的适应。
和前面一样我们需要创建一个背景对象。但在这里我们我们可以选择是否检测阴影。如果 detectShadows = True(默认值),它就会检测并将影子标记出来,但是这样做会降低处理速度。影子会被标记为灰色。
BackgroundSubtractorMOG2算法的两个改进点:
-阴影检测
-速度快了一倍
我们将使用官方提供的人体跟踪的视频:
这个我提供在这儿:
我们来看代码:
def MOG2(): cap = cv2.VideoCapture("test.avi") fgbg = cv2.createBackgroundSubtractorMOG2() while (1): ret, frame = cap.read() fgmask = fgbg.apply(frame) cv2.imshow('frame', fgmask) k = cv2.waitKey(100) & 0xff if k == 27: break cap.release() cv2.destroyAllWindows()
结果:
可以看到基本的行人与背景分离出来了。
BackgroundSubtractorGMG
此算法结合了静态背景图像估计和每个像素的贝叶斯分割。这是 2012 年 Andrew_B.Godbehere,Akihiro_Matsukawa 和 Ken_Goldberg 在文章 中提出的。
它使用前面很少的图像(默认为前 120 帧)进行背景建模。使用了概率前 景估计算法(使用贝叶斯估计鉴定前景)。这是一种自适应的估计,新观察到的 对象比旧的对象具有更高的权重,从而对光照变化产生适应。一些形态学操作 如开运算闭运算等被用来除去不需要的噪音。在前几帧图像中你会得到一个黑 色窗口。
对结果进行形态学开运算对与去除噪声很有帮助。
不过同样的,这个方法目前也是不再用了。
BackgroundSubtractorKNN
KNN作为大名鼎鼎的机器学习算法,其用在背景分离应用中也是得心应手,但是在此不对KNN作过多的解释,它属于机器学习的一个算法,比较复杂,我们来看代码:
def KNN(): cap = cv2.VideoCapture('test.avi') fgbg = cv2.createBackgroundSubtractorKNN() while (1): ret, frame = cap.read() fgmask = fgbg.apply(frame) cv2.imshow('frame', fgmask) k = cv2.waitKey(100) & 0xff if k == 27: break cap.release() cv2.destroyAllWindows()
结果:
实验结果发现KNN的结果要明显优于MOG2算法。