# fDSST-UAV-Tracking **Repository Path**: Jason20602130/fDSST-UAV-Tracking ## Basic Information - **Project Name**: fDSST-UAV-Tracking - **Description**: No description available - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-01-02 - **Last Updated**: 2025-01-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 毕业设计代码 ## 改动kcftracker.cpp与kcftracker.hpp 删除了一些函数和多分支(LAB,FIXEDWINDOW等)的赋值,更改了namespace为dsst,程序运行流畅,720P帧数约为13FPS(70ms),帧数会依据第一帧初始化的框的大小而有较大改变 ## Parameters |参数名 |值 |含义| |:-:|:-:|:-| |translation:| | | | |detect\_thresh_kcf |0.13 |dont how to set| |template\_size |96 |template size in pixels, 0 to use ROI size,the value (template_size/cell_size) should be a power of 2 or a product of small prime numbers| |lambda |0.0001 |regularization| |padding |1.5 |area surrounding the target, relative to its size| |out_put_sigma_factor |0.125 |bandwidth of gaussian target| | | | | |if(hog)/else:| | | | |interp_factor |0.012/0.075 |linear interpolation factor for adaptation| |sigma |0.6/0.2 |gaussian kernel bandwidth| |cell_size |4/1 |hog cell size| | | | | |scale: | | | |n_scales |33 |number of scales| |scale_step |1.05 |a in DSST article | |scale_weight |0.95 |downweight detection scores of other scales for added stability| |scale_padding |1.0 |extra area surrounding the target for scaling| |scale_sigma_factor |0.25 |bandwidth of Gaussion| |scale_lr |0.025 |scale learning rate| |scale_max_area |512 |max ROI size before compressing| |scale_lambda |0.01 |regularization| ## Variables |变量名 |解释| |:-|:-| |全局变量| | | |_roi |input in init, output in update; | |_alphaf |位置滤波器| |_prob |理想输出,在init中创建,从未改变,用来训练位置滤波器| |_tmpl |先验知识模板,每一帧用它与本帧的特征做匹配,结束后用这一帧的特征更新模板| |_num |numerator: use to update as MOSSE,size与samples的相同 | |_den |denumerator: use to update as MOSSE,size为1*n_scale | |_size_patch |0:rows;1:cols;2:numFeatures; init in getFeatures(); | |scaleFactors |a^n in DSST article| |_scale_dsst |当前帧的尺度相对第一帧roi的参数,即当前预测的尺度绝对值就是_scale_dsst*base_width_dsst| |base_width_dsst |第一帧图像给的roi的尺寸| |scale_model_width |尺度预测中,所有尺度的图像块均要resize到这一尺寸后再进行hog特征的提取| |samples |尺度预测提取的样本集,size为x*n_scale| ## Functions --- ### init(); translation init + scale init. translation init: 1. **getFeature()**函数初始化_size_patch???,提取特征feature并初始化特征模板_tmpl 2. 用_size_patch创建_prob 3. 用_tmpl训练 **train()** 位置滤波器_alphaf scale init(init_scale+ tran_scale): 1. init_scale():初始化n_scale个尺度的值,储存在scaleFactors中 2. tran_scale():用scalesFactors提样本sample,并用它们训练尺度滤波器_num_dsst与_den_dsst --- ### update(); 1. 用detect()和detect_scale()函数检测出位置与尺度 2. 用train()和train_scale()函数更新位置滤波器和尺度滤波器 --- ### train(); #### 1.训练滤波器_alphaf step1 get_kxx

step2 get filter this frame

step3 update filter

#### 2.训练模板_tmpl

--- ### train_scale(); #### 1.获得特征samples #### 2.用samples训练尺度滤波器的分子_den_dsst与分母_num_dsst step1 get filter this frame

step2 update filter

- train_scale()的输入是原图,而train()的输入是特征 --- ### detect(); #### 输入: z = _tmpl 训练好的特征模板 x = getFeature(img) 当前帧图像块的特征 #### 输出: peak_value 峰值 res 预测的位置 #### 1.得到相关分数 相关分数:论文中的f(z),代码中的res step1 得到kxz step2 复数点除complexDotDivision得到res

step3 最大响应赋值给peak_value #### 2.得到分数最大位置pi、最终预测位置p step1 minMaxLoc()函数寻找pi step2 subPixelPeak() 改变pi至p --- ### get_sample_dsst() 获得多尺度尺度的特征 #### 1.得到待提取图像块的尺寸 ``` float patch_width = base_width_dsst * scaleFactors[i] * _scale_dsst; float patch_height = base_height_dsst * scaleFactors[i] * _scale_dsst; ``` #### 2.在原图中提取图像块 ``` cv::Mat im_patch = extractImage(image, cx, cy, patch_width, patch_height); ``` cx,cy均为本帧预测出的图像中心 #### 3.对图像块进行resize 统一resize到scale_model_width,scale_model_height的大小 scale_model_width,scale_model_height的来源: init_scale()函数中初始化,即该变量一经初始化后是不再变化的,大小为base_width_dsst x scale_model_factor,即: **若第一帧的图像块面积不大于max_area,那么以后提取的尺度图像块大小均与第一帧图像块的大小一样** --- ### detect_scale() 预测尺度 #### 1.得到samples ``` cv::Mat samples = DSSTTracker::get_sample_dsst(image); ``` samples的尺度是w*n_scale, w的含义未知 #### 2.求得分矩阵分子 ``` cv::reduce(complexDotMultiplication(_num_dsst, samples), add_temp, 0, CV_REDUCE_SUM); ``` reduce是将一个矩阵变成一个向量,即最后的add_temp尺寸为1*15, 与分母_den_dsst的尺寸相同 #### 3.求得分矩阵 ``` cv::idft(complexDotDivisionReal(add_temp, (_den_dsst + scale_lambda)), scale_response, cv::DFT_REAL_OUTPUT); ``` scale_response尺寸也为1*n_scale,即每个尺寸一个得分,求最高的 --- ### getFeature() 位置预测特征提取 #### 1. 中心点 中心点是_roi的中心点 ``` float cx = _roi.x + _roi.width / 2; float cy = _roi.y + _roi.height / 2; ``` #### 2. 特征区域大小 **KCF中的区域大小extracted_roi没有变化过,大小均是上一帧的roi大小乘padded** 即 ``` padded_w = _roi.width * padding; extracted_roi.width = padded_w; ``` --- ## 训练 训练分两种方式:MOSSE方式和KCF的方式,还没比较两种方法的速度,可能KCF更快,因为KCF是MOSSE后面提出的弄懂了KCF的原理提出的更新方法。 - KCF方式将滤波器看成一个整体进行更新,即更新_alphaf,OpenTracker项目中用的均是这种方法 - MOSSE方式分为分子和分母进行更新,即更新_num, _den,DSST论文中用的是这种方式 ## 亚像素极值点检测 subpixel peak detection 代码中的subpixelpeak()函数 参考博客[https://www.cnblogs.com/shine-lee/p/9419388.html](https://www.cnblogs.com/shine-lee/p/9419388.html) 此处使用抛物线近似

## 公式推导 为毕业设计成文方便,见公式推导.docx ## 关于HOG特征提取部分代码的阅读 该部分共三个函数(fhog.cpp): 1. getFeatureMaps(); 2. normalizeAndTruncate(); 3. PCAFeatureMaps(); --- ### getFeatureMaps()函数 变量表: |变量名 |变量含义 | |:- |:- | |k(cell_size) |cell size | |sizeX |待提取图横向有多少个cell | |sizeY |待提取图纵向有多少个cell | |width |待提取图的宽 | |height |待提取图的高 | |numChannels |待提取图的通道数 | |NUM_SECTOR |nbins 方向数 | |map |提取出的特征谱 | |kernel_dx |水平方向微分核 | |kernel_dy |垂直方向微分核 | |arg_vector |离散的方向角 i*pi/nbins | |boundary x |cos(arg_vector) | |boundary y |sin(arg_vector) | |dx |横向的梯度结果 size:width*height*numChannels | |dy |纵向的梯度结果 | |datadx |指向图第j行的微分值地址的指针 | |x,y |第i行,第j列,第c通道的横纵向梯度值 | |r |存梯度最大的通道的梯度绝对值 size:width*height | 函数步骤: step1 声明变量、存储空间 声明以上变量,声明map的存储空间 step2 滑动核求梯度 使用filter2D函数求得横纵向梯度dx,dy step3 计算梯度绝对值 计算三个通道的梯度值 ``` r = squar(x*x+y*y); ``` 取最大的梯度最大的存到r中 step4 计算梯度方向 用离散化的方向角计算 ``` dotProd = boundary_x[i]*x+boundary_y[i]*y; ``` 取最大的arg_vector[i]为方向角 step5 赋值给map --- ### allocFeatureMapObject()函数 声明特征谱(map)的空间,并将map全部赋值为0 函数原型 int allocFeatureMapObject(CvLSVMFeatureMapCaskade **obj, const int sizeX, const int sizeY, const int numFeatures) obj:结构体的名字 sizeX、sizeY、numFeatures:要声明的obj的参数 --- ## 关于编码格式 编码格式会影响opencv的解码速度,进而影响程序的整体运行速度 cap>>frame 这行代码运行时间长 经测试,H.264是较慢的编码格式,但MJEP的编码格式视频质量太差 想办法加速解码速度? ## 关于是否需要更新模板(interp_factor) 代码中关于模板更新的部分: step1. init函数中初始化_tmpl step2. train函数中用这一帧的特征更新_tmpl 若一直更新模板,那么跟踪算法用到的就不仅仅是第一帧目标的特征,若跟踪过程中出现一段较长时间的错误,则模板完全错误,无法再回到原目标,比如当视频中目标尺度略微变化,而跟踪框认为上一帧的尺度分数更高,那么这一帧的尺度就会更新入模板中,多有这样的几帧,算法所认为的尺度就完全发生变化了,就出现了再也跟不准尺度的现象。 若不更新模板,那么跟踪算法从头到尾只使用第一帧框出来的目标特征,而本算法中提取的是HOG特征,因此若不更新模板,对旋转的情况是完全不具有适应性的。 结论:在本场景中,保持一个较小的interp_factor是较为简单的解决方法 ## 关于参数template_size的重要性 原理性问题未知,只说现象: 1. template用在getFeature函数中。在位置滤波器进行初始化init时,对所提取的extracted_roi大小进行微调,虽然extracted_roi的大小仅有几个像素的变化,但是微调后的extracted_roi在提取特征时速度非常快。这样也是因为template_size的值的选取是有讲究的,一般取2的指数。越小速度越快但是容易跟不准,越大速度越慢但效果更好。这里取了128 2. 第一帧初始化后,位置滤波器提取的extracted_roi大小不再变化。 ## 关于位置滤波器的特征提取步骤 step1. 根据上一帧的roi大小(_scale_dsst * base_taget_sz)、padding得到这一帧的特征提取区域(extracted roi),这一区域尺寸是变化的 step2. extracted roi resize到一个固定的尺寸(_tmpl_sz),固定统一尺寸便于做相关运算,便于更新。 step3. 做相关运算,得到_tmpl_sz这个尺度上的响应最大位置坐标(res) step4. 根据resize的映射关系,将res映射回原图的尺度中 ``` real-shift = resized-shift * cell_size * _scale_dsst ``` ## 关于n_scale和scale_step的选择 ## TLD算法 各部分任务: tracker: 针对目标的运动进行预测(利用帧间关系) detector: 将每一帧视为独立的进行全图的检测,会存储目前未知所有的正负模板样本 learning: 观察tracker和detector,预测检测器的错误,产生样本去避免这些错误 detector: 全图检测方法:用窗口滑动滑出约50k个图像块,用cascaded方法逐步筛选出有目标的图像块 cascad方法:分成多个stage,一个stage是一个阈值条件,剔除一部分没有目标的图像块 stage1 Patch variance 灰度变化低于50的留下,其余的剔除,也叫variance filter stage2 Ensemble clssifier n个滤波器,每个滤波器产生一个code,对目标进行评价 stage3 Nearest neighbor classifier ## STAPLE算法 staple算法在DSST基础上加入了CN这一新的特征,即利用了颜色信息,分为template和histogram两个评价体系来预测位置,这个方法对于形变物体具有较好的适应性 ## 测试结果 --- ### PC各段时间测试 测试视频 201903062.MP4 h.264编码,n_sacle = 33 |主函数 |子函数 |时长(ms) | |:- |:- |:- | |总程序 | |23 | |解码 | |4 | |init | |3.404 | |update | |19.3 | |update |tranlation estimation |3 | |update |scale estimation |6.5 | |update |filter train |9.6 | --- ### n_scale与scale_step的修改 --- #### 速度测试 测试视频 201903062.MP4 h.264编码,n_sacle = 9 |主函数 |子函数 |时长(ms) | |:- |:- |:- | |总程序 | |12.679 | |解码 | |4 | |init | |\ | |update | |8.533 | |update |tranlation estimation |3.337 | |update |scale estimation |1.46 | |update |filter train |4.64 | 测试视频 201903062.MP4 h.264编码,n_sacle = 20, PC |主函数 |子函数 |时长(ms) | |:- |:- |:- | |总程序 | |15.2 | |解码 | |4 | |init | |\ | |update | |11.54 | |update |tranlation estimation |2.68 | |update |scale estimation |5.7 | |update |filter train |6.7 | 测试视频 landing19030722.MP4 h.264编码,n_sacle = 15 scale_step = 1.1, PC |主函数 |子函数 |时长(ms) | |:- |:- |:- | |总程序 | |36.4 | |解码 | |4 | |init | |\ | |update | |32.2 | |update |tranlation estimation |3.68 | |update |scale estimation |16.2 | |update |filter train |12.25 | #### 调参事项 1. 最终是要找到一条很好的尺度变化曲线 2. 当尺度过小时,如8时,尺度结果始终是1,即没有响应,当15时开始有响应 3. 论文中给出的n_scale是33,scale_step是1.05 4. 速度是和第一帧的roi大小相关的,因为后面提取的图像块都要resize到base_scale上再提hog特征 --- ### manifold test 测试视频 DJI_0144.MP4 n_sacle = 15 MPED4, MANIFOLD |主函数 |子函数 |时长(ms) | |:- |:- |:- | |总程序 | |62 | |解码 | |10 | |init | |29 | |update | |50 | |update |tranlation estimation |20 | |update |scale estimation |6 | |update |filter train |24 | 测试视频 scale1.MP4 n_sacle = 15 h.264, MANIFOLD, init window 119*114 |主函数 |子函数 |时长(ms) | |:- |:- |:- | |总程序 | |117 | |解码 | |61 | |init | |\ | |update | |56 | |update |tranlation estimation |22 | |update |scale estimation |6 | |update |filter train |27.7 | 测试视频 landing2.MP4 n_sacle = 15 h.264, MANIFOLD, init window 132*118 |主函数 |子函数 |时长(ms) | |:- |:- |:- | |总程序 | |117 | |解码 | |61 | |init | |\ | |update | |97 | |update |tranlation estimation |35 | |update |scale estimation |6 | |update |filter train |46 | ## 待拍摄(测试)的数据 ## 日志 3.18. 视频末端被跟踪物体变大后位置滤波器很容易出问题,出现漂移的问题 原因:位置滤波器提取特征的大小只与第一帧大小有关,以后不再变大,第一帧只有70*70像素的目标最后变成了300*300的大小,位置滤波器还是以120*120的大小在提特征 3.19. 继续测试视频,对3.18.的问题寻找解决方法。 目前的思考是,虽然特征框不再变大,但由于靶标是内嵌的,因此内部也是有HOG信息的,对于靶标这种跟踪物体来说,位置滤波器的大小不变是没有问题的,即目标变大,位置滤波器提取的特征就是内部的HOG特征。只需要稍稍增大学习率(0.012->0.1),让模板更新稍稍变快即可。因此现在在对学习率进行调整。但是问题还没有得到解决。 对于舰船这种目标,可能内部特征不是很好,没有什么轮廓、纹理。 另一种思路是让extracted_roi大小跟着变化,但是提取尺寸的问题还没得到很好的解决 晚上解决了18号的问题,在阅读了原论文matlab版代码后,发现matlab代码在位置滤波器提取特征时使用的extracted_roi大小: ``` patch_sz = floor(model_sz * currentScaleFactor); ... ... ... ...(subwindow img and get im_patch) im_patch = resize(im_patch, model_sz); ``` 即先用currentScaleFactor(本代码中的_scale_dsst)乘model_sz(=base_target_sz*padding)得到本帧提取的区域大小(变化的),提取子区域后,在resize到统一的model_sz(不变的)大小,用resize后的图像提取hog特征。再用这个特征去做相关得到最后的响应,取响应最大处得到位置预测结果,再用resize的关系将resize后的最大响应坐标映射回原图中: ``` _roi.x = _roi.x + res.x * cell_size * _scale_dsst; _roi.y = _roi.y + res.y * cell_size * _scale_dsst; //realshift = resizedshift * cell_size * _scale_dsst ``` 另外在测试DJI_0144视频的时候,尺度滤波器没有跟上尺度的变化,因此稍稍减小了scale filter的lr(0.025->0.02),减小了scale_step(1.05->1.03) 3.20. 目前计划:1.测试视频,继续找bug;2. 优化尺度曲线;3. 优化参数 3.25. 讨论了毕业设计要做的工作 1.近处跟踪靶标的软件已基本完成,对尺度、位移适应性较强 2.需要完成的新功能,在远处识别到舰船后,用视觉跟踪舰船,这一部分就需要对旋转亦有适应性,因此需要使用新的算法,对于新算法的速度问题,解决方法有二:使用GPU;硬件平台使用TX2或manifold2 3.27. 调研了目前的目标跟踪算法对于旋转的适应性 旋转的适应性分为两种:非平面的旋转(out-of-plain rotation)和平面内的旋转 - 平面内的旋转,目前有些方法可以解决,ECO算法可以解决,另一种叫LDES(AAAI 2019)的算法也可以同时尺度和平面内旋转的问题,它将图像放在对数极坐标(log-polar),在极坐标中尺度和旋转就变成了普通的位移,这种在对数极坐标中的方法亦称为傅立叶梅林方法 - 平面外的旋转,目前ECO称对平面外的旋转具有适应性,但论文中给出的例子也不是很理想 在TX2上对目前的fDSST程序进行了测试,速度并没有明显的提升,随后对程序的各个部分进行了详细的测试 目前耗时较长的几个模块: 1. getFeature(); 大小为247*232的图像块,耗时14ms 2. get_sample_dsst(); 大小为247*232的图像块,耗时17ms 3. gaussianCorrelation(); 大小为196*185的图像块,耗时8ms 归结起来(主耗时程序): translation estimation = getFeature()+detect() detect() = gaussioncorrelation() scale estimation = get_sample_dsst() translation train = getFeature()+gaussioncorrelation() scale estimation = get_sample_dsst() 3.28. 打算用gpu加速hog特征的提取 阅读了fDSST中HOG特征的提取过程 阅读了opencv sample中HOG特征提取的例程 还没有依照例程实现gpu提取HOG特征 3.29. 使用opencv中封装好的HOG特征提取的函数,报错,没有运行成功,返回学习cuda编程基础,想看懂代码 4.2. 无GPU,有了效果较好的一版 ``` detect_thresh_kcf = 0.13; detect_thresh_dsst = 0.15; lambda = 0.0001; padding = 1.5; output_sigma_factor = 0.125; //0.1 if (hog) { // HOG - KCF // VOT interp_factor = 0.1; sigma = 0.6; // TPAMI //interp_factor = 0.02; //sigma = 0.5; cell_size = 4; //hog cell size = 4; _hogfeatures = true; } else { // RAW - CSK // interp_factor = 0.075; interp_factor = 0.01; sigma = 0.2; cell_size = 1; //just pixel; _hogfeatures = false; } //multiscale========= template_size = 128; // 64 or 96 is a little small; scale_weight = 0.95; //dsst=================== scale_step = 1.03; n_scales = 15; // _dsst = true; _scale_dsst = 1; scale_padding = 1.0; scale_sigma_factor = 0.25; scale_lr = 0.02; scale_max_area = 512; scale_lambda = 0.01; ``` 4.2.测试视频小结 使用DJI无人机拍摄的视频进行测试 1.帧率 视频分辨率640*360 程序帧数可稳定在20fps以上 2.各项适应性 - 快速移动:具有较好的适应性(car8) - 尺度变化:具有较好的适应性(boat1) - 小目标(20*30):跟踪不稳定,跟踪框有些抖动(boat6) - 旋转:不具有适应性(boat5) - 会车、会船:若跟踪框内背景较少,可适应,若跟踪框内包括了其他船,无法适应(boat5,car3) - 遮挡:不具有适应性(car4) 4.4. 使用opencv cuda库提取hog特征: 出现以下问题: 1.目标图片过小时,程序报错 2.hog特征如何转化成程序中可用的特征图(feature map)未知 feature map使用的fhog特征,一方面size较小,另一方面提取较快 4.6. TLD论文 STAPLE论文 SSE及NEON:SSE是英特尔开发的单指令多数据流指令集(SIMD),类似于并行处理的原理让它可以对一些算法进行加速,neon和sse类似,是属于ARM Cortex A系列的扩展结构。 4.7, 找到了staple的代码,运行测试后发现比只用DSST效果好很多: - 能基本解决非平面旋转的问题 - 能解决短时间遮挡的问题 - 适用neon加速提取fhog特征,720P速度在20帧左右 - 尺度部分偶尔会逐渐放大,需要debug