如何使用背景减法
我们将学习如何从视频和图像序列中提取前景蒙版并展示它们。
背景减法(BS)是一种常用的和广泛使用的技术,用于生成前景遮罩(即,包含属于场景中移动物体的像素的二值图像)
顾名思义,BS计算前景遮罩执行当前帧和背景模型之间的减法,包括场景的静态部分,或者,更一般的,所有可以被认为是背景给定的观察场景的特征。
背景建模包括两个主要步骤:
背景初始化;
背景更新。
在第一步中,计算背景的初始模型,而在第二步中,模型被更新以适应场景中可能的变化。
在本教程中,您将学习如何:
使用cv::VideoCapture从视频或图像序列中读取数据;
使用cv::BackgroundSubtractor创建和更新背景模型;
使用cv::imshow获取和显示前景遮罩;
1.生成前景遮罩
Ptr<BackgroundSubtractor> pBackSub;
if (parser.get<String>("algo") == "MOG2")
pBackSub = createBackgroundSubtractorMOG2();
else
pBackSub = createBackgroundSubtractorKNN();
2.读取输入的视频或图像序列
VideoCapture capture( samples::findFile( parser.get<String>("input") ) );
if (!capture.isOpened()){
cerr << "Unable to open: " << parser.get<String>("input") << endl;
return 0;
}
3.每一帧都用于计算前景掩码和更新背景。如果您希望更改用于更新后台模型的学习率,可以通过向apply方法传递一个参数来设置特定的学习率
pBackSub->apply(frame, fgMask);
4.可以从cv::VideoCapture对象中提取当前帧号,并在当前帧的左上角打上戳记。一个白色的矩形用来突出黑色的帧号
rectangle(frame, cv::Point(10, 2), cv::Point(100,20),cv::Scalar(255,255,255), -1);
stringstream ss;
ss << capture.get(CAP_PROP_POS_FRAMES);
string frameNumberString = ss.str();
putText(frame, frameNumberString.c_str(), cv::Point(15, 15),FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0));
目标跟踪
在这一章,我们将学习在视频中跟踪对象的Meanshift和Camshift算法。
Meanshift
Meanshift原理很简单。假设你有一组点,给你一个小窗口(可能是一个圆),你必须移动窗口到最大像素密度(或最大点数)的区域。
使用meanshift,首先我们需要设置目标,找到它的直方图,这样我们就可以在每一帧上反向投影目标来计算meanshift。我们还需要提供窗口的初始位置。对于直方图,这里只考虑色相。另外,为了避免由于光线不足而产生的错误值,可以使用c.inrange()函数来丢弃光线不足的值。
Camshift
你密切关注最后的结果了吗?有一个问题。无论车离相机多远或多近,我们的窗口总是一样大,这是不好的。
我们需要根据目标的大小和旋转来调整窗口大小。同样,这个解决方案来自“OpenCV实验室”,它被称为CAMshift(连续自适应Meanshift),由Gary Bradsky在1998年[28]发表的论文《计算机视觉人脸跟踪用于感知用户界面》中发表。
它先应用meanshift。meanshift一旦收敛,则更新窗口大小。
它还计算了最佳拟合椭圆的方向。同样,它应用了新的缩放搜索窗口和先前窗口位置的meanshift。这个过程一直持续到满足要求的精度。
光流
我们将学习如何使用光流方法来跟踪稀疏特征或创建密集表示。
在这一章,
我们将理解光流的概念和使用Lucas-Kanade方法估计它。
我们将使用cv.calcOpticalFlowPyrLK()这样的函数来跟踪视频中的特征点;
我们将使用cv.calcOpticalFlowFarneback()方法创建一个密集的光流场。
光流
光流是指由于物体或相机的运动而引起的图像物体在连续两帧之间的视运动模式。它是一个二维向量场,其中每个向量都是一个位移向量,显示从第一帧到第二帧的点的运动。
光流在以下领域有很多应用:结构与运动、视频压缩、视频稳定
光流工作有几个假设:物体的像素强度在连续的帧之间不变化;相邻像素具有类似的运动;
cv.calcOpticalFlowPyrLK()中提供了所有这些功能。我们创建一个简单的应用程序来跟踪视频中的一些点。
为了确定这些点,我们使用了cv.goodFeaturesToTrack()。首先选取第一帧,检测其中的一些角点,然后利用Lucas-Kanade光流迭代跟踪这些角点。对于函数cv.calcOpticalFlowPyrLK(),我们传递前一帧、前一点和下一帧。
它返回下一个点以及一些状态号,如果找到下一个点,该状态号的值为1,否则为0。我们迭代地将这些下一个点作为下一个步骤中的前一个点传递。
Lucas-Kanade方法计算稀疏特征集的光流(在我们的例子中,使用Shi-Tomasi算法检测角落)。
OpenCV提供了另一种寻找密集光流的算法。它计算坐标系中所有点的光流。它基于炮手法内巴克的算法,该算法在2003年炮手法内巴克的“基于多项式展开的两帧运动估计”中得到了解释。