相关滤波之开篇Mosse原理及代码详解

2023-11-03

相关滤波之开篇Mosse原理及代码详解

本文主要介绍相关滤波算法开篇——mosse具体原理及其python代码实现流程

相关滤波(Correlation Filter )介绍

相关滤波(CF)源于信号处理领域,有这么一句话“两个信号越相似,其相关值越高。在跟踪,就是找到与跟踪目标响应最大的项” 贯穿了整个相关滤波算法的根本。

2010年CVPR,David S.Bolme在文章《visual object tracking using adaptive correlation filters》中首次将相关滤波用在了跟踪领域,在其文章的基础之上,很多改进的算法相继出现,跟踪的效果也越来越好。

两个信号之间的相关为,
( f ⊗ g ) ( τ ) = ∫ ∞ − ∞ f ∗ ( t ) g ( t + τ ) d t (f\otimes g)(\tau)=\int_\infty^{-\infty}f^*(t)g(t+\tau)dt (fg)(τ)=f(t)g(t+τ)dt ( f ⊗ g ) ( n ) = ∑ − ∞ ∞ f ∗ [ m ] g ( m + n ) (f\otimes g)(n)=\sum_{-\infty}^\infty f^*[m]g(m+n) (fg)(n)=f[m]g(m+n) 其中f表示f的复共轭。correlation的直观解释就是衡量两个函数在某个时刻相似程度。
在图像中相关滤波意思就是输入图像(框选的目标)跟滤波器之间做一个相关操作,相关操作类似卷积操作(卷积需要反转,相关不用),相关操作如下图所示。
在这里插入图片描述
这里要注意输入图像f,滤波器h,及相应输出g的大小是完全一样的。

在这里插入图片描述
相关滤波意思就是现在在第一帧图像中框选了一个目标,然后对这个目标训练一个滤波器(大小相同)使得其输出响应g(大小相同)在中间值最大。其中输入图像给定,响应图也是可以直接生成的。一般都是用高斯函数,中间值最大,旁边逐渐降低。

然后滤波器的值推导过程类似于机器学习的线性回归
m i n H ∗ = ∑ i = 1 m ∣ H ∗ F i − G i ∣ 2 min_{H^*}=\sum _{i=1}^m|H^*F_i-G_i|^2 minH=i=1mHFiGi2
就是要找一个滤波器H*使得其上式的结果最小,其实也就是找到一个滤波器,使得其响应在中间的值最大,这就是利用了相关滤波器的原理。
然后根据数学求导,各种计算规则(有兴趣的可以看下原来论文,步骤很详细,这里就不展示了),最终可以得到
H w v = ∑ i F i w v G i w v ∗ ∑ i F i w v F i w v ∗ H_{wv}={\sum _i F_{iwv}G^*_{iwv}\over \sum _i F_{iwv}F^*_{iwv} } Hwv=iFiwvFiwviFiwvGiwv上面得到是H中每个元素的值,最后得到H为:
H = ∑ i F i ⋅ G i ∗ ∑ i F i ⋅ F i ∗ H={\sum _iF_i\cdot G^*_i \over \sum _iF_i\cdot F^*_i } H=iFiFiiFiGi上式就是滤波器的模型公式。
其中的G为高斯函数矩阵的傅里叶变换,F为输入目标图矩阵的傅里叶变换,都是用的快速傅里叶变换(FFT),这块不懂的可以查看快速傅里叶变换

然后为了具有更好的鲁棒性,滤波器采用迭代的方法 H t = A t B t H_t={A_t\over B_t} Ht=BtAt A t = η F t ⋅ G t ∗ + ( 1 − η ) A t − 1 A_t=\eta F_t \cdot G^*_t +(1-\eta)A_{t-1} At=ηFtGt+(1η)At1 B t = η F t ⋅ F t ∗ + ( 1 − η ) B t − 1 B_t=\eta F_t \cdot F^*_t +(1-\eta)B_{t-1} Bt=ηFtFt+(1η)Bt1更新参数为η,每一帧的滤波器都与上一帧的取值有关。
至此,第一帧图像目标框选之后就得到了一个设计好的滤波器,然后对第二帧图像提取目标区域对其与刚才的滤波器先进行傅里叶变换进行卷积之后逆向傅里叶变换找最大响应值,这个响应值的位置就是第二帧图像的待追踪目标的中心。

每一步目标图像在傅里叶变换前还要进行一些预处理
(1)FFT卷积算法需要将图像和滤波器映射到拓扑结构上,边界采用循环图像的方式填充,即将图像的左边缘连接到右侧边缘,将顶部连接到底部。
(2)采用点乘余弦窗处理,使图像边缘慢慢变成零。
在代码中都有所体现

接下来讲代码,附上GitHub链接
是python代码(因为对python比较熟悉)
项目根目录下主要有
datasets文件夹(用于存放跟踪图片集)
examples文件夹(用于存放gif动图,可不用)
demo.py (主程序,用于初始化参数,及运行各个函数)
mosse.py(跟踪算法的实现)
utils.py(一些图像处理操作)

代码解读

接下来分别介绍下各个具体模块的代码首先是主程序demo.py

from mosse import mosse
import argparse

parse = argparse.ArgumentParser()
parse.add_argument('--lr', type=float, default=0.125, help='the learning rate')
parse.add_argument('--sigma', type=float, default=100, help='the sigma')
parse.add_argument('--num_pretrain', type=int, default=128, help='the number of pretrain')
parse.add_argument('--rotate', action='store_true', help='if rotate image during pre-training.')
parse.add_argument('--record', action='store_true', help='record the frames')

if __name__ == '__main__':
    args = parse.parse_args()
    img_path = 'datasets/surfer/'

    tracker = mosse(args, img_path)
    tracker.start_tracking()

其中下半部分为主程序,进行参数的赋值,图像路径的赋值,跟踪器的设计,开始跟踪
上半部分为参数的赋值,为python自带模块argparse 的使用。

其次是
mosse.py
这里定义了一个mosse类 用于mosse算法的实现
主要就是一个方法

    def start_tracking(self):
        # 得到图像的第一帧
        init_img = cv2.imread(self.frame_lists[0])
        init_frame = cv2.cvtColor(init_img, cv2.COLOR_BGR2GRAY)
        init_frame = init_frame.astype(np.float32)
        # 在第一帧中框选中需要的目标区域
        init_gt = cv2.selectROI('demo', init_img, False, False)
        init_gt = np.array(init_gt).astype(np.int64)
        # 得到当前的高斯响应
        response_map = self._get_gauss_response(init_frame, init_gt)
   
        # 得到目标图像大小的高斯响应图
        g = response_map[init_gt[1]:init_gt[1]+init_gt[3], init_gt[0]:init_gt[0]+init_gt[2]]
        #原始图像
        fi = init_frame[init_gt[1]:init_gt[1]+init_gt[3], init_gt[0]:init_gt[0]+init_gt[2]]
        #进行傅里叶变换
        G = np.fft.fft2(g)
        # 预处理
        Ai, Bi = self._pre_training(fi, G)
        # 开始跟踪
        for idx in range(len(self.frame_lists)):
            current_frame = cv2.imread(self.frame_lists[idx])
            frame_gray = cv2.cvtColor(current_frame, cv2.COLOR_BGR2GRAY)
            frame_gray = frame_gray.astype(np.float32)
            if idx == 0:
                Ai = self.args.lr * Ai
                Bi = self.args.lr * Bi
                pos = init_gt.copy()
                clip_pos = np.array([pos[0], pos[1], pos[0]+pos[2], pos[1]+pos[3]]).astype(np.int64)
            else:
                Hi = Ai / Bi
                fi = frame_gray[clip_pos[1]:clip_pos[3], clip_pos[0]:clip_pos[2]]
                fi = pre_process(cv2.resize(fi, (init_gt[2], init_gt[3])))
                Gi = Hi * np.fft.fft2(fi)
                gi = linear_mapping(np.fft.ifft2(Gi))
                # 找到最大的响应点,这就是第二帧的目标位置
                max_value = np.max(gi)
                max_pos = np.where(gi == max_value)
                dy = int(np.mean(max_pos[0]) - gi.shape[0] / 2)
                dx = int(np.mean(max_pos[1]) - gi.shape[1] / 2)
                
                # 更新位置信息
                pos[0] = pos[0] + dx
                pos[1] = pos[1] + dy

                # trying to get the clipped position [xmin, ymin, xmax, ymax]
                clip_pos[0] = np.clip(pos[0], 0, current_frame.shape[1])
                clip_pos[1] = np.clip(pos[1], 0, current_frame.shape[0])
                clip_pos[2] = np.clip(pos[0]+pos[2], 0, current_frame.shape[1])
                clip_pos[3] = np.clip(pos[1]+pos[3], 0, current_frame.shape[0])
                clip_pos = clip_pos.astype(np.int64)

                # get the current fi..
                fi = frame_gray[clip_pos[1]:clip_pos[3], clip_pos[0]:clip_pos[2]]
                fi = pre_process(cv2.resize(fi, (init_gt[2], init_gt[3])))
                # online update...
                Ai = self.args.lr * (G * np.conjugate(np.fft.fft2(fi))) + (1 - self.args.lr) * Ai
                Bi = self.args.lr * (np.fft.fft2(fi) * np.conjugate(np.fft.fft2(fi))) + (1 - self.args.lr) * Bi
            
            #可视化跟踪序列图像
            cv2.rectangle(current_frame, (pos[0], pos[1]), (pos[0]+pos[2], pos[1]+pos[3]), (255, 0, 0), 2)
            cv2.imshow('demo', current_frame)
            cv2.waitKey(100)
            # if record... save the frames..
            if self.args.record:
                frame_path = 'record_frames/' + self.img_path.split('/')[1] + '/'
                if not os.path.exists(frame_path):
                    os.mkdir(frame_path)
                cv2.imwrite(frame_path + str(idx).zfill(5) + '.png', current_frame)

整个流程基本与mosse算法原理一致,对照着原理,把这个推导一遍,会更加好理解这个算法基本原理

utils.py里面主要就是对图像进行一些预处理比如图像线性映射,进行点乘余弦窗处理,使图像边缘慢慢变成零,图像反转操作等。

程序框图

以上就是整个mosse算法的原理及代码流程,最后附上一张流程框图,结合去看,会理解的更加深入。
mosse代码流程图
先写到这里,第一次写博客,很多不是很完善,之后慢慢改。。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

相关滤波之开篇Mosse原理及代码详解 的相关文章

  • vue-router详解 - 从使用到扩展

    1 认识路由 1 1 后端路由 早期的网站开发整个HTML页面是由服务器来渲染的 服务器直接生产渲染好对应的HTML页面 返回给客户端进行展示 但是 一个网站 这么多页面服务器如何处理呢 一个页面有自己对应的网址 也就是URL URL会发送

随机推荐

  • Pychram:踩坑记录/窍门分享

    Debug Console 当使用PyCharm的Debug模式时 最好用的莫过于Debug Console 它与断点相配合可以实现类似于Jupyter Notebook的逐块运行代码的效果 但是今天我突然发现Debug Console无法
  • 用户体验式UI设计

    用户体验式UI设计 1 什么是用户体验式设计 产品的业务化和易用性始终是我们追求的目标 随着 Net Framework 3 0的推出 Windows Presentation Foundation WPF 组件库把用户UI
  • openGL之API学习(三十七)如何从FBO中读取颜色、深度信息

    方法一 保存成图片 QImage img new QImage WINDOW WIDTH WINDOW HEIGHT QImage Format ARGB32 uchar tmpBIT img gt bits 从颜色缓冲区中读取数据 int
  • C++整型(short,int,long,longlong)

    C 整型数据类型 整型就是没有小数部分的 C 基本整型有char short int long long long 由于char 类型比较特殊 下面只关于char int long long long 1 整型short int long
  • 使用verilog实现4选1数据选择器的几种方法

    第一种方法module mux d1 d2 d3 d4 se1 se2 dout input d1 input d2 input d3 input d4 input se1 input se2 output dout reg dout al
  • 一目了然凉哥为大家倾力打造的付费专栏

    写在前面 大家好 我是几何心凉 欢迎来到我的付费专栏系列 本专栏将深入介绍 Vue 3 和 Vite 以及如何在 TypeScript 的帮助下构建现代化的 Web 应用程序 Vue 是一个流行的 JavaScript 框架 它允许开发人员
  • 【AntDesign】图片自定义上传组件 超详细含代码及解读~

    技术栈 AntDesign 版本 3x 效果图如下 官网示例给的是标准上传模式 此处用的是自定义上传模式 customRequest 代码 子组件代码 import React useState useImperativeHandle fr
  • 初识微服务框架ServiceComb

    https blog csdn net zengdongwen article details 93486257 后续跟进学习 转载于 https www cnblogs com chaojizhengui p 11586398 html
  • C#变量初始化问题:字段初始值无法引用非静态字段、方法或属性

    问题 字段初始值设定项无法引用非静态字段 方法或属性的问题 下面代码出错的原因 在类中定义的字段为什么不能用 public class Test public Test public int Age 23 public int temp A
  • 隐马尔科夫模型 (HMM) 算法介绍及代码实现

    Table of Contents Hidden Markov Model 隐马尔科夫模型 定义 基本问题 前向算法 算法流程 实现代码 后向算法 算法流程 实现代码 Viterbi算法 算法流程 实现代码 Baum Welch 算法 单观
  • 网络布线的基础知识

    目录 网络布线的基础知识 1 信号 1 1什么是信号 1 2信号的分类 1 3数字信号的优势 2 双绞线 2 1双绞线 2 2双绞线标准与分类 3 光纤概述 3 1光纤的特点 3 2光纤分类 3 3光纤的优点 4 传输介质的连接与布线 4
  • 各种代理IP背后的原理

    讲解各种代理IP背后的原理 知道代理IP的人越来越多了 不管是单纯的换IP 还是进行大量的数据采集 或者是游走于灰色之中 都是离不开代理IP这个工具的 但是很少人会关注各种代理IP背后的原理 今天就听小编来给大家普及下吧 一 代理类型代理I
  • Python 数组教程 – 定义、索引、方法

    在本文中 您将学习如何使用 Python 数组 您将了解如何定义它们以及对它们执行操作常用的不同方法 本文介绍了您通过导入array module 我们不会在这里讨论 NumPy 数组 目录 什么是 Python 数组 Python 列表和
  • 【单目标优化算法】杂草优化算法(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 杂草算法代码简单 易于实现 具有较强的自适
  • postman系列-使用变量

    事先声明 以下内容 均来自于postman官网 仅做学习会用 侵删 如果想系统的学习postman 也推荐官网直接学习 谢谢 作用 在请求中和脚本中 使用变量可以存储值和重用值 将值存储在变量中 就可以在collections enviro
  • 静态变量与非静态变量的区别

    静态变量的类型说明符是static 非静态变量反而类型说明符就不是static了 本文主要介绍静态和非静态变量的区别 希望对你有帮助 一起来看 AD 静态变量 静态变量使用 static 修饰符进行声明在所属类被装载时创建通过类进行访问所属
  • 数据结构 每日一练 :选择 + 编程

    目录 选择 编程 选择 A 正确 B 不正确 答案 A 解析 多维数组是一维数组的扩展 也就是数组的数组 例如二维数组可以看作是一维数组作为数据元素构成的一维数组 三维数组可以看作二维数组作为元素构成的一维数组 数组与线性表的关系 数组是线
  • 大学排行榜

    def read file file m 读文件中的学校名到列表中 返回排名前m学校集合 ls if file alumni txt with open file r encoding utf 8 as data for line in d
  • Python——元组的基本语法(创建、访问、修改、删除)

    Python 元组的使用 Python 的元组与列表类似 不同之处在于元组的元素不能修改 元组使用小括号 列表使用方括号 元组创建很简单 只需要在括号中添加元素 并使用逗号隔开即可 gt gt gt tup1 Google Runoob 1
  • 相关滤波之开篇Mosse原理及代码详解

    相关滤波之开篇Mosse原理及代码详解 相关滤波 Correlation Filter 介绍 代码解读 程序框图 本文主要介绍相关滤波算法开篇 mosse具体原理及其python代码实现流程 相关滤波 Correlation Filter