TLD之跟踪篇(三)

article/2025/9/22 4:46:23

TLD之跟踪篇(三)

TLD之扯淡篇(一)、 TLD之检测篇(二) TLD之学习篇(四)

    目标跟踪的一般思想是跟踪目标中关键点。TLD也是跟踪点(但不是跟踪SIFT之类的关键点)。点跟踪采用的是光流法,具体来说是Pyramidal Lucas-Kanade tracker,这个以后机会再介绍,推荐阅读《Learning OpenCV》第10章的Lucas-Kanade Method部分,这里只介绍OpenCV的实现函数,跳过原理和实现细节。

    首先看跟踪点的函数,calcOpticalFlowPyrLK,它的作用是找到上一帧中的跟踪点在当前帧的位置。调用形式如下:

calcOpticalFlowPyrLK( img_last,img_currpoints_last points_curr, status, errs)

    参数意思应该很直白了吧,补充一下status为1,表示对应点找到了,为0就是没找到,errs自然是误差。注意:可以是单个点,也可以是点集,如果是点集,那么对应的status和errs就都是vector啦。

    下面说说怎么跟踪目标,TLD采用的是基于作者自己提出的Median-Flow tracker,此外增加了跟踪失败检测。

通过Forward-Backward error来筛选要跟踪的点

    前面提到TLD跟踪的不是关键点,它跟踪的是更简单的点:能稳定存在的点,那哪些点是稳定的呢?Median-Flow tracker的基本思想是,看反向跟踪后的残差,用所有点的残差中值作为稳定点的筛选条件。如上图中的黄色点就因为残差太大,被pass掉了,既然稳定点是可以筛选出来的,那么就不必煞费苦心的寻找那些关键点,可以直接将所有的点都作为初始跟踪点,好吧所,有的点毕竟还是太多了,于是作者是选取网格交叉点作为初始跟踪点(见下图框框中黄色的点点)。

 

Median Flow tracker 的流程图

    下面正式介绍作者的跟踪函数TLD::track调用形式如下:

track(img1,img2,points1,points2)

    img1是上一帧的图像,img2是当前帧的图像,points1,points2都是这个函数的输出函数,points1是将上一次跟踪到的目标区域lastbox划分成网格后,所得到的网格交点,即上图左边的黄色点,而points2是points1中能稳定出现在当前帧出的点,即右图中的点

    下面结合上面的流程图,并补充TLD需要增加的环节,来介绍track。

TLD::track函数

void TLD::track(const Mat& img1, const Mat& img2,vector<Point2f>& points1,vector<Point2f>& points2){//【5.4】// 1.Generate pointsbbPoints(points1,lastbox);if (points1.size()<1){//问题:何时会出现这种情况??printf("BB= %d %d %d %d, Points not generated\n",lastbox.x,lastbox.y,lastbox.width,lastbox.height);tvalid=false;tracked=false;return;}vector<Point2f> points = points1;//Frame-to-frame tracking with forward-backward error cheking// 2. 推断上一帧的points,在当前帧的位置,points->points2// 注意:只有通过筛选的point对 还保留在points,points2tracked = tracker.trackf2f(img1,img2,points,points2);if (tracked){//只要有一个点跟到了,就算跟到了……,是不是应该严格一点呢??// 3. Bounding box predictionbbPredict(points,points2,lastbox,tbb);//此时,lastbox,还是依据上一帧预测的目标在当前帧的位置
<span style="white-space:pre">	</span>  // 4. Failure detection,检测 getFB()>10 || 完全出轨 if (tracker.getFB()>10 || tbb.x>img2.cols ||  tbb.y>img2.rows || tbb.br().x < 1 || tbb.br().y <1){//br() bottom right坐标tvalid =false; //too unstable prediction or bounding box out of imagetracked = false;printf("Too unstable predictions FB error=%f\n",tracker.getFB());return;}// 5. Estimate Confidence and ValidityMat pattern;Scalar mean, stdev;BoundingBox bb;bb.x = max(tbb.x,0);bb.y = max(tbb.y,0);bb.width = min(min(img2.cols-tbb.x,tbb.width),min(tbb.width,tbb.br().x));//问题:我觉得后面的min没必要呀??bb.height = min(min(img2.rows-tbb.y,tbb.height),min(tbb.height,tbb.br().y));getPattern(img2(bb),pattern,mean,stdev);vector<int> isin;float dummy;classifier.NNConf(pattern,isin,dummy,tconf); //1.tconf是用Conservative Similaritytvalid = lastvalid;<span style="white-space:pre">	</span>  if (tconf>classifier.thr_nn_valid){//thr_nn_validtvalid =true;//2.判定轨迹是否有效,从而决定是否要增加正样本,标志位tvalid【5.6.2 P-Expert】}}elseprintf("No points tracked\n");
}

1.Initialize points to grid

    将bb切成10*10的网格,将网格交点存在points,函数为TLD::bbPoints

//将bb切成10*10的网格,将网格交点存在points
void TLD::bbPoints(vector<cv::Point2f>& points,const BoundingBox& bb){int max_pts=10;int margin_h=0;//留白没有用到int margin_v=0;int stepx = ceil((bb.width-2*margin_h)/max_pts);//向上取整int stepy = ceil((bb.height-2*margin_v)/max_pts);for (int y=bb.y+margin_v;y<bb.y+bb.height-margin_v;y+=stepy){for (int x=bb.x+margin_h;x<bb.x+bb.width-margin_h;x+=stepx){points.push_back(Point2f(x,y));//最多有11*11=121个点}}
}

2.Track points
3.Estimate tracking error
4.Filter out outliers

    这三步都在函数trackf2f 中,调用层次关系tld.processFrame->track->[tracked = tracker.trackf2f(img1,img2,points,points2)]

//points1->points2,由于调用了filterPts,所以只有通过筛选的point对还保留在points1,points2
bool LKTracker::trackf2f(const Mat& img1, const Mat& img2,vector<Point2f> &points1, vector<cv::Point2f> &points2){//TODO!:implement c function cvCalcOpticalFlowPyrLK() or Faster tracking function//1. Track points,Forward-Backward trackingcalcOpticalFlowPyrLK( img1,img2, points1, points2, status,similarity, window_size, level, term_criteria, lambda, 0);calcOpticalFlowPyrLK( img2,img1, points2, pointsFB, FB_status,FB_error, window_size, level, term_criteria, lambda, 0);//2. Estimate tracking error,Compute the real FB-errorfor( int i= 0; i<points1.size(); ++i ){FB_error[i] = norm(pointsFB[i]-points1[i]);//残差为欧氏距离【ICPR 2】}//3.Filter out outliers//Filter out points with FB_error[i] > median(FB_error) && points with sim_error[i] > median(sim_error)normCrossCorrelation(img1,img2,points1,points2);return filterPts(points1,points2);
}

    其中normCrossCorrelation(img1,img2,points1,points2)是对光流法跟踪的结果不放心,因此希望通过对比前后两点周围的小块的相似性,来进一步去掉不稳定的点。这次的相似性不是相关系数,而是normalized cross-correlation (NCC):

 

    这个比较复杂,建议看wiki的公式,其实还是前面提到的相关系数,只不过计算的时候需要自己减去均值。

void LKTracker::normCrossCorrelation(const Mat& img1,const Mat& img2, vector<Point2f>& points1, vector<Point2f>& points2) {Mat rec0(10,10,CV_8U);Mat rec1(10,10,CV_8U);Mat res(1,1,CV_32F);for (int i = 0; i < points1.size(); i++) {if (status[i] == 1) {//跟踪到了getRectSubPix( img1, Size(10,10), points1[i],rec0 );//以points1[i]为中心,提取10*10的小块getRectSubPix( img2, Size(10,10), points2[i],rec1);matchTemplate( rec0,rec1, res, CV_TM_CCOEFF_NORMED);//Cross Correlation similarity[i] = ((float *)(res.data))[0];} else {similarity[i] = 0.0;}}rec0.release();rec1.release();res.release();
}

    该计算的都计算好了,终于可以筛选了, filterPts( points1, points2)
//Filter out points with FB_error[i] > median(FB_error) && points with sim_error[i] > median(sim_error)
bool LKTracker::filterPts(vector<Point2f>& points1,vector<Point2f>& points2){//Get Error Medianssimmed = median(similarity);//NCC中值size_t i, k;for( i=k = 0; i<points2.size(); ++i ){//前向筛选,没跟踪到的不要if( !status[i])continue;if(similarity[i]> simmed){//normalized crosscorrelation (NCC)筛选,比对前后两点周围的小块points1[k] = points1[i];points2[k] = points2[i];FB_error[k] = FB_error[i];k++;}}if (k==0)return false;points1.resize(k);points2.resize(k);FB_error.resize(k);fbmed = median(FB_error);//残差中值for( i=k = 0; i<points2.size(); ++i ){//后向筛选,找到了,但是偏离太多if( !status[i])continue;if(FB_error[i] <= fbmed){points1[k] = points1[i];points2[k] = points2[i];k++;}}points1.resize(k);points2.resize(k);if (k>0)return true;elsereturn false;
}

5.Update bounding box

    bbPredict(points,points2,lastbox,tbb), points和points2是前面筛选完之后的点对,现在要依据points,points2来估计bb1的位移尺度变化,这两个信息都有了,自然可以决定lastbox在当前帧的位置tbb。

位移估计

   位移估计的方法是用所有点对x,y位移的中值作为位移的估计,如上图。尺度的估计的方法是用所有点对(同一帧)的伸缩比的中值作为尺度伸缩的估计,假设只有一堆点,尺度伸缩值的估计方式如下图:

尺度估计

//依据points1,points2估计bb1的位移和尺度变化,这两个信息都有了,自然可以决定其范围bb2
void TLD::bbPredict(const vector<cv::Point2f>& points1,const vector<cv::Point2f>& points2,const BoundingBox& bb1,BoundingBox& bb2)    {int npoints = (int)points1.size();vector<float> xoff(npoints);vector<float> yoff(npoints);printf("tracked points : %d\n",npoints);// 用位移的中值,作为目标位移的估计for (int i=0;i<npoints;i++){xoff[i]=points2[i].x-points1[i].x;yoff[i]=points2[i].y-points1[i].y;}float dx = median(xoff);//float dy = median(yoff);float s;// 用点对之间的距离的伸缩比例的中值,作为目标尺度变化的估计if (npoints>1){vector<float> d;d.reserve(npoints*(npoints-1)/2);for (int i=0;i<npoints;i++){for (int j=i+1;j<npoints;j++){
<span style="white-space:pre">			</span>  //之前比较的都是对应点之间的相似性,现在计算的是任意两点的相似性,所以更能反映拓扑结构的变化
<span style="white-space:pre">			</span>  //问题:假设比值是s,那么加个min(s,1/s)不是更好吗????
<span style="white-space:pre">			</span>  //呃,好吧,亲你又YY了,这一步不是干这个的好吗?,so,这三行都忽略d.push_back(norm(points2[i]-points2[j])/norm(points1[i]-points1[j]));}}s = median(d);//}else {s = 1.0;}float s1 = 0.5*(s-1)*bb1.width;// top-left 坐标的偏移(s1,s2)float s2 = 0.5*(s-1)*bb1.height;printf("s= %f s1= %f s2= %f \n",s,s1,s2);bb2.x = round( bb1.x + dx -s1);bb2.y = round( bb1.y + dy -s2);bb2.width = round(bb1.width*s);bb2.height = round(bb1.height*s);printf("predicted bb: %d %d %d %d\n",bb2.x,bb2.y,bb2.br().x,bb2.br().y);
}

6.Failure detection

    这一步很简单,原文是说A failure of the tracker is declared if  pixels,其中是残差的中值,残差即反向跟踪和原始跟踪点的距离。不过程序里面还要防止目标飞到图像外面去了。

if (tracker.getFB()>10 || tbb.x>img2.cols || tbb.y>img2.rows || tbb.br().x < 1 || tbb.br().y <1){//br() bottom right坐标
tvalid =false; //too unstable prediction or bounding box out of image
tracked = false;
printf("Too unstable predictions FB error=%f\n",tracker.getFB());
return;
}

7.Estimate Confidence and Validity

Mat pattern;
Scalar mean, stdev;
BoundingBox bb;
bb.x = max(tbb.x,0);
bb.y = max(tbb.y,0);
bb.width = min(min(img2.cols-tbb.x,tbb.width),min(tbb.width,tbb.br().x));// bb.height = min(min(img2.rows-tbb.y,tbb.height),min(tbb.height,tbb.br().y));
getPattern(img2(bb),pattern,mean,stdev);
vector<int> isin;
float dummy;
classifier.NNConf(pattern,isin,dummy,tconf); //1.tconf是用Conservative Similarity
tvalid = lastvalid; 
if (tconf>classifier.thr_nn_valid){//thr_nn_valid
tvalid =true;//2.判定轨迹是否有效,从而决定是否要增加正样本,标志位tvalid【5.6.2 P-Expert】
}

    注释很清楚了,大家可以先忽略判定轨迹是否有效这一部分,只要知道它是用最近邻分类器的Conservative Similarity【5.2】作为跟踪目标的得分即可,后面要用这个分数和检测器进行比较。


http://chatgpt.dhexx.cn/article/3uPSIyhC.shtml

相关文章

项目中tld文件使用

原理及作用&#xff1a; TLD术语解释&#xff1a;标签库描述文件&#xff0c;如要在JSP页面中实现JSP标签&#xff0c;必须首先定义实现标签的类&#xff0c;然后在标签库描述文件&#xff08;TLD&#xff09;中 将写好的类映射成JSP标签,最后在JSP文件中使用定义好的标签&a…

什么是.tld文件

TLD术语解释&#xff1a;标签库描述文件. 如要在JSP页面中实现JSP标签&#xff0c;必须首先定义实现标签的类&#xff0c;然后在…

Tracking-Learning-Detection原理分析

转自http://johnhany.net/2014/05/tld-the-theory/ Tracking-Learning-Detection&#xff08;TLD&#xff09;是Zdenek Kalal提出的一种对视频中单个物体长时间跟踪的算法。我主要会根据他在2010年发表的论文《Tracking-Learning-Detection》来分析TLD算法的原理。该项目的首页…

TLD算法简介

TLD算法简介 TLD&#xff08;Tracking-Learning-Detection&#xff09;是 Zdenek Kalal 等人于 2009 至2012 年期间提出的单目标、长时间图像跟踪算法。与传统的单一跟踪算法相比&#xff0c;TLD 跟踪算法融合了跟踪器、检测器和学习模块三个部分&#xff0c;既能够对连续运动目…

行列式的逆序数定义

行列式的逆序数定义是一个直接定义&#xff0c;但并不直观。在实际计算中很少直接使用。因为计算逆序数的时间复杂度总是O(N^2), 总的时间复杂度确实O(n!), 所以计算机也不是用这个算法来计算的。 这个定义的好处是可以看清行列式的大概结构&#xff0c;用于定性计算&#xff0…

ACM 逆序对(逆序数)总结

最近做题遇到几次逆序数了&#xff0c;今天总结一下&#xff0c;以后遇到了再也不怕了。 首先说明一下什么是逆序数&#xff0c;下面是百度的定义&#xff1a; 在一个排列中&#xff0c;如果一对数的前后位置与大小顺序相反&#xff0c;即前面的数大于后面的数&#xff0c;那么…

排列的逆序数

百度百科&#xff1a; 在一个排列中&#xff0c;如果一对数的前后位置与大小顺序相反&#xff0c;即前面的数大于后面的数&#xff0c;那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。也就是说&#xff0c;对于n个不同的元素&#xff0c;先规定各元素之…

逆序数算法

原题 在一个排列中&#xff0c;如果一对数的前后位置与大小顺序相反&#xff0c;即前面的数大于后面的数&#xff0c;那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。 如2 4 3 1中&#xff0c;2 1&#xff0c;4 3&#xff0c;4 1&#xff0c;3 1是逆序…

C语言计算逆序数

从键盘任意输入一个3为整数&#xff0c;编程计算并输出它的逆序数&#xff08;忽略整数前的正负号&#xff09;。例如&#xff0c;输入-123&#xff0c;则忽略负号&#xff0c;由其百位1、十位2、个位3&#xff0c;然后计算3*1002*101 321&#xff0c;并输出321。 输入格式要…

迁移率随载流子浓度变化

载流子迁移率随载流子浓度变化&#xff0c;弱场下几乎保持恒定&#xff0c;然而随着载流子浓度变大&#xff0c;迁移率开始下降 从上面的公式可以得出&#xff0c;在浓度很小的时候&#xff0c;迁移率保持在最大值&#xff0c;当浓度比参考浓度大很多的时候&#xff0c;迁移率…

半导体器件物理 2022.10.13

漂移电流由两部分组成 扩散电流 扩散电流漂移电流就是总的电流&#xff0c;在实际问题中漂移电流远远大于扩散电流 空间电荷限制电流&#xff0c;对于本征半导体和一些绝缘体里面的电流&#xff0c;我们的作业 我们首先忽略我们的扩散电流&#xff0c;只考虑扩散电流 电流密度…

半导体材料参数介绍-很有用

上期文章我们最后提到了半导体参数&#xff0c;之所以专门挑一篇文章来说&#xff0c;因为它确实比较重要&#xff0c;可以让我们明白当前各种半导体材料的优势与劣势的原因。 不仅如此&#xff0c;还可以让我们明白一些东西&#xff0c;特别是二极管和三极管的一些特性。 其实…

silvaco-mobility models(1)

1.前一阶段的问题 大概接触了一段时间的silvaco&#xff0c;根据《InP基PIN开关二极管结构设计与制备》这篇文章提供的结构和一些简单的参数进行仿真。因为已经工作&#xff0c;没有老师在自己摸索&#xff0c;学习期间看到很多人写的心得或理解&#xff0c;或多或少都对我有所…

研究蛋白和DNA的相互作用—EMSA(凝胶迁移或电泳迁移率实验),可用于DAP-seq后续验证

技术简介 凝胶迁移或电泳迁移率实验&#xff08;EMSA,Electrophoretic Mobility Shift Assay&#xff09;是研究DNA结合蛋白和其相关的DNA结合序列相互作用的技术&#xff0c;可用于定性和定量分析。可用于DAP-seq后续验证实验。 EMSA实验&#xff0c;基于生物素标记探针与对应…

网络迁移学习率调整思路

在将HRNet从PyTorch框架向MindSpore迁移的过程中&#xff0c;由于初始学习率的选择不好&#xff0c;导致了最终精度没有达到预期要求。 文末有总结。 具体实验过程如下&#xff1a; 实验过程 优化器&#xff1a;SGD 初始学习率&#xff1a;0.01 学习率调整策略&#xff1a;p…

【迁移攻击笔记】数据集の变化→提高迁移率!Improving Transferability of Adversarial Examples with Input Diversity

1.作案动机 已知&#xff1a; 迭代攻击&#xff08;eg.I-FGSM&#xff09;过拟合且易陷入局部最优&#xff0c;不适合迁移。 单步攻击&#xff08;eg.FGSM&#xff09;欠拟合&#xff0c;不适合迁移。 对输入进行图像处理可以有效抵抗对抗攻击。 推测&#xff1a; 图像处理之后…

为什么NMOS管比PMOS管用得多--电子迁移率-宽禁带-半导体材料参数介绍

上期文章我们最后提到了半导体参数&#xff0c;之所以专门挑一篇文章来说&#xff0c;因为它确实比较重要&#xff0c;可以让我们明白当前各种半导体材料的优势与劣势的原因。 不仅如此&#xff0c;还可以让我们明白一些东西&#xff0c;特别是二极管和三极管的一些特性。 其实…

silvaco 第三章迁移率模型

记录模型都是什么 都用了什么 低场迁移率&#xff1a; 1 MUN and MUP parameters to set constant values for electron and hole mobilities and optionally specify temperature dependence. 2 using a look-up table model (CONMOB) to relate the low-field mobility at…

基于形变势理论计算载流子迁移率

载流子迁移率通常指半导体内部电子和空穴整体的运动快慢情况&#xff0c;是衡量半导体器件性能的重要物理量&#xff0c;例如对石墨烯、黑磷等二维材料展现出的高载流子迁移率的研究。由于电子在运动过程中不仅受到外电场力的作用&#xff0c;还会不断的与晶格、杂质、缺陷等发…

Silvaco 学习笔记 3——物理模型:迁移率模型

迁移率模型一般可以分为一下四种&#xff1a; 1.低场行为&#xff1a;此时载流子与晶格几乎处于平衡&#xff0c;其迁移率具有典型的低场值&#xff0c;一般用来表示。 低场载流子的迁移率可以采用5种不同的方式进行定义&#xff1b; 第一种方法使用MUN和MUP参数设置电子和空穴…