干货!升级Opencv的多目标跟踪(多线程,可根据需要实时删减和新增跟踪目标)

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
干货!升级Opencv的多目标跟踪(多线程,可根据需要实时删减和新增跟踪目标)_第1张图片

你可能感兴趣的:(OpenCv传统图像处理)