Keywords:
Multitracker 多线程跟踪 跟踪目标删除 跟踪目标新增 opencv跟踪算法 多线程 动态删减新增跟踪目标 目标跟踪 opencv 多目标跟踪 c++ opencv 多目标跟踪 动态删减目标 动态新增目标 新增目标 删减目标 多个目标跟踪 多个目标跟踪器 目标跟踪器
程序的功能和框架
本源码分三个功能:
1,基于固定场景的多帧中值滤波
2,基于高斯背景模型的前景提取(可以换成其他方法如:深度学习或机器学习的检测结果ROI)
3,根据高斯背景模型提取的ROI框进行目标跟踪。本文选用的是CSTR跟踪器,可根据需要换成KCF等其他跟踪器。 相当于重写了Multitracker 的新增跟踪目标和删减部分。
性能优于opencv原版的Multitracker ,因为Multitracker 跟踪多个目标是串行
要说的话
源码未整理,只保留功能,没有封装。多线程仅限于多跟踪器的多线程,其他部分没加多线程,有兴趣的可以优化。建议用Release模式跑,不然卡死。
opencv源码里的多目标跟踪器并没有删减目标跟踪的功能,本源码加上这以功能。 并可根据需要新增和删减跟踪目标
依赖环境
opencv342 X64 Release版本 VS2019
opencv3 vs各版本下载地址: 链接: https://pan.baidu.com/s/1f5oAFqs-u15vkD5LNTcxtw 提取码: 2qj9
上面的百度网盘应该没有我调试用的opencv版本 VS2019_release_X64_opencv342,可以加QQ群去群文件找:539308722
话不多说,具体请参考下面的源码
随便抄,原创不易,点个赞或者关注一下
另:两个可以水中文核心的代码。懒得写论文了,有需要的也可以进群联系 给我挂个共同一作或者二作就成
源码如果有错的地方,那就是csdn编辑器编辑起来很别扭,复制粘贴时乱了一点。也可以加群找我要代码。
#include
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
#define COLS 960
#define ROWS 540
#define FN 10//时序中值的图像数目
Mat matRotateClockWise180(Mat src)//顺时针180
{
flip(src, src, 0);
flip(src, src, 1);
return src;
}
void BaseLine_Generator_1(Mat* BaseLine,vector<Mat>* vMat)
{
for (int i = 0; i < ROWS; ++i)
{
for (int j = 0; j < COLS; ++j)
{
uchar Mid_value_[FN];
for (int k = 0; k < FN; k++) {
Mid_value_[k] = (*vMat)[k].at<Vec3b>(i, j)[0];
}
sort(Mid_value_, Mid_value_ + FN);
BaseLine->at<Vec3b>(i, j)[0] = Mid_value_[FN / 2];
for (int k = 0; k < FN; k++) {
Mid_value_[k] = (*vMat)[k].at<Vec3b>(i, j)[1];
}
sort(Mid_value_, Mid_value_ + FN);
BaseLine->at<Vec3b>(i, j)[1] = Mid_value_[FN / 2];
for (int k = 0; k < FN; k++) {
Mid_value_[k] = (*vMat)[k].at<Vec3b>(i, j)[2];
}
sort(Mid_value_, Mid_value_ + FN);
BaseLine->at<Vec3b>(i, j)[2] = Mid_value_[FN / 2];
}
}
}
float RectOverlap(cv::Rect r, cv::Rect rOther)
{
int x0 = std::max(r.x, rOther.x);
int x1 = std::min(r.x + r.width, rOther.x + rOther.width);
int y0 = std::max(r.y, rOther.y);
int y1 = std::min(r.y + r.height, rOther.y + rOther.height);
if (x0 >= x1 || y0 >= y1) return 0.f;
float areaInt = (x1 - x0) * (y1 - y0);
float MINArea= MIN((float)r.width * r.height, (float)rOther.width * rOther.height);
return areaInt / MINArea;
}
//删除跟踪器
void CSRT_tracker(vector<Ptr<Tracker>>* tracker, Mat* frame, vector<Rect2d>* bbox, vector<bool>* ok_CSRT, int i) {
(*ok_CSRT)[i] = (*tracker)[i]->update(*frame, (*bbox)[i]);
}
void CSRT_tracker_erase_(vector<Ptr<Tracker>>* tracker, vector<Rect2d>* bbox, vector<bool>* ok_CSRT, vector<clock_t>* Start_time_record, vector<double>* fish_distance, vector<Rect2d>* ptr_bboxCSRT,int i) {
(*tracker).erase((*tracker).begin() + i);
(*bbox).erase((*bbox).begin() + i);
(*ok_CSRT).erase((*ok_CSRT).begin() + i);
(*Start_time_record).erase((*Start_time_record).begin() + i);
(*fish_distance).erase((*fish_distance).begin() + i);
(*ptr_bboxCSRT).erase((*ptr_bboxCSRT).begin() + i);
}
int main(int argc, char** argv)
{
Ptr<BackgroundSubtractorMOG2> bgsubtractor = createBackgroundSubtractorMOG2();
bgsubtractor->setVarThreshold(20);
VideoCapture video("C:/testv/5.mp4");
if (!video.isOpened())
{
cout << "Could not read video file" << endl;
return 1;
}
Mat frame;
Mat src;
vector<Mat> Filtering_Mat;
//*******************8
vector<thread> TrackerThread_;
vector<Ptr<Tracker>> trackerCSRT;
vector<Rect2d> bboxCSRT;
vector<double> fish_distance;
vector<Rect2d> ptr_bboxCSRT;
Rect2d bbox;
bool sign = false;
vector<bool> OK_;
vector<clock_t> Start_time_record;
bool OK_0 = false;
long int fishnum = 0;
///////////////////////////
for (int i = 0; i < FN; i++) {
Mat src1;
video.read(frame);
resize(frame, src1, Size(960, 540));
src1 = matRotateClockWise180(src1);
imshow("check", src1);
waitKey(100);
Filtering_Mat.push_back(src1);
}
while (video.read(frame)) {
resize(frame, src, Size(960, 540));
src = matRotateClockWise180(src);
imshow("src", src);
Mat filter_src1 = src.clone();
Filtering_Mat.erase(Filtering_Mat.begin());
Filtering_Mat.push_back(filter_src1);
Mat filter_src = src.clone();
BaseLine_Generator_1(&filter_src, &Filtering_Mat);
imshow("Final result", filter_src);
Mat mask;
Mat Gfilter_src;
cvtColor(filter_src, Gfilter_src, CV_RGB2GRAY);
bgsubtractor->apply(filter_src, mask, 0.01);
imshow("GMask", mask);
std::vector<std::vector<cv::Point> > cnts;
Mat kernel = getStructuringElement(MORPH_CROSS, Size(13, 13), Point(-1, -1));
cv::dilate(mask, mask, kernel);
Mat kernel1 = getStructuringElement(MORPH_CROSS, Size(12,12), Point(-1, -1));
cv::erode(mask, mask, kernel1);
cv::threshold(mask, mask, 128, 255, THRESH_BINARY);
imshow("GMask1", mask);
findContours(mask, cnts, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
float Area;
Rect rect;
vector<Point> m;
for (int i = cnts.size() - 1; i >= 0; i--)
{
vector<Point> c = cnts[i];
Area = contourArea(c);
if (Area < 1600)//目标的大小
{
continue;
}
else
{
m = c;
}
rect = boundingRect(m);
//高斯背景求的前景目标比例限制,可根据需要调整
if(double(MAX(rect.width, rect.height)) / double(MIN(rect.width, rect.height)) <1.5) continue;
if (double(MAX(rect.width, rect.height)) / double(MIN(rect.width, rect.height)) > 3) continue;
if((rect.width + rect.height)>400)continue;
// Rect rect_track = rect;
double cx = double(rect.x + double(rect.width)/2);
double cy = double(rect.y + double(rect.height) / 2);
bool Needcontinue = false;
for (int kk =0;kk<bboxCSRT.size();kk++)
{
//与已有的目标中心点曼哈顿距离小于100
if ((abs((bboxCSRT[kk].x + bboxCSRT[kk].width / 2) - cx) + abs((bboxCSRT[kk].y + bboxCSRT[kk].height / 2) - cy)) < 100)
{
Needcontinue = true;
continue;
}
//于已有框体交叉面积大于20%
float verlap_ = RectOverlap(rect, bboxCSRT[kk]);
if (verlap_ >0.2)
{
Needcontinue = true;
continue;
}
}
if (Needcontinue) {
continue;
}
Ptr<Tracker > tracker_0;
tracker_0 = TrackerCSRT::create();
bbox = rect;
rectangle(filter_src, bbox, Scalar(255, 0, 0), 2, 1);
bboxCSRT.push_back(bbox);
tracker_0->init(src, bbox);
trackerCSRT.push_back(tracker_0);
OK_.push_back(OK_0);
clock_t start_time = clock();
double zero_ = 0;
fish_distance.push_back(zero_);
ptr_bboxCSRT.push_back(bbox);
Start_time_record.push_back(start_time);
}
imshow("CSRT Tracking src", filter_src);
int k1 = waitKey(1);
Mat tracksrc;
bilateralFilter(src, tracksrc, 5, 2, 2);
if(OK_.size() > 0){
double timer = (double)getTickCount();
for (int i = 1; i < trackerCSRT.size(); i++) {
TrackerThread_.push_back(thread(CSRT_tracker, &trackerCSRT, &tracksrc, &bboxCSRT, &OK_, i));
}
OK_[0] = trackerCSRT[0]->update(tracksrc, bboxCSRT[0]);
for (auto& ite : TrackerThread_) {
ite.join();
}
TrackerThread_.clear();
float fps = getTickFrequency() / ((double)getTickCount() - timer);
Mat frameCSRT = tracksrc.clone();
for (int i = 0; i < trackerCSRT.size(); i++) {
if (OK_[i])
{
rectangle(frameCSRT, bboxCSRT[i], Scalar(0, 255, 255), 2, 1);
}
else {
putText(frameCSRT, "Tracking failure detected" + to_string(i), Point(100, 80 + i * 10), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 255), 2);
}
double x_b;
double y_b;//框体的右下点坐标
x_b = bboxCSRT[i].x + bboxCSRT[i].width;
y_b = bboxCSRT[i].y + bboxCSRT[i].height;
string str;
clock_t time_out = clock() - Start_time_record[i];
double cx0 = double(bboxCSRT[i].x + double(bboxCSRT[i].width) / 2);
double cy0 = double(bboxCSRT[i].y + double(bboxCSRT[i].height) / 2);
double cx1 = double(ptr_bboxCSRT[i].x + double(ptr_bboxCSRT[i].width) / 2);
double cy1 = double(ptr_bboxCSRT[i].y + double(ptr_bboxCSRT[i].height) / 2);
fish_distance[i]= fish_distance[i] + abs(cx0 - cx1) + abs(cy0 - cy1);
ptr_bboxCSRT[i].x = bboxCSRT[i].x;
ptr_bboxCSRT[i].y= bboxCSRT[i].y;
ptr_bboxCSRT[i].width = bboxCSRT[i].width;
ptr_bboxCSRT[i].height = bboxCSRT[i].height;
bool dis_time = false;
dis_time = ((time_out / CLOCKS_PER_SEC) > 30) && (fish_distance[i] < 300);//出现在场景中的时间超过30秒且目标的距离小于300
//目标越界,且走过de的距离大于400,删除目标,计数+1
if ((bboxCSRT[i].x < 0 || bboxCSRT[i].y < 0 || x_b >960 || y_b>540) && (fish_distance[i] > 400)) {
CSRT_tracker_erase_(&trackerCSRT, &bboxCSRT, &OK_, &Start_time_record,&fish_distance,&ptr_bboxCSRT,i);
str = "Find Fish, delete Rect!";
fishnum++;
}
else if(!OK_[i] || dis_time|| ((time_out / CLOCKS_PER_SEC) > 80)){
CSRT_tracker_erase_(&trackerCSRT, &bboxCSRT, &OK_, &Start_time_record, &fish_distance, &ptr_bboxCSRT, i);
str = "Not Fish, delete Rect!";
}
//跟踪目标越界,在场景中走过的距离不超过300个像素 曼哈顿距离
else if((bboxCSRT[i].x < 0 || bboxCSRT[i].y < 0 || x_b >960 || y_b>540) && (fish_distance[i] < 300)){
CSRT_tracker_erase_(&trackerCSRT, &bboxCSRT, &OK_, &Start_time_record, &fish_distance, &ptr_bboxCSRT, i);
str = "Not Fish, delete Rect!";
}
putText(frameCSRT, "CSRT Tracker Number:" + to_string(OK_.size()), Point(100, 20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50, 170, 50), 2);
putText(frameCSRT, "FPS : " + to_string((int(fps))) + str, Point(100, 50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50, 170, 50), 2);
putText(frameCSRT, "Found fish: " + to_string(fishnum) , Point(100, 80), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50, 170, 50), 2);
imshow("CSRT Tracking", frameCSRT);
waitKey(1);
}
}
}
return 0;
}
结果图示意:貌似上面这个代码是没有鱼轨迹的,忘记了.
获取有轨迹的版本:https://download.csdn.net/download/weixin_37918890/12593594