文章目录
前言
前景/背景分割法提取前景物体的方法比较简单,适用于背景相对固定的简易场景。但是在很多情况下,背景中的某些部位会在不同的值之间波动,导致背景检测结果频繁出错。背景物体的移动(如树叶)、刺眼的物体(如水面)等因素都是产生这种现象的原因。物体的阴影也会带来问题,因为阴影也是会移动的。为了解决这些问题,我们引入了更复杂的背景模型。
提示:以下是本篇文章正文内容,下面案例可供参考
一、混合高斯模型是什么?
混合高斯方法是这些改进型算法中的一种。它的处理方式与前面介绍的基本一致,但做了几项改进。
首先,该方法适用于每个像素有不止一个模型(即不止一个滑动平均值)的情况。这样的话,如果—个背景像素在两个值之间波动,那么就会储存两个滑动平均值。只有当新的像素值不属于任何一个频繁出现的模型时,才会认为这个像素是前景。模型的数量可以在参数中设置,通常为5个。
其次,每个模型不仅保存了滑动平均值,还保存了滑动均差。它的计算方式如下所示:
计算得到的平均值和方差用于构建高斯模型,根据高斯模型就可计算某个像素值属于背景的概率。用概率替代绝对差值后,阈值的选择就会更加容易。这样.如果某个区域的背景波动较大,就需要有更大的差值才能被认定为前景物体。
最后,这是一个自适应模型。也就是说.如果某个高斯模型满足条件的概率不够高,它就会被排除在背景模刑之外,反之,如果发现一个像素值在当前背景模型之外(即为一个前景像素),那么就会创建一个新的高斯模型。如果这个新建的模型随后频繁收到像素,就把它作为正确的背景模型。
二、API
混合高斯模型API,提取运动目标
//应用时需要加上头文件 #include <opencv2/bgsegm.hpp>
cv::Ptr<cv::BackgroundSubtractor> ptrMOG = cv::bgsegm::createBackgroundSubtractorMOG();
ptrMOG->apply(frame, frame, 0.03);
检测并画出轮廓API
cv::findContours(imgl, contours, cv::RETR_LIST, cv::CHAIN_APPROX_NONE); //检测轮廓点
r0 = cv::boundingRect(contours[i]); //通过检测到的轮廓点形成矩形
cv::drawContours(imglo, contours, -1, 0, 2); //画出轮廓点
计算矩
cv::Moments mom = cv::moments(contours[i]);//计算轮廓的矩
cv::Point center = cv::Point(mom.m10 / mom.m00, mom.m01 / mom.m00);//轮廓的质心
cv::circle(imglo, center, 2, cv::Scalar(0, 0, 255), 2);//画出质点
1.代码
代码如下(示例):
int main()
{
cv::VideoCapture cap("D:\\桌面\\代码区\\20201206132227.avi");
cv::Mat imglo, imgro, imgl,imgr,frame,background;
bool status = true;
cv::Ptr<cv::BackgroundSubtractor> ptrMOG = cv::bgsegm::createBackgroundSubtractorMOG();
while (status)
{
cap >> frame;
clock_t start, end;
start= clock();
int w = frame.cols;
int h = frame.rows;
if (frame.empty())
{
break;
}
cv::GaussianBlur(frame, frame, cv::Size(5, 5), 0, 0);
cv::Mat kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cv::filter2D(frame, frame, -1, kernel);
imglo = frame;
ptrMOG->apply(frame, frame, 0.03);
cv::threshold(frame, frame, 100, 255, cv::THRESH_BINARY_INV);
//cv::dilate(frame, frame, cv::Mat());
cv::erode(frame, frame, cv::Mat());
cv::imshow("frame", frame);
imgl = frame;
std::vector<std::vector<cv::Point>> contours;
cv::findContours(imgl, contours, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
int max_s = 0;
cv::Rect r0,r1;
for (int i = 0; i < contours.size(); i++)
{
r0 = cv::boundingRect(contours[i]);
if (r0.area() < w*h && r0.area() > 2200)
{
cv::rectangle(imglo, r0, 0, 2);
cv::Moments mom = cv::moments(contours[i]);//轮廓的矩
cv::Point center = cv::Point(mom.m10 / mom.m00, mom.m01 / mom.m00);//轮廓的质心
cv::circle(imglo, center, 2, cv::Scalar(0, 0, 255), 2);
}
}
/*for (int i = 0; i < contours.size(); i++)
{
r0 = cv::boundingRect(contours[i]);
if (r0.area()>max_s && r0.area()<w*h && r0.area()>10)
{
max_s=r0.area();
r1 = r0;
}
}
cv::rectangle(imglo, r1, 0, 2);*/
//cv::findContours(imgl, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
//cv::drawContours(imglo, contours, -1, 0, 2);
end = clock(); //程序结束用时
double endtime = (double)(end - start) / CLOCKS_PER_SEC;
cout << "Total time:" << endtime << endl; //s为单位
cv::imshow("L", imglo);
if (cv::waitKey(30) > 0)
{
status = false;
}
}
//system("pause");
return 0;
}