智慧交通day02-车流量检测实现07:匈牙利算法

简介: 有一种很特别的图,就做二分图,那什么是二分图呢?就是能分成两组,U,V。其中,U上的点不能相互连通,只能连去V中的点,同理,V中的点不能相互连通,只能连去U中的点。这样,就叫做二分图。

匈牙利算法(Hungarian Algorithm)与KM算法(Kuhn-Munkres Algorithm)是用来解决多目标跟踪中的数据关联问题,匈牙利算法与KM算法都是为了求解二分图的最大匹配问题。


50a0a6d8d61b47ba9cf8dff5e254b50d.png


有一种很特别的图,就做二分图,那什么是二分图呢?就是能分成两组,U,V。其中,U上的点不能相互连通,只能连去V中的点,同理,V中的点不能相互连通,只能连去U中的点。这样,就叫做二分图。


可以把二分图理解为视频中连续两帧中的所有检测框,第一帧所有检测框的集合称为U,第二帧所有检测框的集合称为V。同一帧的不同检测框不会为同一个目标,所以不需要互相关联,相邻两帧的检测框需要相互联通,最终将相邻两帧的检测框尽量完美地两两匹配起来。而求解这个问题的最优解就要用到匈牙利算法或者KM算法。


1.匈牙利算法


匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法。美国数学家哈罗德·库恩于1955年提出该算法。此算法之所以被称作匈牙利算法,是因为算法很大一部分是基于以前匈牙利数学家Dénes Kőnig和Jenő Egerváry的工作之上创建起来的。


我们以目标跟踪的方法介绍匈牙利算法,以下图为例,假设左边的四张图是我们在第N帧检测到的目标(U),右边四张图是我们在第N+1帧检测到的目标(V)。红线连起来的图,是我们的算法认为是同一行人可能性较大的目标。由于算法并不是绝对理想的,因此并不一定会保证每张图都有一对一的匹配,一对二甚至一对多,再甚至多对多的情况都时有发生。这时我们怎么获得最终的一对一跟踪结果呢?我们来看匈牙利算法是怎么做的。


21da27333d974025989e6bd85eb59df6.png


  • 第一步


首先给左1进行匹配,发现第一个与其相连的右1还未匹配,将其配对,连上一条蓝线。


588de6b0e2d9402685368524678091df.png


  • 第二步


接着匹配左2,发现与其相连的第一个目标右2还未匹配,将其配对


183a422d9e9a45b7883bdcd62cf17023.png


  • 第三步


接下来是左3,发现最优先的目标右1已经匹配完成了,怎么办呢?


我们给之前右1的匹配对象左1分配另一个对象。


(黄色表示这条边被临时拆掉)


3a70cb1f6f7649419f6bbea404671796.png


可以与左1匹配的第二个目标是右2,但右2也已经有了匹配对象,怎么办呢?


我们再给之前右2的匹配对象左2分配另一个对象(注意这个步骤和上面是一样的,这是一个递归的过程)。


3c509aa68d1c44eebd7ae7faa2fa06b7.png


此时发现左2还能匹配右3,那么之前的问题迎刃而解了,回溯回去。


左2对右3,左1对右2,左3对右1。


a322c0f0044f42d5a23b265e5e3a8752.png


所以第三步最后的结果就是:


2507923cd40b48a696d47a3a540396ed.png


  • 第四步


最后是左4,很遗憾,按照第三步的节奏我们没法给左4腾出来一个匹配对象,只能放弃对左4的匹配,匈牙利算法流程至此结束。蓝线就是我们最后的匹配结果。至此我们找到了这个二分图的一个最大匹配。最终的结果是我们匹配出了三对目标,由于候选的匹配目标中包含了许多错误的匹配红线(边),所以匹配准确率并不高。可见匈牙利算法对红线连接的准确率要求很高,也就是要求我们运动模型、外观模型等部件必须进行较为精准的预测,或者预设较高的阈值,只将置信度较高的边才送入匈牙利算法进行匹配,这样才能得到较好的结果。


可以使用:


scipy.optimize.linear_sum_assignment(cost_matrix)


实现匈牙利算法,其中const_matrix表示代价矩阵。比如第一帧有a,b,c,d四个目标,第二帧图像有p,q,r,s四个目标,其相似度矩阵如下所示:


7a91892b7e334ea2932c609e2216276b.png


from scipy.optimize import linear_sum_assignment
import numpy as np
# 代价矩阵
cost =np.array([[1,2,3,4],[2,4,6,8],[3,6,9,12],[4,8,12,16]])
# 匹配结果
row_ind,col_ind=linear_sum_assignment(cost)
#对应的行索引
print("行索引:\n{}".format(row_ind))
#对应行索引的最优指派的列索引
print("列索引:\n{}".format(col_ind))
#提取每个行索引的最优指派列索引所在的元素,形成数组
print("匹配度:\n{}".format(cost[row_ind,col_ind]))


输出结果为:


11c512f9bbec420291253af44b350685.png


匈牙利算法的流程大家看到了,有一个很明显的问题相信大家也发现了,按这个思路找到的最大匹配往往不是我们心中的最优。匈牙利算法将每个匹配对象的地位视为相同,在这个前提下求解最大匹配。这个和我们研究的多目标跟踪问题有些不合,因为每个匹配对象不可能是同等地位的,总有一个真实目标是我们要找的最佳匹配,而这个真实目标应该拥有更高的权重,在此基础上匹配的结果才能更贴近真实情况。


KM算法就能比较好地解决这个问题,我们下面来看看KM算法。


2.KM算法


KM算法解决的是带权二分图的最优匹配问题。


还是用上面的图来举例子,这次给每条连接关系加入了权重,也就是我们算法中其他模块给出的置信度分值。


eea6e966154a4f938116dd3471d13778.png


KM算法解决问题的步骤是这样的。


  • 第一步


首先对每个顶点赋值,称为顶标,将左边的顶点赋值为与其相连的边的最大权重,右边的顶点赋值为0


2f9065a74ceb4de3a937f88e4fbe0750.png


  • 第二步:


匹配的原则是只和权重与左边分数(顶标)相同的边进行匹配,若找不到边匹配,对此条路径的所有左边顶点的顶标减d,所有右边顶点的顶标加d。参数d我们在这里取值为0.1。


对于左1,与顶标分值相同的边先标蓝。


6499b124bcea4e32b575b8c07a0c0a0c.png


然后是左2,与顶标分值相同的边标


d15a78bb6d9848fb93b9c7226f69a08d.png


然后是左3,发现与右1已经与左1配对。首先想到让左3更换匹配对象,然而根据匹配原则,只有权值大于等于0.9+0=0.9(左顶标加右顶标)的边能满足要求。于是左3无法换边。那左1能不能换边呢?对于左1来说,只有权值大于等于0.8+0=0.8的边能满足要求,无法换边。此时根据KM算法,应对所有冲突的边的顶点做加减操作,令左边顶点值减0.1,右边顶点值加0.1。结果如下图所示。


1cba79a8e65b49b0bf05b7dd0895d040.png


再进行匹配操作,发现左3多了一条可匹配的边,因为此时左3对右2的匹配要求只需权重大于等于0.8+0即可,所以左3与右2匹配


53bb57279e7543e792e46049d2377784.png


最后进行左4的匹配,由于左4唯一的匹配对象右3已被左2匹配,发生冲突。进行一轮加减d操作,再匹配,左四还是匹配失败。两轮以后左4期望值降为0,放弃匹配左4。


至此KM算法流程结束,三对目标成功匹配,甚至在左三目标预测不够准确的情况下也进行了正确匹配。可见在引入了权重之后,匹配成功率大大提高。。


最后还有一点值得注意,匈牙利算法得到的最大匹配并不是唯一的,预设匹配边、或者匹配顺序不同等,都可能会导致有多种最大匹配情况,所以有一种替代KM算法的想法是,我们只需要用匈牙利算法找到所有的最大匹配,比较每个最大匹配的权重,再选出最大权重的最优匹配即可得到更贴近真实情况的匹配结果。但这种方法时间复杂度较高,会随着目标数越来越多,消耗的时间大大增加,实际使用中并不推荐。


总结:


  • 匈牙利算法和KM算法是进行二分图最大匹配的算法,在目标追踪用于进行目标关联


from scipy.optimize import linear_sum_assignment
import numpy as np
# 代价矩阵
cost =np.array([[1,2,3,4],[2,4,6,8],[3,6,9,12],[4,8,12,16]])
# 匹配结果
row_ind,col_ind=linear_sum_assignment(cost)
#对应的行索引
print("行索引:\n{}".format(row_ind))
#对应行索引的最优指派的列索引
print("列索引:\n{}".format(col_ind))
#提取每个行索引的最优指派列索引所在的元素,形成数组
print("匹配度:\n{}".format(cost[row_ind,col_ind]))
# 行索引:
# [0 1 2 3]
# 列索引:
# [3 2 1 0]
# 匹配度:
# [4 6 6 4]
result=linear_sum_assignment(cost)
print(np.array(list(zip(*result))))
# [[0 3]
#  [1 2]
#  [2 1]
#  [3 0]]
"""
匈牙利算法(Hungarian Algorithm)与KM算法(Kuhn-Munkres Algorithm)
  1.匈牙利算法与KM算法:都是用来解决多目标跟踪中的数据关联问题
  2.匈牙利算法与KM算法:都是为了求解二分图的最大匹配问题
二分图
  1.有一种很特别的图,就做二分图,那什么是二分图呢?就是能分成两组,U,V。
    其中,U上的点不能相互连通,只能连V中的点,同理,V中的点不能相互连通,只能连U中的点。
    这样,就叫做二分图。
  2.可以把二分图理解为视频中连续两帧中的所有检测框,第一帧所有检测框的集合称为U,
    第二帧所有检测框的集合称为V。同一帧的不同检测框不会为同一个目标,所以不需要互相关联,
    相邻两帧的检测框需要相互联通,最终将相邻两帧的检测框尽量完美地两两匹配起来。
    而求解这个问题的最优解就要用到匈牙利算法或者KM算法。
匈牙利算法
  1.匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法。
  2.我们以目标跟踪的方法介绍匈牙利算法,以下图为例,假设左边的四张图是我们在第N帧检测到的目标(U),
    右边四张图是我们在第N+1帧检测到的目标(V)。
    红线连起来的图,是我们的算法认为是同一人的可能性较大的目标。
    由于算法并不是绝对理想的,因此并不一定要保证每张图都有一对一的匹配,
    出现一对二甚至一对多的情况,再甚至多对多的情况都时有发生。
    这时我们怎么获得最终的一对一跟踪结果呢?我们来看匈牙利算法是怎么做的。  
  3.匈牙利算法
    1.第一步:
      首先给左1进行匹配,发现左1与其相连的第一个目标右1还未匹配,将其配对,连上一条蓝线。  
    2.第二步:
      接着匹配左2,发现左2与其相连的第一个目标右2还未匹配,将其配对,连上一条蓝线。
    3.第三步:
      1.接下来匹配左3,发现左3与其相连的第一个目标(最优先的目标)右1已经匹配给左1了,怎么办呢?
        那么我们给之前右1匹配的对象左1分配给另外一个对象,即把左1和右1的匹配关系取消掉,
        黄色线表示这左1和右1的匹配关系被临时拆掉。
      2.可以与左1匹配的第二个目标是右2,但右2此时也已经有了其匹配对象左2,怎么办呢?
        我们再给之前右2的匹配对象左2分配给另一个对象(注意这个步骤和上面是一样的,这是一个递归的过程),
        即把左2和右2的匹配关系取消掉,黄色线表示这左2和右2的匹配关系被临时拆掉。
      3.此时发现左2还能匹配与其相连的第二个目标右3,发现左1还能匹配与其相连的第二个目标右2,
        最终左2匹配右3,左1匹配右2,左3匹配右1。
    4.第四步:
      最后是左4,很遗憾,按照第三步的节奏我们没法给左4腾出来一个匹配对象,只能放弃对左4的匹配,
      匈牙利算法流程至此结束。蓝线就是我们最后的匹配结果。至此我们找到了这个二分图的一个最大匹配。
      最终的结果是我们匹配出了三对目标,由于候选的匹配目标中包含了许多错误的匹配红线(边),
      所以匹配准确率并不高。可见匈牙利算法对红线连接的准确率要求很高,
      也就是要求我们运动模型、外观模型等部件必须进行较为精准的预测,或者预设较高的阈值,
      只将置信度较高的线(边)才送入匈牙利算法进行匹配,这样才能得到较好的结果。 
实现匈牙利算法
  1.API:scipy.optimize.linear_sum_assignment(cost_matrix)
    其中 const_matrix 表示代价矩阵。
    比如第一帧有a,b,c,d四个目标,第二帧图像有p,q,r,s四个目标,其相似度矩阵如下所示.
  2.例子: 
    from scipy.optimize import linear_sum_assignment
    import numpy as np
    # 代价矩阵
    cost =np.array([[1,2,3,4],[2,4,6,8],[3,6,9,12],[4,8,12,16]])
    # 匹配结果
    row_ind, =linear_sum_assignment(cost)
    #对应的行索引
    print("行索引:\n{}".format(row_ind))
    #对应行索引的最优指派的列索引
    print("列索引:\n{}".format(col_ind))
    #提取每个行索引的最优指派列索引所在的元素,形成数组
    print("匹配度:\n{}".format(cost[row_ind,col_ind])) 
    打印结果:
      行索引:
      [0 1 2 3]
      列索引:
      [3 2 1 0]
      匹配度:
      [4 6 6 4]   
  3.结论:
    匈牙利算法的流程,有一个很明显的问题,按这个思路找到的最大匹配往往不是我们心中的最优。
    匈牙利算法将每个匹配对象的地位视为相同,在这个前提下求解最大匹配。
    这个和所研究的多目标跟踪问题有些不合,因为每个匹配对象不可能是同等地位的,
    总有一个真实目标是我们要找的最佳匹配,而这个真实目标应该拥有更高的权重,
    在此基础上匹配的结果才能更贴近真实情况。
    KM算法就能比较好地解决这个问题。
KM算法
  KM算法解决的是带权二分图的最优匹配问题。
  还是用上面的图来举例子,这次给每条连接关系加入了权重,权重也就是我们算法中其他模块给出的置信度分值。
KM算法解决带权二分图的最优匹配问题的步骤:
  1.左右两边的图匹配的原则是:
    左右两边的图只和"权重与左边图的分数(顶标)相同的"边进行匹配,
    若左边图根据与其分数(顶标)相同的最大权重的线(边)所连接到的右图已经被分配了某个左图的话,
    那么产生冲突,解决的方式是对产生冲突的左边的两个图的顶标减d,
    然后令产生冲突的右边的一个图的顶点值加d。参数d我们在这里取值为0.1。
  2.实现具体步骤:
    1.第一步
      首先对左右两边的每个图(顶点)进行赋值,该值分数称为顶标。
      将左边的每个图(顶点)赋值为与其相连的线(边)的最大权重,右边的每个图(顶点)赋值为0。
    2.第二步:
      1.对于左1,与左1的顶标分值相同的最大权重的边先标蓝,左1连接右1。
      2.对于左2,与左2的顶标分值相同的最大权重的边先标蓝,左2连接右3。
      3.对于左3,与左3的顶标分值相同的最大权重的边所连接的右1已经与左1配对,左3无法直接连接右1,
        此时产生冲突。
        1.首先想到的是让左3更换匹配对象,然而根据匹配原则,
          只有权值大于等于(左图顶标加右图顶标)0.9+0=0.9的边能满足左3连接右1的要求,否则无法换边。
          那么于是左3无法换边。那左1能不能换边(更换匹配对象)呢?
          对于左1来说,只有权值大于等于(左图顶标加右图顶标)0.8+0=0.8的边能满足左1连接右1的要求,
          否则无法换边。
        2.此时根据KM算法,应对产生冲突的左右两边的图的顶点做加减操作,
          首先令产生冲突的左边的两个图的顶点值减0.1,然后令产生冲突的右边的一个图的顶点值加0.1。
        3.此时发现左3多了一条可匹配的边,因为此时左3连接右2的匹配要求能满足权重大于等于
          (左图顶标加右图顶标)0.8+0=0.8,所以左3与右2匹配。
      4.最后进行左4的匹配,由于左4唯一的可匹配对象右3已被左2匹配,此时发生冲突。
        左右两边发生冲突的图进行一轮加减d的操作,再进行匹配,此时左四还是匹配右3失败。
        当经过一共两轮的加减d的操作后发现左4的顶标降为0,左4放弃继续匹配。
  3.至此KM算法流程结束,三对目标成功匹配,甚至在左三目标预测不够准确的情况下也进行了正确匹配。
    可见在引入了权重之后,匹配成功率大大提高。
      最后还有一点值得注意,匈牙利算法得到的最大匹配并不是唯一的,预设匹配边、或者匹配顺序不同等,
    都可能会导致有多种最大匹配情况,所以有一种替代KM算法的想法是,
    我们只需要用匈牙利算法找到所有的最大匹配,比较每个最大匹配的权重,
    再选出最大权重的最优匹配即可得到更贴近真实情况的匹配结果。
    但这种方法时间复杂度较高,会随着目标数越来越多,消耗的时间大大增加,实际使用中并不推荐。
"""
目录
相关文章
|
机器学习/深度学习 算法 数据可视化
基于RCNN深度学习网络的交通标志检测算法matlab仿真
基于RCNN深度学习网络的交通标志检测算法matlab仿真
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统python+TensorFlow+算法模型+Django网页+数据集
交通标志识别系统python+TensorFlow+算法模型+Django网页+数据集
113 0
|
1月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于MSER和HOG特征提取的SVM交通标志检测和识别算法matlab仿真
### 算法简介 1. **算法运行效果图预览**:展示算法效果,完整程序运行后无水印。 2. **算法运行软件版本**:Matlab 2017b。 3. **部分核心程序**:完整版代码包含中文注释及操作步骤视频。 4. **算法理论概述**: - **MSER**:用于检测显著区域,提取图像中稳定区域,适用于光照变化下的交通标志检测。 - **HOG特征提取**:通过计算图像小区域的梯度直方图捕捉局部纹理信息,用于物体检测。 - **SVM**:寻找最大化间隔的超平面以分类样本。 整个算法流程图见下图。
|
8天前
|
机器学习/深度学习 人工智能 监控
智慧交通AI算法解决方案
智慧交通AI算法方案针对交通拥堵、违法取证难等问题,通过AI技术实现交通管理的智能化。平台层整合多种AI能力,提供实时监控、违法识别等功能;展现层与应用层则通过一张图、路口态势研判等工具,提升交通管理效率。方案优势包括先进的算法、系统集成性和数据融合性,应用场景涵盖车辆检测、道路环境检测和道路行人检测等。
|
2月前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
107 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
6月前
|
算法 定位技术 Windows
R语言最大流最小割定理和最短路径算法分析交通网络流量拥堵问题
R语言最大流最小割定理和最短路径算法分析交通网络流量拥堵问题
|
机器学习/深度学习 存储 算法
基于Fast-RCNN深度学习网络的交通标志检测算法matlab仿真
基于Fast-RCNN深度学习网络的交通标志检测算法matlab仿真
|
算法 调度
转:使用匈牙利算法对局域网共享软件有哪些好处
在局域网共享软件中,匈牙利算法主要应用于解决资源分配的问题。局域网共享软件可能存在多个用户同时访问同一文件或打印机的情况,为了确保资源的公平共享,需要对资源进行分配。
89 2
|
机器学习/深度学习 传感器 算法
【优化红绿灯】基于遗传算法优化绿灯时间实现单个十字路口的交通拥堵情况疏通附matlab代码
【优化红绿灯】基于遗传算法优化绿灯时间实现单个十字路口的交通拥堵情况疏通附matlab代码
|
数据采集 机器学习/深度学习 存储
基于PCA降维的交通标志训练和识别算法matlab仿真
交通标志识别一直是计算机视觉和机器学习领域的研究热点之一。PCA(Principal Component Analysis)降维算法是一种常用的特征提取方法,可以将高维数据降低到低维空间中。本文介绍一种基于PCA降维的交通标志训练和识别算法,该算法可以从交通标志图像中提取特征,并训练出一个分类器,用于识别新的交通标志图像。
基于PCA降维的交通标志训练和识别算法matlab仿真