多目标跟踪计数opencv(C++实现)
2017-08-08 17:44
483 查看
今天小博就把多目标检测,追踪,计数的代码贴出来供大家把玩,如有有疑问,可发邮件到1039463596@qq.com,欢迎提出批评指正:
我们先看一下追踪计数的效果吧
1. 算法目的:
运动目标跟踪算法的目的就是对视频中的图象序列进行分析,计算出目标在每帧图象上的位置。这里要根据区域分割过程给出的目标质心位置,计算出目标位移,并且根据质心位置的变化判断出目标的运动方向,以及运动目标是否在观察窗口,实现对客流量的统计。因为该跟踪是对多目标的追踪,需要找出运动目标在相邻帧上的对应区域。
系统具有固有噪声,目标周围背景的干扰可能会产生误差,但这些噪声在前面的过程已经去除,如有必要可做适当调整修正。
2. 算法难点:
(1)因为要跟踪的是多目标,需要找到相邻帧之间对应的运动目标区域不致跟踪混乱。
(2)如何判断运动目标区域是否是新的目标进入观测窗口
(3)运动目标是否离开了观测窗口以及离开的方向;即计数器何时加1、是否加1
(4)对跟踪过程中出现的一些偏差和问题,要进行必要的修正
3. 算法描述:
(1)跟踪首先要判断的是:帧与帧之间如何将运动目标对应起来。追踪过程中的追踪特
征是物体的质心(由运动区域分割过程中给出),这里判断对应目标可以:a.只利用质心间的最短距离做为特征; b.利用加权系数将最短距离,运动目标区域的长度,宽度以及长宽比和面积等综合起来作为特征。
(2)根据判断特征设置目标链,记录每个被跟踪目标的最新质心位置,为下步判断提供条件。另外将每个目标的质心位置存储起来,可以随时掌握目标的运动情况,为以后要输出目标的运动曲线做基础。
(3)每进入观察窗口一个新的运动目标,就将它的最新质心位置加入该目标链。如何判断该运动目标是新的:设置门限值ymin,ymax(当ymin
运动目标检测与卡尔曼滤波追踪结合的追踪方法实现了这一过程。。。`
我们先看一下追踪计数的效果吧
1. 算法目的:
运动目标跟踪算法的目的就是对视频中的图象序列进行分析,计算出目标在每帧图象上的位置。这里要根据区域分割过程给出的目标质心位置,计算出目标位移,并且根据质心位置的变化判断出目标的运动方向,以及运动目标是否在观察窗口,实现对客流量的统计。因为该跟踪是对多目标的追踪,需要找出运动目标在相邻帧上的对应区域。
系统具有固有噪声,目标周围背景的干扰可能会产生误差,但这些噪声在前面的过程已经去除,如有必要可做适当调整修正。
2. 算法难点:
(1)因为要跟踪的是多目标,需要找到相邻帧之间对应的运动目标区域不致跟踪混乱。
(2)如何判断运动目标区域是否是新的目标进入观测窗口
(3)运动目标是否离开了观测窗口以及离开的方向;即计数器何时加1、是否加1
(4)对跟踪过程中出现的一些偏差和问题,要进行必要的修正
3. 算法描述:
(1)跟踪首先要判断的是:帧与帧之间如何将运动目标对应起来。追踪过程中的追踪特
征是物体的质心(由运动区域分割过程中给出),这里判断对应目标可以:a.只利用质心间的最短距离做为特征; b.利用加权系数将最短距离,运动目标区域的长度,宽度以及长宽比和面积等综合起来作为特征。
(2)根据判断特征设置目标链,记录每个被跟踪目标的最新质心位置,为下步判断提供条件。另外将每个目标的质心位置存储起来,可以随时掌握目标的运动情况,为以后要输出目标的运动曲线做基础。
(3)每进入观察窗口一个新的运动目标,就将它的最新质心位置加入该目标链。如何判断该运动目标是新的:设置门限值ymin,ymax(当ymin
#include <iostream> #include <opencv2/opencv.hpp> //#include <opencv2/video/background_segm.hpp> using namespace std; using namespace cv; #define drawCross( img, center, color, d )\ line(img, Point(center.x - d, center.y - d), Point(center.x + d, center.y + d), color, 2, CV_AA, 0);\ line(img, Point(center.x + d, center.y - d), Point(center.x - d, center.y + d), color, 2, CV_AA, 0 )\ vector<Point> mousev,kalmanv; cv::KalmanFilter KF; cv::Mat_<float> measurement(2,1); Mat_<float> state(4, 1); // (x, y, Vx, Vy) int incr=0; void initKalman(float x, float y) { // Instantate Kalman Filter with // 4 dynamic parameters and 2 measurement parameters, // where my measurement is: 2D location of object, // and dynamic is: 2D location and 2D velocity. KF.init(4, 2, 0); measurement = Mat_<float>::zeros(2,1); measurement.at<float>(0, 0) = x; measurement.at<float>(0, 0) = y; KF.statePre.setTo(0); KF.statePre.at<float>(0, 0) = x; KF.statePre.at<float>(1, 0) = y; KF.statePost.setTo(0); KF.statePost.at<float>(0, 0) = x; KF.statePost.at<float>(1, 0) = y; setIdentity(KF.transitionMatrix); setIdentity(KF.measurementMatrix); setIdentity(KF.processNoiseCov, Scalar::all(.005)); //adjust this for faster convergence - but higher noise setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1)); setIdentity(KF.errorCovPost, Scalar::all(.1)); } Point kalmanPredict() { Mat prediction = KF.predict(); Point predictPt(prediction.at<float>(0),prediction.at<float>(1)); KF.statePre.copyTo(KF.statePost); KF.errorCovPre.copyTo(KF.errorCovPost); return predictPt; } Point kalmanCorrect(float x, float y) { measurement(0) = x; measurement(1) = y; Mat estimated = KF.correct(measurement); Point statePt(estimated.at<float>(0),estimated.at<float>(1)); return statePt; } int main() { Mat frame, thresh_frame; vector<Mat> channels; VideoCapture capture; vector<Vec4i> hierarchy; vector<vector<Point> > contours; // cv::Mat frame; cv::Mat back; cv::Mat fore; cv::BackgroundSubtractorMOG2 bg; //bg.nmixtures = 3;//nmixtures //bg.bShadowDetection = false; int incr=0; int track=0; capture.open("4.avi"); if(!capture.isOpened()) cerr << "Problem opening video source" << endl; mousev.clear(); kalmanv.clear(); initKalman(0, 0); while((char)waitKey(1) != 'q' && capture.grab()) { Point s, p; capture.retrieve(frame); bg.operator ()(frame,fore); bg.getBackgroundImage(back); erode(fore,fore,Mat()); erode(fore,fore,Mat()); dilate(fore,fore,Mat()); dilate(fore,fore,Mat()); dilate(fore,fore,Mat()); dilate(fore,fore,Mat()); dilate(fore,fore,Mat()); dilate(fore,fore,Mat()); dilate(fore,fore,Mat()); cv::normalize(fore, fore, 0, 1., cv::NORM_MINMAX); cv::threshold(fore, fore, .5, 1., CV_THRESH_BINARY); split(frame, channels); add(channels[0], channels[1], channels[1]); subtract(channels[2], channels[1], channels[2]); threshold(channels[2], thresh_frame, 50, 255, CV_THRESH_BINARY); medianBlur(thresh_frame, thresh_frame, 5); // imshow("Red", channels[1]); findContours(fore, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); vector<vector<Point> > contours_poly( contours.size() ); vector<Rect> boundRect( contours.size() ); Mat drawing = Mat::zeros(thresh_frame.size(), CV_8UC1); for(size_t i = 0; i < contours.size(); i++) { // cout << contourArea(contours[i]) << endl; if(contourArea(contours[i]) > 500) drawContours(drawing, contours, i, Scalar::all(255), CV_FILLED, 8, vector<Vec4i>(), 0, Point()); } thresh_frame = drawing; findContours(fore, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); drawing = Mat::zeros(thresh_frame.size(), CV_8UC1); for(size_t i = 0; i < contours.size(); i++) { // cout << contourArea(contours[i]) << endl; if(contourArea(contours[i]) > 3000) drawContours(drawing, contours, i, Scalar::all(255), CV_FILLED, 8, vector<Vec4i>(), 0, Point()); } thresh_frame = drawing; // Get the moments vector<Moments> mu(contours.size() ); for( size_t i = 0; i < contours.size(); i++ ) { mu[i] = moments( contours[i], false ); } // Get the mass centers: vector<Point2f> mc( contours.size() ); for( size_t i = 0; i < contours.size(); i++ ) { mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); /* for(size_t i = 0; i < mc.size(); i++) { // drawCross(frame, mc[i], Scalar(255, 0, 0), 5); //measurement(0) = mc[i].x; //measurement(1) = mc[i].y; // line(frame, p, s, Scalar(255,255,0), 1); // if (measurement(1) <= 130 && measurement(1) >= 120) { // incr++; // cout << "Conter " << incr << " Loation " << measurement(1) << endl; // } }*/ } for( size_t i = 0; i < contours.size(); i++ ) { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true ); boundRect[i] = boundingRect( Mat(contours_poly[i]) ); } p = kalmanPredict(); // cout << "kalman prediction: " << p.x << " " << p.y << endl; mousev.push_back(p); for( size_t i = 0; i < contours.size(); i++ ) { if(contourArea(contours[i]) > 1000){ rectangle( frame, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 2, 8, 0 ); Point center = Point(boundRect[i].x + (boundRect[i].width /2), boundRect[i].y + (boundRect[i].height/2)); cv::circle(frame,center, 8, Scalar(0, 0, 255), -1, 1,0); s = kalmanCorrect(center.x, center.y); drawCross(frame, s, Scalar(255, 255, 255), 5); if (s.y <= 130 && p.y > 130 && s.x > 15) { incr++; cout << "Counter " << incr << endl; } for (int i = mousev.size()-20; i < mousev.size()-1; i++) { line(frame, mousev[i], mousev[i+1], Scalar(0,255,0), 1); } } } imshow("Video", frame); imshow("Red", channels[2]); imshow("Binary", thresh_frame); } return 0; }
运动目标检测与卡尔曼滤波追踪结合的追踪方法实现了这一过程。。。`
相关文章推荐
- C++实现钢管计数
- 利用数组操作实现灰度图像放大两倍(C++&opencv)
- C++使用opencv实现彩色直方图计算
- 【C++】智能指针之引用计数的实现
- opencv3 图像处理(一)图像缩放( python与c++ 实现)
- C++ 简易string类实现(二)-引用计数
- LLC(Locality-constrained Linear Coding)基于OpenCV的C++源码实现
- 利用Opencv实现微信跳一跳脚本源码放送(C++实现嵌套python)
- SIFT算法的c++实现(VS2010+OpenCV2.3.1)
- 矩阵特征分解介绍及雅克比(Jacobi)方法实现特征值和特征向量的求解(C++/OpenCV/Eigen)
- share_ptr 实现c++ 句柄引用计数
- SIFT算法的c++实现(VS2010+OpenCV2.3.1)
- SIFT算法的c++实现(VS2010+OpenCV2.3.1)
- C++&OpenCV实现抠除(也可用于更换)证件照背景
- C++ 简易string类实现(三)-抽离引用计数
- 图像配准 - 三张灰度图合成彩色图 ECC算法 OpenCV C++/Python实现
- 【OpenCV学习笔记4】OpenCV GUI 之VCWin32+OpenCV 实现细胞计数
- C++ 引用计数技术及智能指针的简单实现及改进
- KUAN滤波和Lee滤波的C++结合opencv实现
- C++ OpenCV 实现RGB彩色图像转化成灰度图像再转换成二值图像