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

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

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

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

1.匈牙利算法

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

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

  • 第一步

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

  • 第二步

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

  • 第三步

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

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

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

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

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

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

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

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

  • 第四步

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

可以使用:

scipy.optimize.linear_sum_assignment(cost_matrix)

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

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]))

输出结果为:

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

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

2.KM算法

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

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

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

  • 第一步

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

  • 第二步:

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

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

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

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

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

最后进行左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_assignmentimport 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算法的想法是,我们只需要用匈牙利算法找到所有的最大匹配,比较每个最大匹配的权重,再选出最大权重的最优匹配即可得到更贴近真实情况的匹配结果。但这种方法时间复杂度较高,会随着目标数越来越多,消耗的时间大大增加,实际使用中并不推荐。
"""

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

非线性回归(Non-linear Regression)学习笔记

非线性回归&#xff08;Non-linear Regression&#xff09; 1.概率: 1.1定义概率Probability:对一件事情发生的可能性的衡量 1.2范围 0<P<1 1.3计算方法: 1.3.1根据个人置信 1.3.2根据历史数据 1.3.3根据模拟数据 1.4条件概率:&#xff08;A发生的条件下B发生的概率&…

智慧交通day02-车流量检测实现08:目标跟踪中的数据关联(将检测框bbox与卡尔曼滤波器的跟踪框进行关联匹配)

# 将YOLO模型的检测框和卡尔曼滤波的跟踪框进行匹配 def associate_detection_to_tracker(detections,trackers,iou_threshold0.3):"""将检测框bbox与卡尔曼滤波器的跟踪框进行关联匹配:param detections:检测框:param trackers:跟踪框&#xff0c;即跟踪目标:p…

回归中的相关度和R平方值 学习笔记

回归中的相关度和R平方值 自变量x和因变量y的相关度 1.皮尔逊相关系数(Pearson Correlation Coefficient): 1.1衡量两个值线性相关强度的量 1.2取值范围[-1,1]: 正向相关: >0,负向相关: <0,无相关性: 0 公式&#xff1a;correlation&#xff0c; correlationvariance(Co…

智慧交通day02-车流量检测实现09:SORT/deepSORT

SORT和DeepSORT是多目标跟踪中两个知名度比较高的算法。DeepSORT是原团队对SORT的改进版本。现在来解析一下SORT和DeepSORT的基本思路。 1.SORT SORT核心是卡尔曼滤波和匈牙利匹配两个算法。流程图如下所示&#xff0c;可以看到整体可以拆分为两个部分&#xff0c;分别是匹配…

素数环 与 算法 全排列

在说起全排列前&#xff0c;先说一下昨天碰到的一个题目&#xff08;答案不是我做出来的&#xff0c;但是我感觉有好多个亮点&#xff0c;贴出来方便日后的学习&#xff09;&#xff1a; 素数环 时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;…

简单线性回归(Simple Linear Regression)和多元线性回归(Multiple Regression)学习笔记

简单线性回归(Simple Linear Regression) 0.前提介绍: 为什么需要统计量? 统计量:描述数据特征 0.1集中趋势衡量 0.1.1均值(平均数&#xff0c;平均值) (mean)&#xff1a;&#xff08;求和除以个数&#xff0c;Ex也可以表示x求均值&#xff09; 0.1.2中位数(median) : 将数…

智慧交通day02-车流量检测实现10:多目标追踪实现

在这里我们主要实现了一个多目标跟踪器&#xff0c;管理多个卡尔曼滤波器对象&#xff0c;主要包括以下内容&#xff1a; 初始化&#xff1a;最大检测数&#xff0c;目标未被检测的最大帧数 目标跟踪结果的更新&#xff0c;即跟踪成功和失败的目标的更新 初始化 def __init_…

智慧交通day02-车流量检测实现11:yoloV3模型

yoloV3以V1&#xff0c;V2为基础进行的改进&#xff0c;主要有&#xff1a;利用多尺度特征进行目标检测&#xff1b;先验框更丰富&#xff1b;调整了网络结构&#xff1b;对象分类使用logistic代替了softmax,更适用于多标签分类任务。 1.算法简介 YOLOv3是YOLO (You Only Loo…

bzoj1992鬼谷子的钱袋(二分乱搞 二进制)

1192: [HNOI2006]鬼谷子的钱袋 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3223 Solved: 2333Descriptio 鬼谷子非常聪明&#xff0c;正因为这样&#xff0c;他非常繁忙&#xff0c;经常有各诸侯车的特派员前来向他咨询时政。有一天&#xff0c;他在咸阳游历的时候&…

聚类(Clustering): K-means算法

聚类(Clustering): K-means算法 1.归类: 聚类(clustering)属于非监督学习(unsupervised learning) 无类别标记( class label) 3. K-means 算法&#xff1a; 3.1 Clustering 中的经典算法&#xff0c;数据挖掘十大经典算法之一 3.2 算法接受参数 k &#xff1b;然后将事先输入…

智慧交通day02-车流量检测实现12:基于yoloV3的目标检测

在本章节代码编写中&#xff0c;发现之前的代码所处的环境是python3&#xff0c;因此导致了cv2.dnn.readNetFromDarknet()在代码运行中导致了i[0]的获值失败&#xff0c;故总结如下&#xff1a; cv2.dnn.readNetFromDarknet()在python3上遇到的问题_李大狗的读研日记-CSDN博客…

cv2.dnn.readNetFromDarknet()在python3上遇到的问题

问题描述&#xff1a; 代码如下 net cv2.dnn.readNetFromDarknet(configPath,weightsPath) #获取YOLO每一层的名称 #getLayerNames&#xff08;&#xff09;&#xff1a;获取网络所有层的名称。 ln net.getLayerNames() # 获取输出层的名称: [yolo-82,yolo-94,yolo-106] # …

智慧交通day02-车流量检测实现13:基于虚拟线圈法的车辆统计+视频中的车流量统计原理解析

1.基于虚拟线圈法的车辆统计 基于虚拟线圈的车流量统计算法原理与交通道路上的常见的传统的物理线圈类似&#xff0c;由于物理线圈需要埋设在路面之下&#xff0c;因此会有安装、维护费用高&#xff0c;造成路面破坏等问题&#xff0c;而采用基于视频的虚拟线圈的车辆计数方法…

ubuntu 12.04 eclipse 安装

方法二&#xff1a;(优点是安装内容清爽&#xff0c;缺点是配置麻烦) 1、安装JDK&#xff0c;参考 Ubuntu 12.04 下安装 JDK 7 2、下载 Eclipse 从 http://www.eclipse.org/downloads/index-developer.php下载合适版本&#xff0c;如&#xff1a;Eclipse IDE for C/C Develope…

智慧交通day02-车流量检测实现14:代码汇总+问题修正

代码权重文件资源https://download.csdn.net/download/qq_39237205/43072746https://download.csdn.net/download/qq_39237205/43072746 环境要求&#xff1a;python2.7 环境配置&#xff1a;见文末requirements.txt 1.YOLO.py # encoding:utf-8 import imutils import tim…

从资源池和管理的角度理解物理内存

早就想搞一下内存问题了&#xff01;这次正趁着搞bigmemory内核&#xff0c;可以写一篇文章了。本文旨在记录&#xff0c;不包含细节&#xff0c;细节的话&#xff0c;google&#xff0c;百度均可&#xff0c;很多人已经写了不少了。我只是按照自己的理解记录一下内存的点点滴滴…

从头开始学一个android activity

一、类层次结构&#xff1a; 二、什么是Activity&#xff0c;如何理解Activity 1、 用户与应用程序的交互的接口 2、 控件的容器&#xff0c;我们要把控件摆放在这个容器中 三、如何创建一个Activity 新建一个类&#xff1a; 1、 继承Activity类 [java] view plaincopyprint…

python3 numpy中矩阵np.dot(a,b)乘法运算

python np.dot(a,b)乘法运算 首先我们知道矩阵运算是不满足交换律的&#xff0c;np.dot(a, b)与np.dot(b, a)是不一样的 另外np.dot(a,b)和a.dot(b)果是一样的 1.numpy中数组&#xff08;矩阵&#xff09;相乘np.dot(a,b)运算&#xff1a; 对于两数组a和b &#xff1a; 示例…

ML Backpropagation算法的计算过程举例

Backpropagation计算过程举例 初始权重(initialize weights)是随机产生的(如-1~1之间) 初始化可以选择均值为0&#xff0c;方差为1/n_in的正态分布&#xff0c;n_in为输入的实例个数&#xff0c;Python中可使用np.random.normal函数来初始化权重&#xff1a; np.random.normal…

Python基础知识__字符串

字符串介绍 一. 认识字符串 字符串是 Python 中最常用的数据类型。我们一般使用引号来创建字符串。创建字符串很简单&#xff0c;只要为变量分配一个值即可。 a hello world b "abcdefg" print(type(a)) print(type(b)) 注意&#xff1a;控制台显示结果为<cl…