opencv学习之路(37)、运动物体检测(二)
一、运动物体轮廓椭圆拟合及中心
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv; Mat MoveDetect(Mat frame1, Mat frame2)
{
Mat result = frame2.clone();
Mat gray1, gray2;
cvtColor(frame1, gray1, CV_BGR2GRAY);
cvtColor(frame2, gray2, CV_BGR2GRAY); Mat diff;
absdiff(gray1, gray2, diff);
imshow("absdiss", diff);
threshold(diff, diff, , , CV_THRESH_BINARY);
imshow("threshold", diff); Mat element = getStructuringElement(MORPH_RECT, Size(, ));
Mat element2 = getStructuringElement(MORPH_RECT, Size(, ));
erode(diff, diff, element);
imshow("erode", diff); dilate(diff, diff, element2);
imshow("dilate", diff); vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
//画椭圆及中心
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
vector<RotatedRect> box(contours.size());
for(int i=; i<contours.size(); i++)
{
box[i] = fitEllipse(Mat(contours[i]));
ellipse(result, box[i], Scalar(, , ), , );
circle(result, box[i].center, , Scalar(, , ), -, );
}
return result;
} void main()
{
VideoCapture cap("E://man.avi");
if(!cap.isOpened()) //检查打开是否成功
return;
Mat frame;
Mat result;
Mat background;
int count=;
while()
{
cap>>frame;
if(frame.empty())
break;
else{
count++;
if(count==)
background = frame.clone(); //提取第一帧为背景帧
imshow("video", frame);
result = MoveDetect(background, frame);
imshow("result", result);
if(waitKey()==)
break;
}
}
cap.release();
}
和上一篇文章代码的不同点在30-38行,天台行人视频适合用背景减法处理,自行车视频适合帧差法处理

二、滤波方法去除噪声
上篇文章中使用腐蚀膨胀消除噪声,这次使用滤波方法去除噪声
中值滤波
//二值化后使用中值滤波+膨胀
Mat element = getStructuringElement(MORPH_RECT, Size(, ));
medianBlur(diff, diff, );//中值滤波
imshow("medianBlur", diff);
dilate(diff, diff, element);
imshow("dilate", diff);

均值滤波
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv; //int to string helper function
string intToString(int number)
{
stringstream ss;
ss << number;
return ss.str();
} Mat MoveDetect(Mat background, Mat img)
{
Mat result = img.clone();
Mat gray1, gray2;
cvtColor(background, gray1, CV_BGR2GRAY);
cvtColor(img, gray2, CV_BGR2GRAY); Mat diff;
absdiff(gray1, gray2, diff);
threshold(diff, diff, , , CV_THRESH_BINARY);
imshow("threshold", diff);
blur(diff, diff, Size(, ));//均值滤波
imshow("blur", diff); vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8); //绘制轮廓
int x0=, y0=, w0=, h0=;
for(int i=; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形 x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
//rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
circle(result, Point(x0+w0/, y0+h0/), , Scalar(, , ), , );
line(result, Point(x0+w0/-, y0+h0/), Point(x0+w0/+, y0+h0/), Scalar(, , ), , );
line(result, Point(x0+w0/, y0+h0/-), Point(x0+w0/, y0+h0/+), Scalar(, , ), , );
putText(result,"(" + intToString(x0+w0/)+","+intToString(y0+h0/)+")",Point(x0+w0/+, y0+h0/), , ,Scalar(,,),);
}
return result;
} void main()
{
VideoCapture cap("E://ball.avi");
if(!cap.isOpened()) //检查打开是否成功
return;
Mat frame;
Mat result;
Mat background;
int count=;
while()
{
cap>>frame;
if(frame.empty())
break;
else{
count++;
if(count==)
background = frame.clone(); //提取第一帧为背景帧
imshow("video", frame);
result = MoveDetect(background, frame);
imshow("result", result);
if(waitKey()==)
break;
}
}
cap.release();
}

三、轮廓筛选去除噪声(效果挺好的)
//其余代码相同
int x0=, y0=, w0=, h0=;
for(int i=; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形 x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
//筛选
if(w0> && h0>)
rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(, , ), , ); //绘制第i个外接矩形
}

四、运动轨迹绘制
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv; Point center;
Point fre_center;//存储前一帧中心坐标
int num=;
vector<Point> points; Mat MoveDetect(Mat background, Mat img)
{
Mat result = img.clone();
Mat gray1, gray2;
cvtColor(background, gray1, CV_BGR2GRAY);
cvtColor(img, gray2, CV_BGR2GRAY); Mat diff;
absdiff(gray1, gray2, diff);
imshow("absdiss", diff);
threshold(diff, diff, , , CV_THRESH_BINARY);
imshow("threshold", diff); Mat element = getStructuringElement(MORPH_RECT, Size(, ));
Mat element2 = getStructuringElement(MORPH_RECT, Size(, ));
erode(diff, diff, element);
imshow("erode", diff);
dilate(diff, diff, element2);
imshow("dilate", diff); vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8); //绘制轮廓
vector<RotatedRect> box(contours.size());
int x0=, y0=, w0=, h0=;
for(int i=; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形 x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
if(w0> && h0>)//筛选长宽大于30的轮廓
{
num++;
//rectangle(result, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
box[i] = fitEllipse(Mat(contours[i]));
ellipse(result, box[i], Scalar(, , ), , ); //椭圆轮廓
circle(result, box[i].center, , Scalar(, , ), -, ); //画中心
center = box[i].center;//当前帧的中心坐标
points.push_back(center);//中心塞进points向量集
if(num !=)
{
//line(result, fre_center, center, Scalar(255, 0, 0), 2, 8);
for(int j=; j<points.size()-; j++)
line(result, points[j], points[j+], Scalar(, , ), , );
}
//fre_center = center;
}
}
return result;
} void main()
{
VideoCapture cap("E://man.avi");
if(!cap.isOpened()) //检查打开是否成功
return;
Mat frame;
Mat background;
Mat result;
int count=;
while()
{
cap>>frame;
if(!frame.empty())
{
count++;
if(count==)
background = frame.clone(); //提取第一帧为背景帧
imshow("video", frame);
result = MoveDetect(background, frame);
imshow("result", result);
if(waitKey()==)
break;
}
else
break;
}
cap.release();
}

五、车辆数量检测
1.帧差法检测运动目标
2.预处理:a.转灰度图,绝对值做差 b.二值化,腐蚀,中值滤波,膨胀 c.查找轮廓,筛选轮廓,绘制外接矩形,计数,输出
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv; int CarNum = ;
//int to string helper function
string intToString(int number)
{
//this function has a number input and string output
stringstream ss;
ss << number;
return ss.str();
} Mat MoveDetect(Mat frame1, Mat frame2) {
Mat result = frame2.clone();
Mat gray1, gray2;
cvtColor(frame1, gray1, CV_BGR2GRAY);
cvtColor(frame2, gray2, CV_BGR2GRAY); Mat diff;
absdiff(gray1, gray2, diff);
//imshow("absdiss", diff);
threshold(diff, diff, , , CV_THRESH_BINARY);
imshow("threshold", diff); Mat element = getStructuringElement(MORPH_RECT, Size(, ));
Mat element2 = getStructuringElement(MORPH_RECT, Size(, ));
erode(diff, diff, element);
//imshow("erode", dst);
medianBlur(diff, diff, );
imshow("medianBlur", diff);
dilate(diff, diff, element2);
imshow("dilate", diff); vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(, ));//查找轮廓
vector<vector<Point>>contours_poly(contours.size());
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8); //绘制轮廓
int x0 = , y0 = , w0 = , h0 = ;
for (int i = ; i<contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_poly[i], , true);//对图像轮廓点进行多边形拟合:轮廓点组成的点集,输出的多边形点集,精度(即两个轮廓点之间的距离),输出多边形是否封闭
boundRect[i] = boundingRect(Mat(contours_poly[i]));
if (boundRect[i].width> && boundRect[i].width< && boundRect[i].height> && boundRect[i].height<) {//轮廓筛选
x0 = boundRect[i].x;
y0 = boundRect[i].y;
w0 = boundRect[i].width;
h0 = boundRect[i].height; rectangle(result, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(, , ), , , );
if ((y0 + h0 / + ) >= && (y0 + h0 / - ) <= ) {//经过这条线(区间),车辆数量+1
CarNum++;
}
}
line(result, Point(, ), Point(, ), Scalar(, , ), , );//画红线
Point org(, );
putText(result, "CarNum=" + intToString(CarNum), org, CV_FONT_HERSHEY_SIMPLEX, 0.8f, Scalar(, , ), );
}
return result;
} void main()
{
VideoCapture cap("E://2.avi");
if (!cap.isOpened()) //检查打开是否成功
return;
Mat frame;
Mat tmp;
Mat result;
int count = ;
while ()
{
cap >> frame;
if(frame.empty())//检查视频是否结束
break;
else{
count++;
if (count == )
result = MoveDetect(frame, frame);
else result = MoveDetect(tmp, frame);
imshow("video", frame);
imshow("result", result);
tmp = frame.clone();
if (waitKey() == )
break;
}
}
cap.release();
}

opencv学习之路(37)、运动物体检测(二)的更多相关文章
- opencv学习之路【四】——opencv文件结构介绍
这里要感谢这篇博主的文章 部分内容转载自此 opencv在2.3版本之前 都是用的c语言实现的 而在2.3以后的版本 做了很多重大的改变 其中最主要的是用c++重写大部分结构 然后文件的结构和2.0之 ...
- opencv学习之路(36)、运动物体检测(一)
一.简介 二.背景减法 图片说明 #include "opencv2/opencv.hpp"using namespace cv; void main() { Mat img1 = ...
- opencv学习之路(32)、角点检测
一.角点检测的相关概念 二.Harris角点检测——cornerHarris() 参考网址: http://www.cnblogs.com/ronny/p/4009425.html #include ...
- OpenCV 学习笔记03 直线和圆检测
检测边缘和轮廓不仅重要,还经常用到,它们也是构成其他复杂操作的基础. 直线和形状检测与边缘和轮廓检测有密切的关系. 霍夫hough 变换是直线和形状检测背后的理论基础.霍夫变化是基于极坐标和向量开展的 ...
- Opencv学习之路—Opencv下基于HOG特征的KNN算法分类训练
在计算机视觉研究当中,HOG算法和LBP算法算是基础算法,但是却十分重要.后期很多图像特征提取的算法都是基于HOG和LBP,所以了解和掌握HOG,是学习计算机视觉的前提和基础. HOG算法的原理很多资 ...
- opencv学习之路(41)、人脸识别
一.人脸检测并采集个人图像 //take_photo.cpp #include<opencv2/opencv.hpp> using namespace cv; using namespac ...
- opencv学习之路(35)、SURF特征点提取与匹配(三)
一.简介 二.opencv中的SURF算法接口 三.特征点匹配方法 四.代码 1.特征点提取 #include "opencv2/opencv.hpp" #include < ...
- opencv学习之路(34)、SIFT特征匹配(二)
一.特征匹配简介 二.暴力匹配 1.nth_element筛选 #include "opencv2/opencv.hpp" #include <opencv2/nonfree ...
- opencv学习之路(33)、SIFT特征点提取(一)
一.简介 二.OpenCV中的SIFT算法接口 #include "opencv2/opencv.hpp" #include <opencv2/nonfree/nonfree ...
随机推荐
- django项目同一用户不能同时登陆
1.session认证 ..... login(request, user) #登录成功 # 登录之后获取获取最新的session_key session_key = request.session. ...
- 杂_小技巧_将网页上的内容通过亚马逊邮箱传到kindle中
所需条件 1.kindle要联网 2.要有亚马逊邮箱 3.要有微信,电脑上或者手机上 操作步骤: 1.找到你想要传送到kindle上的文章网页 2.在微信中关注“亚马逊kindle服务号”并且按照里边 ...
- 微信小程序调用高德地图
index.wxml: longitude:经度 latitude:维度 地图所定位的区域 index.js 地图所定位的点
- MacBookPro磁盘空间不够
256G的SSD还是快被占满了,剩余12G,本来一切运行正常. 要往U盘里拷点资料,突然电脑就罢工了,cleanMyMac 显示磁盘容量剩余 1.8G. finder 罢工,无法重启,无法强退. 无法 ...
- jsp的环境搭建
JSP : 动态网页 一.静态和动态的区别: 1.是否会随着时间.地点.用户操作的改变而改变. 2.动态网页需要使用服务器端的脚本语言(JSP) 二.BS CS 1.CS:QQ.微信.CS游戏. 缺点 ...
- 常见查找算法(Java代码实现)
一,顺序查找 查找算法中顺序查找算是最简单的了,无论是有序的还是无序的都可以,只需要一个个对比即可,但其实效率很低.我们来看下代码 public static int search(int[] a, ...
- Python基础之 函数名,闭包,和迭代器
1.函数名作用 函数名本质上就是函数的内存地址或对象. 1.可以被引用 2.可以被当作容器类型的元素 3.可以当作函数的参数和返回值 4.如果记不住的话,那就记住一句话,就当普通变量用 2.闭包 什么 ...
- WEB服务器,TOMCAT和servlet之间的关系
WEB服务器,TOMCAT和servlet之间的关系 什么是WEB服务器Web服务器是指能够为发出请求的浏览器提供文档的程序.服务器是 一种被动程序,只有浏览器发出请求的时候才会响应.应用层使用 的是 ...
- 从零开始搭建一个vue.js的脚手架
在谷歌工作的时候,我们要做很多界面的原型,要求快速上手,灵活运用,当时用的一些现有框架,比如angular,太笨重了——尤雨溪(Vue.js 作者) vue.js是现在一个很火的前端框架,官网描述其简 ...
- C# 读取xml——XmlReader和XElement
1.有些xml文件头部有DTD,程序解析的时候会报错 如:其他信息: 打开外部 DTD“file:///E:/PM数据/MeContext=CDF2775/MeasDataCollection.dtd ...