参考 https://blog.csdn.net/xiao__run/article/details/77478579 运动目标检测部分,简单手写了一下多目标追踪
存在一些问题未解决:由于检测部分并不时刻准确,导致同一物体不同时刻id会变
ubuntu 下 opencv4(用3的话改一些cv里变量的名字即可)
CmakeList.txt:
cmake_minimum_required( VERSION 2.8 )
project( track )
find_package( OpenCV REQUIRED )
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(test test.cpp)
target_link_libraries(test ${OpenCV_LIBS})
源代码test.cpp:
#include
#include
#include
#include
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);
//计算两中心点距离
double ComputeDistance( vector<double> c1, vector<double> c2){
return sqrt( (c1[0]-c2[0])*(c1[0]-c2[0])+(c1[1]-c2[1])*(c1[1]-c2[1]) );
}
string num2str(int i)//int转型为字符串
{
stringstream ss;
ss << i;
return ss.str();
}
int main(){
Mat frame, thresh_frame;
int therehold = 100;
/**/
int count = 0;
//用vetor来作容器,(按道理用map应该会更方便点)
vector<vector<double> > center_points_prev_frame;//存上一帧各boxs中心
vector<vector<double> > center_points_cur_frame;//存储当前帧boxs中心
vector<vector<double> > tracking_object_center;//跟踪的目标的中心
vector<vector<vector<double> > > tractory;//跟踪的目标的每个id的轨迹
int track_id = 0;
/**/
vector<Mat> channels;
VideoCapture capture("cars.avi");
if (!capture.isOpened())
cout << "hello";
vector<Vec4i> hierarchy;
vector<vector<Point> > contours;
cv::Mat back, img;
cv::Mat fore;
cv::Ptr<BackgroundSubtractorMOG2> bg = createBackgroundSubtractorMOG2();
int incr = 0;
int track = 0;
bool update_bg_model = true;
if (!capture.isOpened())
cerr << "Problem opening video source" << endl;
bool isfirstframe = true;
while ((char)waitKey(1) != 'q' && capture.grab()){
capture.retrieve(frame);
count ++;//计第几帧
/***************************根据背景提取动态目标**********************/
bg->apply(frame, fore, update_bg_model ? -1 : 0);
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);
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]) > 1000)
drawContours(drawing, contours, i, Scalar::all(255), cv::FILLED, 8, vector<Vec4i>(), 0, Point());
}
thresh_frame = drawing;
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]));
}
/****************************************************************************/
//计算当前帧各个box中心
center_points_prev_frame.assign(center_points_cur_frame.begin(),center_points_cur_frame.end());//赋值
center_points_cur_frame.clear();
for (size_t i = 0; i < contours.size(); i++){
if (contourArea(contours[i]) > 3000){
vector<double> center;
center.push_back(boundRect[i].x + (boundRect[i].width / 2));
center.push_back(boundRect[i].y + (boundRect[i].height / 2));
//cout<
center_points_cur_frame.push_back(center);
//rectangle(frame, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 2, 8, 0);
}
}
//cout<<" cur_num1 " <
if( count == 1 ) {
imshow("Video", frame);
//waitKey(0);
cout<<"第一帧"<<endl;
continue;}
if( count ==2 ){
for(auto center_cur:center_points_cur_frame ){
int trac_index = 0;
double distance = 0;
double min_distance = 100000;
for(auto center_prev:center_points_prev_frame){
distance =ComputeDistance( center_cur , center_prev );
//cout<<"distance"<
min_distance = distance < min_distance ? distance : min_distance ;
//cout<<"min_distance"<
}
if( min_distance < therehold ){
tracking_object_center.push_back(center_cur);//不同id在当前帧对应的点
tractory.resize(tracking_object_center.size());
for(auto trac:tractory ){
trac.resize(100);
for( auto trac1:trac ){
trac1.resize(2);
}
}
tractory[track_id].push_back(center_cur);
track_id ++;
trac_index ++;
}
}
cout<<"第二帧"<<endl;
continue;
}
/* if( count <= 7 ) {
center_points_prev_frame.assign(center_points_cur_frame.begin(),center_points_cur_frame.end());//赋值
cout<<"size "<=8 ){
for(auto center_cur:center_points_cur_frame ){
double distance = 0;
double min_distance = 100000;
for(auto center_prev:center_points_prev_frame){
distance =ComputeDistance( center_cur , center_prev );
cout<<"distance"<
//开始第二帧后的匹配 当前帧中的点与上一帧的点进行匹配,匹配成功则继承id
cout<<" cnt "<<count<<" cur_num " <<center_points_cur_frame.size()<<endl;
for(int object_id = 0; object_id < tracking_object_center.size();object_id ++){
double distance = 0;
double min_distance = 100000;
vector<double> temp;
int temp_index = 0;
bool object_exist = false;
for( int i = 0; i < center_points_cur_frame.size(); i++ ){
if(tracking_object_center[object_id][0]==-1) continue;
distance = ComputeDistance(tracking_object_center[object_id] , center_points_cur_frame[i]);
if( distance < min_distance ){
min_distance = distance < min_distance ? distance : min_distance ;
temp = center_points_cur_frame[i];
temp_index = i;
}
}
//cout<<"distance "<
if( min_distance < therehold ){
object_exist = true;
/*Point p1= Point(tracking_object_center[object_id][0], tracking_object_center[object_id][1]);
Point p2= Point(temp[0],temp[1]);
line(frame,p1 , p2, Scalar(0, 255, 0), 1);*/
tracking_object_center[object_id] = temp;
tractory[object_id].push_back(temp);
Scalar color = CV_RGB(255, 0, 0);
Point pt= Point(temp[0], temp[1] - 10);
putText(frame, "car"+num2str(object_id), pt, cv::FONT_HERSHEY_DUPLEX, 1.0f, color);
center_points_cur_frame.erase(center_points_cur_frame.begin() + temp_index);
}
if( object_exist == false ){
//cout<<"non "<
tracking_object_center[object_id][0]=-1;
tracking_object_center[object_id][1]=-1;
tractory[object_id].clear();
//cout<<" yes "<
}
}
for( auto center_cur:center_points_cur_frame ){
tracking_object_center.push_back(center_cur);
tractory.resize(tracking_object_center.size());
tractory[track_id].push_back(center_cur);
Scalar color = CV_RGB(255, 0, 0);
Point pt= Point(center_cur[0], center_cur[1] - 10);
putText(frame, "car"+num2str(track_id), pt, cv::FONT_HERSHEY_DUPLEX, 1.0f, color);
track_id ++;
}
//cout<<" center_size "<< tracking_object_center.size()<<" "<
//加文本
/*for(size_t i=0; i < tracking_object_center.size();i++){
cout<< "huizhi"<
string text;
for (size_t i = 0; i < contours.size(); i++)
{
if (contourArea(contours[i]) > 3000)
{
rectangle(frame, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 2, 8, 0);
Point pt = Point(boundRect[i].x, boundRect[i].y + boundRect[i].height + 15);
Point pt1 = Point(boundRect[i].x, boundRect[i].y - 10);
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);
Scalar color = CV_RGB(255, 0, 0);
text = num2str(boundRect[i].width) + "*" + num2str(boundRect[i].height);
//putText(frame, "people", pt, cv::FONT_HERSHEY_DUPLEX, 1.0f, color);
putText(frame, text, pt1, cv::FONT_HERSHEY_DUPLEX, 1.0f, color);
}
}
//画轨迹
for( auto trac:tractory ){
// cout<<" trac "<
for(size_t i = 1; i < trac.size(); i++){
// cout<<" "<
Point p1 ,p2;
p1.x = trac[i][0];
p1.y = trac[i][1];
p2.x = trac[i-1][0];
p2.y = trac[i-1][1];
line(frame,p1,p2,Scalar(0, 255, 0),4);
}
}
imshow("Video", frame);
//waitKey(0);
}
return 0;
}