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

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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)。

2. 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。

相关文档
最新文档