目标跟踪-边缘跟踪

边缘跟踪算法实现过程

网上大部分关于边缘跟踪的算法不是目标跟踪领域,而是串接目标的边缘,和区域生长法作用一样。极少有文献是关于目标跟踪领域的边缘跟踪算法。

边缘跟踪算法主要包括4个步骤:

  1. 帧间波门内差分;
  2. 波门内阈值分割;
  3. 波门内去噪声;
  4. 计算边缘点(中心)

前面三步和质心跟踪算法一样,第4步如果是计算单个边缘点,就是单边缘跟踪,如果是计算边缘点的中心,就是双边缘中心跟踪。这里以双边缘中心跟踪为例。

帧间波门内差分

相邻帧之间在波门内进行差分操作。为了仅体现相邻帧之间的变化量,这里我做了绝对值差分操作。即
D i f f x , y = ∣ f x , y i + 1 − f x , y i ∣ Diff_{x,y} = |f^{i+1}_{x,y} - f^i_{x,y}| Diffx,y=fx,yi+1fx,yi
f i + 1 f^{i+1} fi+1和f^i是相邻帧的波门框定图像。x, y表示具体坐标。通过绝对差分可以表征帧间目标的变化量。具体函数如下:

cv::absdiff(gray_image(_roi), this->gray_image(_roi), diff);

波门内阈值分割

在得到差分图像以后,有可能差分图像本身的对比度较低。我们需要对差分图像进行二值化来进一步体现目标的变化量。一般的图像二值化可以固定一个阈值比如127u,但是差分图像需要自适应地选择阈值来进行分割。此处选择最大类间方差算法来选择分割阈值。具体思想可以参见:https://blog.csdn.net/zhu_hongji/article/details/80967776

int EdgeTracker::getThresholdValue(cv::Mat& image);

选择了最优阈值之后,就对图像进行二值分割。

void EdgeTracker::segmentByThreshold(cv::Mat& src, cv::Mat& dst, int threshold);

波门内去噪声

去噪声这一步是可选的,在实现里我采用腐蚀+膨胀的方法(被注释掉了),腐蚀是为了去除白噪点,膨胀是为了突出目标的变化量。结构元素3x3。

计算边缘的中心

计算边缘点的中心是根据阈值分割后的图来的,这一步思想非常简单,就是找目标的上下左右边界。形式化表述如下:
y u p p e r = max ⁡ { y ∗ ∣ ∀ y < y ∗ , 0 < x < W , I ( x , y ) = 0 } y l o w e r = min ⁡ { y ∗ ∣ ∀ y > y ∗ , 0 < x < W , I ( x , y ) = 0 } x l e f t = max ⁡ { x ∗ ∣ ∀ x < x ∗ , 0 < y < H , I ( x , y ) = 0 } x r i g h t = min ⁡ { x ∗ ∣ ∀ x > x ∗ , 0 < y < H , I ( x , y ) = 0 } y_{upper} = \max \{y^* | \forall y < y^*, 0 < x < W, I(x, y) = 0 \} \\ y_{lower} = \min \{y^* | \forall y > y^*, 0 < x < W, I(x, y) = 0 \} \\ x_{left} = \max \{x^* | \forall x < x^*, 0 < y < H, I(x, y) = 0 \} \\ x_{right} = \min \{x^* | \forall x > x^*, 0 < y < H, I(x, y) = 0 \} \\ yupper=max{y∣∀y<y,0<x<W,I(x,y)=0}ylower=min{y∣∀y>y,0<x<W,I(x,y)=0}xleft=max{x∣∀x<x,0<y<H,I(x,y)=0}xright=min{x∣∀x>x,0<y<H,I(x,y)=0}
其中, y u p p e r y_{upper} yupper, y l o w e r y_{lower} ylower分别表示目标的上下边界的纵坐标, x l e f t x_{left} xleft, x r i g h t x_{right} xright分别表示目标的左右边界的横坐标, W W W H H H分别为图像的宽度和高度。

那么可以得到4个边缘点的坐标为:
p u p p e r = ( x l e f t + x r i g h t 2 , y u p p e r ) p l o w e r = ( x l e f t + x r i g h t 2 , y l o w e r ) p l e f t = ( x l e f t , y u p p e r + y l o w e r 2 ) p r i g h t = ( x r i g h t , y u p p e r + y l o w e r 2 ) p_{upper} = (\frac{x_{left} + x_{right}}{2}, y_{upper}) \\ p_{lower} = (\frac{x_{left} + x_{right}}{2}, y_{lower}) \\ p_{left} = (x_{left}, \frac{y_{upper} + y_{lower}}{2}) \\ p_{right} = (x_{right}, \frac{y_{upper} + y_{lower}}{2}) pupper=(2xleft+xright,yupper)plower=(2xleft+xright,ylower)pleft=(xleft,2yupper+ylower)pright=(xright,2yupper+ylower)

如果只利用其中一个边缘点,那么可以导出单边缘跟踪算法,这里介绍双边缘跟踪算法,实际上就是计算这4个点的中心坐标, 也就是
p c e n t e r = ( x l e f t + x r i g h t 2 , y u p p e r + y l o w e r 2 ) p_{center} = (\frac{x_{left} + x_{right}}{2}, \frac{y_{upper} + y_{lower}}{2}) pcenter=(2xleft+xright,2yupper+ylower)

p c e n t e r p_{center} pcenter的偏移可以导出目标在不同帧的移动路径,并由此确定当前帧目标的波门。

头文件如下:

class EdgeTracker : CustomTracker
{
public:
    EdgeTracker(bool debug = false);
    ~EdgeTracker();
    void init(cv::Mat& image, const cv::Rect_<int> &roi);
    cv::Rect_<int> update(cv::Mat& image);
    cv::Mat getDiff(cv::Mat& gray_image);
    int getThresholdValue(cv::Mat& image);
    void segmentByThreshold(cv::Mat& src, cv::Mat& dst, int threshold);
    vector<cv::Point_<int>> findEdgePoints(cv::Mat& seg_map);

protected:
    cv::Rect_<float> _roi;
    cv::Mat image;
    cv::Mat gray_image;
    bool DEBUG = false;
    vector<cv::Point_<int>> edge_points; // centerp_upper, centerp_lower, centerp_left, centerp_right
    int ite_num;
    bool first_ite;
};

核心代码如下:

vector<cv::Point_<int>> EdgeTracker::findEdgePoints(cv::Mat& seg_map)
{
    int x0, y0, x1, y1;
    x0 = 0;
    y0 = 0;
    x1 = _roi.width-1;
    y1 = _roi.height-1;
    int width = seg_map.cols;
    int height = seg_map.rows;
    bool flag1 = false, flag2 = false;
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            uint8_t pix0 = seg_map.ptr<uint8_t>(i)[j];
            uint8_t pix1 = seg_map.ptr<uint8_t>(height-i-1)[j];
            if (pix0 == 255 && !flag1)
            {
                y0 = i;
                flag1 = true;
            }
            if (pix1 == 255 && !flag2)
            {
                y1 = height-i-1;
                flag2 = true;
            }
            if (flag1 && flag2) 
            {
                flag1 = flag2 = false;
                goto P1;
            }
        }
    }
    P1: for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            uint8_t pix0 = seg_map.ptr<uint8_t>(j)[i];
            uint8_t pix1 = seg_map.ptr<uint8_t>(j)[width-i-1];
            if (pix0 == 255)
            {
                x0 = i;
                flag1 = true;
            }
            if (pix1 == 255)
            {
                x1 = width-i-1;
                flag2 = true;
            }
            if (flag1 && flag2) goto P2;
        }
    }
    P2: // 计算4个边缘点的坐标
    vector<cv::Point_<int>> points;
    cv::Point_<int> upper, lower, left, right;
    upper.x = (x0 + x1) / 2;
    upper.y = y0;
    lower.x = (x0 + x1) / 2;
    lower.y = y1;
    left.x = x0;
    left.y = (y0 + y1) / 2;
    right.x = x1;
    right.y = (y0 + y1) / 2;
    points.push_back(upper);
    points.push_back(lower);
    points.push_back(left);
    points.push_back(right);
    return points;
}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标跟踪系统是一种基于计算机视觉技术的应用,能够对视频中的目标进行追踪和识别。随着计算机视觉技术的发展,目标跟踪系统的应用越来越广泛,如安防监控、自动驾驶、无人机等。本文将以一款开源的目标跟踪系统——OpenCV的Tracker API为例,进行实例分析。 一、目标跟踪系统概述 目标跟踪系统主要包括目标检测和目标跟踪两个部分。目标检测是指在图像或视频中检测目标的位置和尺寸,即框出目标的边界框。而目标跟踪是指在视频中实时追踪目标的位置和尺寸,即跟踪目标的边界框。目标跟踪系统的主要任务是在视频中对目标进行精确定位和跟踪,以满足实际应用的需求。 二、OpenCV目标跟踪系统 OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。OpenCV中的Tracker API提供了多种目标跟踪算法,包括KCF、MIL、Boosting、TLD等。其中,KCF算法是目前最常用的跟踪算法之一,具有较快的速度和较高的精度。 1. KCF算法实现原理 KCF算法是一种基于核方法的目标跟踪算法,其核心思想是将目标的图像特征映射到高维空间中,通过计算两个特征向量之间的内积,来衡量它们之间的相似度。在跟踪过程中,KCF算法不断更新目标的模板,以适应目标的变化。 具体实现时,KCF算法将目标的图像特征表示为HOG(Histogram of Oriented Gradients)特征和颜色直方图特征的结合。HOG特征可以有效地描述目标的边缘和纹理信息,而颜色直方图特征可以描述目标的颜色信息。KCF算法通过计算目标模板和候选区域之间的相似性来确定目标的位置,并利用在线学习的方法来更新目标模板。 2. OpenCV目标跟踪系统实现 OpenCV中的Tracker API提供了多种目标跟踪算法的实现,其中包括KCF算法。下面以KCF算法为例,介绍OpenCV目标跟踪系统的实现流程。 (1)初始化跟踪器 首先,需要选择目标跟踪算法,并初始化跟踪器。在OpenCV中,可以使用create函数创建跟踪器对象,并指定跟踪算法的类型。例如,下面的代码创建了一个使用KCF算法的跟踪器对象。 ```c++ Ptr<Tracker> tracker = TrackerKCF::create(); ``` (2)读取视频帧 接下来,需要读取视频帧,并对每一帧进行处理。在OpenCV中,可以使用VideoCapture类读取视频,并使用read函数读取每一帧。例如,下面的代码读取了一个名为“test.mp4”的视频,并获取了第一帧。 ```c++ VideoCapture capture("test.mp4"); Mat frame; capture.read(frame); ``` (3)初始化跟踪目标 在进行目标跟踪之前,需要先初始化跟踪目标。在OpenCV中,可以使用selectROI函数手动选择目标区域,或者使用detect函数自动检测目标。例如,下面的代码手动选择了目标区域,并将其传给跟踪器对象。 ```c++ Rect2d bbox = selectROI(frame, false); tracker->init(frame, bbox); ``` (4)跟踪目标 完成初始化之后,就可以开始进行目标跟踪了。在每一帧中,需要使用update函数更新跟踪器,并获取当前目标的位置。例如,下面的代码对视频的每一帧进行跟踪,并在图像上绘制出目标的位置。 ```c++ while (capture.read(frame)) { bool ok = tracker->update(frame, bbox); if (ok) { rectangle(frame, bbox, Scalar(0, 0, 255), 2, 1); } imshow("Tracking", frame); waitKey(1); } ``` 三、总结 目标跟踪系统是一种基于计算机视觉技术的应用,具有广泛的应用前景。本文以一款开源的目标跟踪系统——OpenCV的Tracker API为例,进行了实例分析。通过介绍KCF算法的实现原理和OpenCV目标跟踪系统的实现流程,可以更好地理解和应用目标跟踪技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值