opencv学习之基于背景提取等目标跟踪算法#20190704

/* ***********************************************************************************************************************
任务目标:
基于背景提取的目标跟踪算法实践及代码分析。
*********************************************************************************************************************** */

include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

int labelTargets(Mat &src, Mat &mask, int thresh = 100);
// 在自定义函数模块声明中对thresh的值进行了赋值

int main()
{
char fn = "D:\CommonSoftware\OpenCV\Workplace\Example2_track\vtest.avi";
// 指针
fn指向视频地址,此处使用的是OpenCV库中自带的视频
VideoCapture cap; // 定义VideoCapture类用以打开指定视频
Mat source, image, foreGround, backGround, fgMask;
// Mat类:原始视频、缩放后视频、前景、背景、掩膜
Ptr pBgModel =
createBackgroundSubtractorMOG2().dynamicCast();
/* ********************************************************************************************************************
1. 此处采用了模板类的概念,变量"pBgModel"是一个指向"BackgroundSubtractor"对象的指针。
这里的Mat.Ptr(i)[j]并未指定相应"i"和"j"的值,所以默认值都为0,即指向Mat第一行的第一个元素。
2. OpenCV中不止有一种背景提取方法,但是所有的背景提取方法都归结为同一个基类"BackgroundSubtractor",
具体所采用的方法为"creatBackgroundSubtractorMOG2"。
3. "creatBackgroundSubtractorMOG2()"对"pBgModel"指针进行初始化,将其初始化成混合高斯模型。(注
意:在OpenCV 3.0以后的版本中不再含有"BackgroundSubtractorMOG"模型。)
4. 利用C++中的"dynamicCast"函数将pBgModel指针所指的内容动态的转换成"BackgroundSubtractor"型,
并检测是否成功。这里"BackgroundSubtractor"是一个类的引用,所以"()"中也需要放入一个类的引用,否则
抛出一个异常。
******************************************************************************************************************** */

cap.open(fn);

/* ********************************************************************************************************************
1. 使用cap类的open函数打开指针fn所指的视频
2. cap.open()中()内也可以放入数字,而放入数字代表的是接入几号摄像机的视频,该摄像机必须支持windows
的VFW。而且摄像机的编号是从0开始的。
******************************************************************************************************************* */
if (!cap.isOpened()) // cap类的isOpened函数查看是否成功打开
cout << "Cannot open the file: " << fn << endl;

for (; ; )  // 强制循环
{
    cap >> source;  // 将cap提取到的当前帧传给source(原始图像)
    if (source.empty())  // 如果原始图像为空,即视频已结束
    {
        break;  // 直接跳出循环
    }

    resize(source, image, Size(source.cols / 2, source.rows / 2), INTER_LINEAR);
    // 如果原始图像不为空,调用resize函数改变原始图像尺寸,方式为"线性差值法"

    if (foreGround.empty())
    {   // 通过前景是否为空,判断当前帧是否为视频开始
        foreGround.create(image.size(), image.type());
    }   // 如果是视频开始,则为"前景图像"创建矩阵空间,此处是按照原始图像的缩放图像的尺寸和类型进行初始化

    pBgModel->apply(image, fgMask);

/* *********************************************************************************************************************
在这里pBgModel这个指针在定义时已经设定好了处理模式,而"apply"函数会实时的将"pBgModel"中的当前帧
缩放图像"image"采用pBgModel的方式进行处理,并提取fgMask,即前景的掩膜。
********************************************************************************************************************* */

    GaussianBlur(fgMask, fgMask, Size(5, 5), 0);  // 利用高斯滤波器对前景的掩膜做平滑降噪
    threshold(fgMask, fgMask, 30, 255, THRESH_BINARY);  // 通过阈值化去除掩膜中灰度小于30的像素

    foreGround = Scalar::all(0);  // 利用"Scalar"函数将所创建的前景矩阵空间中所有元素赋初值0
    image.copyTo(foreGround, fgMask);  // 标记运动目标

/* **********************************************************************************************************************
调用Mat类的copyTo()函数,仅将原始图像的缩放图像(image)中的掩膜部分(fgMask)复制到前景图像中。
********************************************************************************************************************** */

    int nTargets = labelTargets(image, fgMask);
    cout << "There are " << nTargets << " targets." << endl;

    pBgModel->getBackgroundImage(backGround);

/* ***********************************************************************************************************************
这里使用了getBackgroundImage()函数,其会从pBgModel设定的模型中提取出背景。
*********************************************************************************************************************** */

    imshow("Sized Image", image);  // 显示原始图像的缩放图像。
    imshow("Background", backGround);  // 显示背景图像。
    imshow("Foreground", foreGround);  // 显示前景图像。
    imshow("Foreground Mask", fgMask);  // 显示前景图像的掩膜。

    char key = waitKey(100);  // 每一帧等待100毫秒
    if (key == 27)  // 如果想中途终止程序,按"Esc"退出
    {
        break;
    }
}

waitKey(0);  // 程序执行结束后防止闪退

}

int labelTargets(Mat &src, Mat &mask, int thresh) // 自定义的目标标记函数
{
Mat seg = mask.clone(); // 将掩膜复制到seg当中
vector<vector > cnts; // 定义了二维点类型变量cuts
findContours(seg, cnts, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 调用findContours()函数对掩膜复制图像seg中的Blob进行检测,检测方式是忽略内部边缘仅识别外部边缘

// 以下进行筛选
float area;  // 定义浮点型area变量用以存放单一Blob外围边缘所围面积
Rect rect;
int count = 0;  // 定义整型变量用以计数
string strCount;  // 定义字符串型变量
for (int i = cnts.size() - 1; i >= 0; i--)
{  // 调用vector的size()函数以检测cnts第一维的个数,即Blob个体数,并对其进行循环处理
    vector<Point> c = cnts[i];  // 定义一维点类型变量c用以存放Blob个体,即一维cnts集合
    area = contourArea(c);  // 调用contourArea()函数计算该单一Blob外围边缘所围面积
    if (area < thresh) // 滤除面积小于10的分割结果:可能是噪声
    {
        continue;
    }

    count++; // 统计米粒数量
    cout << "blob " << i << " : " << area << endl;
    rect = boundingRect(c);  // 创建包围矩形数据
    // 在原始图像上画出包围矩形,并给每个矩形标号
    rectangle(src, rect, Scalar(0, 0, 0xff), 1);
    // 调用rectangle()函数在src图像中,把rect包围矩形用红色,1个像素粗细的线框包围起来

    stringstream ss;  // 定义字符流变量"ss",作用是将指定字符串生成输入或输出流
    ss << count;  // 将计数数据传递给字符流
    ss >> strCount;  // 将字符流中的数据传送给字符串变量
    putText(src, strCount, Point(rect.x, rect.y), CV_FONT_HERSHEY_PLAIN, 0.5, Scalar(0, 0xff, 0));
    // 调用putText函数,在src图像上将strCount字符串输出在矩形框左上角,并定义了字体和字号和颜色
}

return count;

}

OpenCV中Mat类的指针ptr的使用:

  1. 定义Mat型的类”image”,1)image.ptr(0),指向image第1行第1个元素的指针;2)image.ptr(1),指向image的第2行第1个元素的指针;3)image.ptr(0)[1],指向image第1行第2个元素的指针。
  • 注意:在使用image.ptr()[]指针的时候,要注意防止索引值溢出(cv::Exception)。
  1. dynamic.cast的用法:
  • 将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理。
  • 例如:dynamic_cast (expression);

? 该运算符把expression转换成type-id类型的对象。

? Type-id 必须是类的指针、类的引用或者void*。

? 如果 type-id 是类指针类型,那么expression也必须是一个指针,(对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针)。如果 type-id 是一个引用,那么 expression 也必须是一个引用(对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用)。

? dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
转自 neilkuang

原文地址:https://www.cnblogs.com/ax204/p/11133555.html

时间: 2024-10-07 22:14:22

opencv学习之基于背景提取等目标跟踪算法#20190704的相关文章

基于粒子滤波器的目标跟踪算法及实现

代码实现: 运行方式:按P停止,在前景窗口鼠标点击目标,会自动生成外接矩形,再次按P,对该选定目标进行跟踪. [cpp] view plaincopy // TwoLevel.cpp : 定义控制台应用程序的入口点. // /************************************************************************/ /*参考文献real-time Multiple Objects Tracking with Occlusion Handli

基于mean shift的目标跟踪算法

Mean shift 算法是一种半自动跟踪方法在起始跟踪帧通过手工确定搜索窗口来选择运动目标计算核函数加权下的搜索窗口的直方图分布用同样的方法计算当前帧对应窗口的直方图分布以两个分布的相似性最大为原则使搜索窗口沿密度增加最大的方向移动目标的真实位置. 加权直方图 传统直方图仅仅统计落入直方图区间的像素的个数,而加权直方图进一步考虑了像素与目标中心的距离,远离目标中心的像素对直方图的贡献较小. 带空间位置信息的加权直方图的思想就是:在计算直方图时,给每个点赋予一定的权值,权值的大小根据它离中心点的

基于MeanShift的目标跟踪算法及实现

一.简介 首先扯扯无参密度估计理论,无参密度估计也叫做非参数估计,属于数理统计的一个分支,和参数密度估计共同构成了概率密度估计方法.参数密度估计方法要求特征空间服从一个已知的概率密度函数,在实际的应用中这个条件很难达到.而无参数密度估计方法对先验知识要求最少,完全依靠训练数据进行估计,并且可以用于任意形状的密度估计.所以依靠无参密度估计方法,即不事先规定概率密度函数的结构形式,在某一连续点处的密度函数值可由该点邻域中的若干样本点估计得出.常用的无参密度估计方法有:直方图法.最近邻域法和核密度估计

目标跟踪算法综述

转自  https://www.zhihu.com/question/26493945 作者:YaqiLYU 第一部分:目标跟踪速览 先跟几个SOTA的tracker混个脸熟,大概了解一下目标跟踪这个方向都有些什么.一切要从2013年的那个数据库说起..如果你问别人近几年有什么比较niubility的跟踪算法,大部分人都会扔给你吴毅老师的论文,OTB50和OTB100(OTB50这里指OTB-2013,OTB100这里指OTB-2015,50和100分别代表视频数量,方便记忆): Wu Y, L

视频目标跟踪算法综述

视频跟踪:基于对比度分析的目标跟踪.基于匹配的目标跟踪和基于运动检测的目标跟踪      基于对比度分析的目标跟踪:主要利用目标和背景的对比度差异实现目标的检测与跟踪.这类算法按照跟踪参考点的不同可以分为边缘跟踪# 形心跟踪和质心 跟踪等.这类算法不适合复杂背景中的目标跟踪"但在空中背景下的目标跟踪中非常有效. 基于匹配的目标跟踪:主要通过前后帧之间的特征匹配实现目标的定位.   特征匹配:特征是目标可区别与其他事物的属性, 具有可区分性.可靠性.独立性和稀疏性.基于匹配的目标跟踪算法需要提取目

挑战目标跟踪算法极限,SiamRPN系列算法解读

商汤科技智能视频团队首次开源其目标跟踪研究平台 PySOT.PySOT 包含了商汤科技 SiamRPN 系列算法,以及刚被 CVPR2019 收录为 Oral 的 SiamRPN++.此篇文章将解读目标跟踪最强算法 SiamRPN 系列. 背景 由于存在遮挡.光照变化.尺度变化等一些列问题,单目标跟踪的实际落地应用一直都存在较大的挑战.过去两年中,商汤智能视频团队在孪生网络上做了一系列工作,包括将检测引入跟踪后实现第一个高性能孪生网络跟踪算法的 SiamRPN(CVPR 18),更好地利用训练数

寻找目标跟踪算法(1)

目标跟踪算法 从知乎的一个帖子开始 计算机视觉中,目前有哪些经典的目标跟踪算法?(https://www.zhihu.com/question/26493945) 跟踪算法比较 Visual Tracker Benchmark:http://www.visual-tracking.net/ 经典算法: Mean-shift, Particle Filter, Ensemble Tracking,TLD, 压缩感知跟踪,KCF Tracker及其改进 KCF(opencv里集成了) http://

目标跟踪算法----KCF进阶(基于KCF改进的算法总结)

一.前情提要 如果你对目标跟踪和KCF是什么东西还不了解的话欢迎你看前一篇博文KCF入门详解:http://blog.csdn.net/crazyice521/article/details/53525366.如果你已经对基于KCF的目标跟踪有了一定的了解,并想知道这个算法有怎么样的后续的发展的话,就请听我慢慢介绍以下的东西. 二.KCF的弊端 说道KCF的缺点的话作者在文章中也已经算是说明了,第一点,KCF因为在跟踪过程当中目标框是已经设定好的,从始至终大小为发生变化,但是我们的跟踪序列当中目

TLD(Tracking-Learning-Detection)一种目标跟踪算法

原文:http://blog.csdn.net/mysniper11/article/details/8726649 视频介绍网址:http://www.cvchina.info/2011/04/05/tracking-learning-detection/ TLD(Tracking-Learning-Detection)是英国萨里大学的一个捷克籍博士生Zdenek Kalal在其攻读博士学位期间提出的一种新的单目标长时间(long term tracking)跟踪算法.该算法与传统跟踪算法的显