目标跟踪实践笔记三

OpenTracker 编译及流程解读

    OpenCV安装编译完成之后就可以接着找几个开源项目跑跑,看看效果,之后再结合理论,去学习一下其中的精华部分。学习应该先学会应用,在应用中探讨理论,改进创新,而不是一股脑全部扎在数学公式的推导。
OpenTracker 项目的介绍是:Real-time C++ ECO tracker etc. speed-up by SSE/NEON, support Linux, Mac, Jetson TX1/2, raspberry pi。它把ECO从MATLAB版本改成了C++版本,并且能够成功运行在各个嵌入式平台,同时对比了常见的目标跟踪算法效果,是入门的首选。因为我最后需要用到实际的应用中,放到像TX2这样的嵌入式中去运行,需要C++代码,并且是轻量化的跟踪器。项目github地址

1、下载源码,快速运行ECO


git clone https://github.com/rockkingjy/OpenTracker
cd OpenTracker/eco
make -j`nproc`
sudo make install
./runecotracker.bin

运行之后便可以看到效果,这里跑的程序是 eco/runecotracker.cc 编译的结果 。

2、ECO C++ 源码运行流程


打开文件eco/runecotracker.cc ,我们可以看见主函数中的内容

    // Database settings
	//一共有这么多种类的数据集,自己也可以添加或者使用外部摄像头
    string databaseTypes[5] = {"Demo","VOT-2017", "TB-2015", "TLP", "UAV123"};
	//我们选择哪一个数据集
    string databaseType = databaseTypes[0];//4];
    // Read from the images ====================================================

这里一共提供了四种数据集来测试性能指标,默认是Demo,只提供了少量的图片来进行运行。

if (databaseType == "Demo")
    {
        path = "../sequences/Crossing"; //数据集路径
        // some of the dataset has '\t' as the delimiter, change it to ','.
		//fstream文件操作函数 读取x y w h
        fstream gt(path + "/groundtruth_rect.txt");
        string tmp;
        size_t index = 1;
        while (gt >> tmp)  //标准化txt文件,方便后面读取
        {
            if(tmp.find(',')<10)
            {
                break;
            }
            if (index%4 == 0)
            {
            }
            else
            {
                gt << ",";
            }
            index++;
        }
        gt.close();
        // Read the groundtruth bbox
        groundtruth = new ifstream(path + "/groundtruth_rect.txt");
        f = 1;
        getline(*groundtruth, s, ',');  //一行一行读取数据
        x = atof(s.c_str());  //将字符串转换为数据
        getline(*groundtruth, s, ',');
        y = atof(s.c_str());
        getline(*groundtruth, s, ',');
        w = atof(s.c_str());
        getline(*groundtruth, s);
        h = atof(s.c_str());
        cout << f << " " << x << " " << y << " " << w << " " << h << " " << endl;
        // Read images in a folder
		//std::setw :需要填充多少个字符,默认填充的字符为' '空格
		//std::setfill:设置std::setw将填充什么样的字符
        osfile << path << "/img/" << setw(4) << setfill('0') << f << ".jpg";
        cout << osfile.str() << endl;
    }

具体的数据集路径也可以自己设置,但是因为后面需要计算指标,就需要标准的数据集来测试。一般的跟踪器都是选取第一帧中的已经标注好的物体为目标物,这里是先读取标准数据集中的Groundtruth文件中的第一帧数据x y w h,确定需要跟踪的物体。


//准备画人工标准的框
    Rect2f bboxGroundtruth(x, y, w, h);
    //先从指定路径读取img
    cv::Mat frame = cv::imread(osfile.str().c_str(), CV_LOAD_IMAGE_UNCHANGED);
    cv::Mat frameDraw;
	//copy img
    frame.copyTo(frameDraw); 
    if (!frame.data)
    {
        cout << "Could not open or find the image" << std::endl;
        return -1;
    }
    // Draw gt;
    if (databaseType == "Demo")
    {
        ii(frameDraw, bboxGroundtruth, Scalar(0, 0, 0), 2, 1);
    }

这里是读取标准数据集中的坐标,画出一个框,用于直观的对比。


ecotracker.init(frame, ecobbox, parameters);
    float fpsecoini = getTickFrequency() / ((double)getTickCount() - timereco);

    while (frame.data)
    {
        frame.copyTo(frameDraw); // only copy can do the real copy, just equal not.
        timereco = (double)getTickCount();
        bool okeco = ecotracker.update(frame, ecobbox);  //更新
        float fpseco = getTickFrequency() / ((double)getTickCount() - timereco);
        if (okeco)
        {
            rectangle(frameDraw, ecobbox, Scalar(255, 0, 255), 2, 1); //blue
        }
        else
        {
            putText(frameDraw, "ECO tracking failure detected", cv::Point(100, 80), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(255, 0, 255), 2);
            //waitKey(0);
        }

这里就开始初始化ECO,得到跟踪器输出的数据 ecobox ,用蓝色画一个框。


if (databaseType == "Demo") //读取标准数据集的数据
        {
            getline(*groundtruth, s, ',');
            x = atof(s.c_str());
            getline(*groundtruth, s, ',');
            y = atof(s.c_str());
            getline(*groundtruth, s, ',');
            w = atof(s.c_str());
            getline(*groundtruth, s);
            h = atof(s.c_str());
            //cout << f << " " << x << " " << y << " " << w << " " << h << " " << isLost << endl;
            // Read images in a folder
            osfile << path << "/img/" << setw(4) << setfill('0') << f << ".jpg";
            //cout << osfile.str() << endl;
        }
//人工标注的矩形
        bboxGroundtruth.x = x;
        bboxGroundtruth.y = y;
        bboxGroundtruth.width = w;
        bboxGroundtruth.height = h;
        frame = cv::imread(osfile.str().c_str(), CV_LOAD_IMAGE_UNCHANGED);
        if(!frame.data)
        {
            break;
        }
        // Calculate the metrics;
		//计算人工标注的和ECO算法生成的误差
        float centererror = metrics.center_error(ecobbox, bboxGroundtruth);//中心误差
        float iou = metrics.iou(ecobbox, bboxGroundtruth);  //IOU 交并比
        CenterError.push_back(centererror); //容器尾端插入数据
        Iou.push_back(iou);
        FpsEco.push_back(fpseco);

这里就是先读取人工标注的标准数据,再和自己跟踪算法输出的进行计算,得到性能评价指标。

3、目标跟踪评价指标 Precision plot


Precision plot. One widely used evaluation metric on tracking precision is the center location error, which is defined as the average Euclidean distance between the center locations of the tracked targets and the manually labeled ground truths. Then the average center location error over all the frames of one sequence is used to summarize the overall performance for that sequence. As the representative precision score for each tracker we use the score for the threshold = 20 pixels. 在 Yi Wu 老师的文章《Online Object Tracking: A Benchmark》中提到了用精确度图来衡量跟踪器的整体性能,是跟踪算法估计的目标位置(bounding box)的中心点与人工标注(ground-truth)的目标的中心点的欧式几何距离,这两者的距离小于给定阈值(一般是20个像素)的视频帧的百分比。

float Metrics::center_error(const cv::Rect2f bbox, const cv::Rect2f bboxGroundtruth)
{
    float cx = bbox.x + bbox.width / 2.0f;  //得到中心点的坐标
    float cy = bbox.y + bbox.height / 2.0f;
    float cx_gt = bboxGroundtruth.x + bboxGroundtruth.width / 2.0f;
    float cy_gt = bboxGroundtruth.y + bboxGroundtruth.height / 2.0f;
    float result = std::sqrt(std::pow((cx - cx_gt), 2) +
                             std::pow((cy - cy_gt), 2));  //中心坐标差平方和开根号
    return result;
}

这个是ECO项目中eco / metrics.cc文件中的函数,用来计算中心误差。

if(centererror <= 20) //20为阈值
        {
            AvgPrecision++;  //中心误差小于阈值(一般设置为20像素),精度加1,最后除以总的帧数即为精度
        }

 AvgPrecision /= (float)(f - 2);

中心误差小于阈值(20个像素)即可以增加一个精确度,最后再除以帧数。例如,数据集中有102帧,追踪算法得到的中心点与标准数据集中心点距离小于20像素有80帧,则当阈值为20像素时,精度为0.8。

4、目标跟踪评价指标 Success plot


来自Online Object Tracking: A Benchmark来自Online Object Tracking: A Benchmark在 Yi Wu 老师的文章《Online Object Tracking: A Benchmark》中提到了用IOU(Intersection-over-Union,交并比)定义准确度。当重叠的区域大于设定的阈值(一般是0.5),则这一帧的识别视为成功。

float Metrics::iou(const cv::Rect2f bbox, const cv::Rect2f bboxGroundtruth)
{
    cv::Rect2f inter = Metrics::intersection(bbox, bboxGroundtruth);
    float area_bbox = bbox.area();
    float area_bbox_gt = bboxGroundtruth.area();
    float area_intersection = inter.area();  //交集的面积
    float iou = area_bbox + area_bbox_gt - area_intersection; //得到两个box的并集面积
    iou = area_intersection / (iou + 1e-12);  //交集/并集,为了防止分母为0, 加一个很小的值
    return iou;
}
//求两个矩形的交集 右坐标最小减去左坐标最大
cv::Rect2f Metrics::intersection(const cv::Rect2f bbox,
                                 const cv::Rect2f bboxGroundtruth)
{
    float x1, y1, x2, y2, w, h;
    x1 = std::max(bbox.x, bboxGroundtruth.x);  //求左上角最大的坐标
    y1 = std::max(bbox.y, bboxGroundtruth.y);
    x2 = std::min(bbox.x + bbox.width, bboxGroundtruth.x + bboxGroundtruth.width); //求右下角最小的坐标
    y2 = std::min(bbox.y + bbox.height, bboxGroundtruth.y + bboxGroundtruth.height);
    w = std::max(0.0f, x2 - x1);
    h = std::max(0.0f, y2 - y1);

    cv::Rect2f result(x1, y1, w, h);
    return result;
}

这个是ECO项目中 eco / metrics.cc 文件中的函数,用来计算两个box的并集和指标IOU。

// Calculate the metrics;
		//计算人工标注的和ECO算法生成的误差
        float centererror = metrics.center_error(ecobbox, bboxGroundtruth);//中心误差
        float iou = metrics.iou(ecobbox, bboxGroundtruth);  //IOU 交并比
        CenterError.push_back(centererror); //容器尾端插入数据
        Iou.push_back(iou);
        FpsEco.push_back(fpseco);

        cout << "iou:" << iou << std::endl;

        if(centererror <= 20) //20为阈值
        {
            AvgPrecision++;  //中心误差小于阈值(一般设置为20像素),精度加1,最后除以总的帧数即为精度
        }
        if(iou >= 0.5) //0.5为阈值
        {
            SuccessRate++; //当IOU大于阈值的时候,认为成功,最后除以总的帧数,即为成功率
        }
       
 SuccessRate /= (float)(f - 2);

得到IOU数据之后,存到一个容器中,之后只要容器中数据大于阈值(0.5),则视为成功。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

经纬的无疆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值