Introducción al algoritmo húngaro.

Nota importante: este artículo está compilado a partir de información en línea. Solo registra el proceso del blogger de aprender puntos de conocimiento relevantes. No se infringe ni se elimina.

1. Materiales de referencia

¿Problema de coincidencia del algoritmo húngaro?
Cómo funciona exactamente el algoritmo húngaro
Asociación de datos de seguimiento de múltiples objetivos
Conocimiento en cinco minutos del algoritmo húngaro: ¿Qué es el algoritmo húngaro?
Documento: El método húngaro para el problema de asignación

2. Introducción relacionada

1. Gráfico bipartito

1.1 El concepto de gráfico bipartito

El gráfico bipartito, también conocido como gráfico bipartito, es un modelo especial en teoría de grafos. El conjunto de vértices de un gráfico bipartito se puede dividir en dos subconjuntos independientes y disjuntos U y V:
G = (U, V, E) G=(U,V,E)GRAMO=( U ,V ,E )
Cada arista en el conjunto de aristas del gráfico bipartito E conecta un vértice en los subconjuntos de vértices U y V respectivamente, pero los vértices dentro de U y V no están conectados entre sí. Un gráfico bipartito típico se ve así:
Insertar descripción de la imagen aquí

En pocas palabras, si todos los vértices del gráfico se pueden dividir en dos conjuntos, y las cabezas y colas de todos los bordes del gráfico no pertenecen al mismo conjunto de vértices, sino que abarcan dos conjuntos, entonces el gráfico es un gráfico bipartito.

1.2 Generar gráfico bipartito a partir de gráfico no dirigido

El gráfico no dirigido se ve así:
Insertar descripción de la imagen aquí

Convierta los vértices a, b, c, d del conjunto A y e, f, g, h del conjunto B en un gráfico bipartito:
Insertar descripción de la imagen aquí

Se puede ver que los vértices del gráfico se pueden dividir en dos conjuntos A y B, y la cabeza y la cola de cualquier arista pertenecen respectivamente al conjunto A y al conjunto B, por lo que este gráfico es un gráfico bipartito.

1.3 Determinar el gráfico bipartito

Determinar si un gráfico es un gráfico bipartito es equivalente a determinar si el gráfico es un gráfico de dos colores, es decir, si todos los vértices del gráfico se pueden teñir en dos tipos de colores (debe asegurarse de que los vértices conectados no se puedan teñir). del mismo color). Puede utilizar la implementación Breadth First Search., BFS).

Ejemplo de código C++, que utiliza una lista de adyacencia para almacenar el gráfico, la complejidad temporal es O (V+E).

#include <iostream>
#include <vector>
#include <queue>
#include <utility>

/**
 * @brief 用于判断输入的图是否是二分图
 *
 * @param V 图的顶点数量
 * @param adj 图的邻接表表示
 * @return bool 图是否是二分图:true - 是,false - 不是
 */
bool IsBipartite(int V, std::vector<int> adj[])
{
    // 存储所有顶点颜色的 vector 容器,初值 -1 表示未染色,0 表示红色,1 表示蓝色
    std::vector<int> col(V, -1);

    // 用于 BFS 过程的 FIFO 队列,元素类型是顶点索引及其颜色组成的二元组
    std::queue<std::pair<int, int>> q;

    // 遍历所有顶点
    for (int i = 0; i < V; i++)
    {
        // 顶点 i 尚未染色
        if (col[i] == -1)
        {
            // 将顶点 i 染成红色 0,并将其压入 BFS FIFO 队列
            col[i] = 0;
            q.push({ i, 0 });

            // 处理 BFS FIFO 队列中的各顶点
            while (!q.empty())
            {
                auto p = q.front();
                q.pop();

                // 当前顶点
                int v = p.first;
                // 当前顶点的颜色
                int c = p.second;

                // 遍历当前顶点的所有相连顶点
                for (int j : adj[v])
                {
                    // 若相连顶点 j 与当前顶点颜色相同,则输入的图不是二分图
                    if (col[j] == c) return false;

                    // 若相连顶点 j 尚未染色
                    if (col[j] == -1)
                    {
                        // 将相连顶点 j 染成与当前顶点颜色相反的颜色,并将其压入 BFS
                        // FIFO 队列
                        col[j] = 1 - c;
                        q.push({ j, col[j] });
                    }
                }
            }
        }
    }

    return true;
}

int main()
{
    int V, E;
    V = 4 , E = 8;

    // 使用邻接表存储图
    std::vector<int> adj[V];
    adj[0] = {1, 3};
    adj[1] = {0, 2};
    adj[2] = {1, 3};
    adj[3] = {0, 2};


    IsBipartite(V, adj) ? std::cout << "输入的图是二分图" << std::endl
                        : std::cout << "输入的图不是二分图" << std::endl;

    return 0;
}

2. Coincidencia de gráficos bipartitos

2.1 Partido

En teoría de grafos, una coincidencia se refiere a un conjunto de aristas en el que no hay dos aristas que tengan un vértice común.

Como se muestra en la siguiente figura, encuentre una coincidencia del gráfico bipartito.
Insertar descripción de la imagen aquí

En la imagen de abajo, el borde rojo coincide.
Insertar descripción de la imagen aquí

2.2 Puntos coincidentes y bordes coincidentes

Dado el gráfico G = ( V , E ) G=(V,E)GRAMO=( V ,E ) , uno de susM \text{M}M representa incluido en el conjunto de aristasE \text{E}Un subconjunto de E , a saberM YuE \text{E}Consta de varias aristas en E.
M ⊆ EM\subseteq EMETRO
No hay vértices comunes entre dos aristas en la coincidencia E. Los dos bordes rojos en la imagen de abajo forman una de sus coincidencias:
Insertar descripción de la imagen aquí

Coincidencia M \text{M}Las aristas en M se llamanbordes coincidentes, los dos bordes rojos en la figura anterior son bordes coincidentes; el conjunto de bordes E \text{E}E no coincide conM \text{M}Las aristas de M se llamanborde inigualable, los bordes grises en la figura anterior son todos bordes incomparables.

Los puntos finales de las aristas coincidentes se llamanDistribución de pescado, Punto medio superior u 4 , u 5 , v 1 , v 3 u_4\text{, }u_5\text{, }v_1\text{, }v_3tu45v1v3Todos son puntos coincidentes; conjunto de vértices U \text UUV \text VOtros vértices en V que no coinciden con los puntos finales de los bordes se llamanNo hay peces asignados, punto medio superior u 1 , u 2 , u 3 , v 2 , v 4 u_1,u_2,u_3,v_2,v_4tu1,tu2,tu3,v2,v4Todos son puntos inigualables.

2.3 Coincidencia máxima

Entre todas las coincidencias de un gráfico, la coincidencia con el mayor número de aristas coincidentes se denomina Coincidencia de cardinalidad máxima del gráfico. La coincidencia máxima no es única, como se muestra en la figura siguiente. Las dos coincidencias en la figura siguiente son coincidencias máximas y el número de aristas en la coincidencia máxima es 4.
Insertar descripción de la imagen aquí

2.4 Combinación perfecta

Si todos los vértices en la coincidencia de un gráfico son puntos coincidentes, entonces es una coincidencia perfecta. Una coincidencia perfecta debe ser una coincidencia máxima (cualquier punto en una coincidencia perfecta ha coincidido y agregar un nuevo borde coincidente definitivamente entrará en conflicto con el borde coincidente existente), pero no todos los gráficos tienen una coincidencia perfecta.

2.5 Coincidencia de peso máximo y coincidencia de peso mínimo

La coincidencia de peso máximo representa las coincidencias con la suma más grande de pesos de borde entre todas las coincidencias en el gráfico ponderado, mientras que la coincidencia de peso mínimo representa las coincidencias con la suma más grande de pesos de borde entre todas las coincidencias en el gráfico ponderado. de pesos coinciden.

Asigne pesos a todos los bordes del gráfico bipartito y conviértalo enGráfico bipartito potenciado,Como se muestra abajo:
Insertar descripción de la imagen aquí

Para el gráfico bipartito ponderado anterior, registramos el peso en cualquier borde como w \text{w}w , cualquier coincidencia se indica comoM \text{M}M , coincide conM \text{M}La suma de los pesos de todas las aristas coincidentes contenidas en M se escribe como la función f ( M ) f(M)f ( M ) , entonces el problema de coincidencia bipartita de peso máximo de gráficos bipartitos ponderados y el problema de coincidencia bipartita de peso mínimo de gráficos bipartitos ponderados se pueden describir en el siguiente lenguaje matemático: { f ( M ) = ∑ ( u ,
v ) ∈ M wu , v max ⁡ / min ⁡ f ( M ) \left\{\begin{array}{l}f(M)=\sum_{(u,v)\in M}w_{u,v}\ \\max/\min f(M)\end{array}\right.{ f ( metro )=( u , v ) Mwu , vmáximo/mín.f ( M )
El problema de asociación de datos de seguimiento de múltiples objetivos se puede transformar en un problema de coincidencia de peso mínimo del gráfico bipartito ponderado. Los fotogramas de imagen en el proceso de seguimiento se pueden considerar como un conjunto de vértices U en el gráfico bipartito ponderado.UV \text VV , el peso del borde puede considerarse como la distancia entre los objetivos del cuadro anterior y siguiente, calculado de alguna maneradistancia coincidente(como la distancia euclidiana), esta distancia coincidente se llamaCosto, todas las distancias coincidentes constituyenMatriz de costos. Lo que debemos hacer es encontrar la relación de coincidencia entre los fotogramas de la imagen para que la distancia total de coincidencia sea la más pequeña y el costo sea el más bajo.

3. Caminos alternativos

Dado el gráfico G = ( V , E ) G=(V,E)GRAMO=( V ,E ) y una de sus coincidenciasM \text MM , Ruta alterna, describe una ruta en el gráfico:comenzando desde un punto no coincidente en el gráfico, pasando alternativamente por bordes no coincidentes y bordes coincidentes. En el siguiente gráfico bipartito, la rutau 3 → v 1 → u 1 → v 3 → u 2 u_3\to v_1\to u_1\to v_3\to u_2tu3v1tu1v3tu2Es un camino alternativo:
Insertar descripción de la imagen aquí

4. Ruta de aumento

4.1 El concepto de ruta aumentada

A partir de un punto no coincidente en el gráfico, pasando alternativamente por aristas no coincidentes y aristas coincidentes, y terminando en otro punto no coincidente diferente del punto inicial, esta ruta se denomina ruta aumentada. La ruta ancha es una ruta alterna especial. En el siguiente gráfico bipartito, la ruta u 1 → v 1 → u 5 → v 4 u_1\to v_1\to u_5\to v_4tu1v1tu5v4Es un camino creciente.
Insertar descripción de la imagen aquí

4.2 Propiedades de la carretera Zengguang

Dado el gráfico G = ( V , E ) G=(V,E)GRAMO=( V ,E ) y una de sus coincidenciasM \text MM y Zengguang RoadP \text PP y convierteP \text PTodas las aristas de P se denotan como el conjunto EP \text E_PmiP, entonces tiene las siguientes tres propiedades muy importantes:

  1. Teorema de Berge: para una gráfica dada G \text GG coincide con uno de susM \text MMM \texto MM esG \text GLa condición necesaria y suficiente para la máxima coincidencia de G es G \text GNo hay ningunaM \text M coincidente en GCarretera M Zengguang;

  2. EP\textE_PmiPEl número de aristas debe ser un número impar y el camino creciente P \text PLa arista impar de P no pertenece a la M coincidente \text MM , el borde par pertenece alM coincidente \text MM , que significaEP \text E_PmiPEl número de aristas no coincidentes debe ser 1 más que el número de aristas coincidentes;

  3. A través de la propiedad 1, no es difícil encontrar que al convertir EP \text E_PmiPEl borde no coincidente se invierte para convertirse en un borde coincidente, y el borde coincidente se invierte para convertirse en un borde no coincidente. Luego se puede obtener un borde coincidente más. El nuevo borde coincidente obtenido al invertir es la suma M \text MM no pertenece aEP \text E_PmiPLos bordes restantes de pueden formar una coincidencia más grande M ′ M^{\prime}METRO' . En teoría de conjuntos,M ′ M^{\prime}METRO se llamaM \text MM yEP \text E_PmiPDiferencia simétrica (Diferencia simétrica), denotada como M ⊖ EPM\ominus E_{P}METROmiP:
    M ⊖ EP = ( M ∪ EP ) − ( M ∩ EP ) M\menos E_P=(M\cup E_P)-(M\cap E_P)METROmiP=( MmiP)( MmiP)
    Combinando las propiedades 1 y 3 podemos encontrar fácilmente que para un gráfico bipartito dadoG = ( U , V , E ) G=(U,V,E)GRAMO=( U ,V ,E ) y una coincidencia inicialmente vacíaM \text MM , podemos expandir gradualmente el tamaño de la coincidencia siempre que busquemos repetidamente Zengguang Road. Finalmente, cuando no podemos encontrar Zengguang Road, obtenemos uncoincidencia máxima, el ejemplo de la siguiente figura demuestra intuitivamente este proceso:
    Insertar descripción de la imagen aquí

El final M = { mi 1 , 3 , mi 3 , 1 , mi 4 , 2 , mi 5 , 4 } M=\{e_{1,3},e_{3,1},e_{4,2} , mi_ {5,4} \}METRO={ mi1 , 3,mi3 , 1,mi4 , 2,mi5 , 4} es ingresar el gráfico bipartitoG \text GUna coincidencia máxima de G.

3. Algoritmo húngaro

El algoritmo húngaro fue propuesto por el matemático húngaro Edmonds en 1965, de ahí su nombre. El algoritmo húngaro es una implementación específica de la idea de asociación de datos del Vecino Global Más Cercano (GNN) y se utilizó por primera vez para resolver problemas en el campo de la economía.Problema de asignación de tareas, y luego se desarrolló en el campo de la teoría de grafos para resolverProblema de coincidencia de peso mínimo para gráficos bipartitos ponderadosalgoritmo general.

La esencia del algoritmo húngaro es un algoritmo gráfico . El núcleo del algoritmo es encontrar la ruta de aumento. Es un algoritmo que utiliza la ruta de aumento para encontrar la coincidencia máxima de un gráfico bipartito. Es un algoritmo de optimización combinatoria que puede resolver el problema de asignación en tiempo polinómico .

1. Introducción al problema

En el seguimiento de objetivos, información como la posición del objeto cambia en diferentes momentos, pero debemos mantenerla con la misma ID.

Tomando el automóvil de seguimiento de objetivos como ejemplo, suponiendo que aparezca un automóvil en el cuadro de video Cuadro 1, utilizando el método de detección de objetivos, el automóvil amarillo siempre se puede marcar como ID = 1.
Insertar descripción de la imagen aquí

Si aparece otro automóvil en el cuadro de video Frame2, el detector de objetivos solo puede clasificar el "automóvil" y no puede saber si la identificación del automóvil amarillo es igual a 1.
Insertar descripción de la imagen aquí

Utilizando el algoritmo húngaro, se pueden juzgar diferentes ID. El algoritmo húngaro creará un gráfico con nodos en el cuadro actual t = 1 y el cuadro anterior t = 0, y calculará la distancia entre los nodos en los dos cuadros. Cuanto menor sea la distancia, la probabilidad de que el objeto en el cuadro actual es el mismo que el objeto en el cuadro anterior.Cuanto más grande.
Insertar descripción de la imagen aquí

2. Escenarios aplicables

El algoritmo húngaro se utiliza principalmente en problemas de asignación, como problemas de correspondencia de tareas. Al convertirlo en un gráfico bipartito, se resuelve la coincidencia máxima para garantizar una asignación óptima.

3. Pensamiento del algoritmo húngaro

**Idea básica:** Al buscar una ruta de aumento, los bordes coincidentes y los bordes no coincidentes en la ruta de aumento se intercambian entre sí, de modo que habrá un borde coincidente más hasta que no se encuentre ninguna ruta de aumento.

Tomemos un ejemplo sencillo para presentar la idea del algoritmo húngaro.

Mire este ejemplo, haga coincidir 1, 2, 3, 4 de la izquierda con a, b, c, d de la derecha.
Insertar descripción de la imagen aquí

Al principio, asignamos a 1 y conectamos una línea roja entre 1 y a para establecer una coincidencia.
Insertar descripción de la imagen aquí

Luego asigna b a 2 y conecta 2 y b con una línea roja para indicar una coincidencia.
Insertar descripción de la imagen aquí

Inmediatamente después de asignar a 3, en este momento encontramos que a y b ya pertenecían, intentamos reasignar 1 y eliminamos la asignación original, que está indicada por la línea azul.
Insertar descripción de la imagen aquí

Pero pronto descubrimos que 1 no se podía reasignar y b ya le pertenecía, por lo que continuamos intentando reasignar 2 y eliminamos la asignación original, representada por una línea azul. 2 se reasigna a c, indicado por la línea roja.
Insertar descripción de la imagen aquí

En este momento, 1 se puede reasignar a b, indicado por la línea roja.
Insertar descripción de la imagen aquí

Finalmente, se puede asignar 3 a a, representado por la línea roja.
Insertar descripción de la imagen aquí

Para 4, debido a que c ya ha sido asignado y no se puede realizar el intento de reasignar otros 1, 2 y 3, termina aquí.

Resumir: El principio básico del algoritmo húngaro es redistribuir según la coincidencia original para ver si se puede agregar una nueva coincidencia.

4. Proceso del algoritmo húngaro

El algoritmo húngaro se utiliza para resolverProblema de asignación, para obtener el resultado de asignación óptimo. El problema de asignación del algoritmo húngaro funciona en 5 pasos: primero se reduce la matriz, luego se cruza por ceros y finalmente se vuelve a reducir hasta que podamos emparejar los elementos. El proceso general es el siguiente:
Insertar descripción de la imagen aquí

Este capítulo utiliza un ejemplo abstracto para presentar el proceso de resolución del problema de asignación utilizando el algoritmo húngaro. Supongamos que tenemos dos cuadros de imágenes. En el primer cuadro, hay CarA, CarB y CarC, y estos tres autos se encuentran a través del detector de objetivos; en el segundo cuadro, de manera similar, también vemos tres autos, CarD, CarE, y CarF. Solo estos tres autos existen en ambos cuadros, pero debido a que el detector de objetivos solo puede decir que son autos, no puede decir si CarD corresponde a CarA u otros autos. Puedes medir la distancia correspondiente entre los dos marcos y dibujarmatriz de costos(matriz de costos). Por ejemplo, la distancia entre CarF del segundo cuadro y CarA del primer cuadro es de 9 m, como se muestra en la siguiente figura.
Insertar descripción de la imagen aquí

4.1 Paso 1: Restar el valor mínimo de cada fila

El más pequeño de la primera fila es 9, luego se resta 9 y así sucesivamente. Finalmente se convierte en:
Insertar descripción de la imagen aquí

4.2 Paso 2: Restar el valor mínimo de cada columna

Si el número más pequeño en la primera columna es 1, entonces resta 1, y así sucesivamente. Finalmente se convierte en:
Insertar descripción de la imagen aquí

4.3 Paso 3: tacha todos los ceros con el número mínimo de líneas

Hay muchas formas de tachar todos los ceros, como se muestra a continuación:
Insertar descripción de la imagen aquí

Pero las formas menos obvias deberían ser dos:
Insertar descripción de la imagen aquí

Si este número es mayor o igual que el número de filas y columnas de la matriz, salte al paso cinco.

4.4 Paso 4: Restar el valor mínimo de la matriz restante

En la matriz restante, se resta el valor mínimo; si se cruzan ceros, se suma el valor mínimo.

Las matrices restantes son [[3, 7], [2, 5]], todas menos 2. Luego suma 2 al 0 en la cruz derecha. se convierte en:
Insertar descripción de la imagen aquí

Luego repite el tercer paso y finalmente conviértete en:
Insertar descripción de la imagen aquí

Ahora tenemos 3 líneas, así que salte al paso cinco.

4.5 Paso 5: Inicie la correspondencia uno a uno desde las filas con un solo cero y elimine la fila completa después de hacer coincidir.

Solo hay un cero en la segunda línea, por lo que el auto F corresponde al auto B, y luego se eliminan la fila y la columna. Finalmente se convierte en:
Insertar descripción de la imagen aquí

En la tercera fila, el Coche C corresponde al Coche D.
Insertar descripción de la imagen aquí

Lo que queda es el Coche A correspondiente al Coche E. El resultado final es:
Insertar descripción de la imagen aquí

5. Implementación en Python del algoritmo húngaro

biblioteca de scipy linear_sum_assignment

Tanto la función en sklearn linear_assignment()como la función en scipy linear_sum_assignment()implementan el algoritmo húngaro y los valores de retorno de las dos tienen diferentes formas:

import numpy as np 
from sklearn.utils.linear_assignment_ import linear_assignment
from scipy.optimize import linear_sum_assignment
 

cost_matrix = np.array([
    [10,15,9],
    [9,18,5],
    [6,14,3]
])
 
matches = linear_assignment(cost_matrix)
print('sklearn API result:\n', matches)
matches = linear_sum_assignment(cost_matrix)
print('scipy API result:\n', matches)
 

"""Outputs
sklearn API result:
 [[0 1]
  [1 2]
  [2 0]]
scipy API result:
 (array([0, 1, 2], dtype=int64), array([1, 2, 0], dtype=int64))
"""

Insertar descripción de la imagen aquí

Como puede ver, lo empareja directamente para usted, 0(Car A) → 1(Car E).

6. Caso especial del algoritmo húngaro

NxN frente a NxM

Si tiene una matriz NxM, puede convertirla en una matriz NxN agregando la columna con el valor máximo.

En este momento, el número de filas y columnas de nuestra matriz es igual. Eso se debe a que solo hay tres autos en los dos cuadros de la imagen. Entonces, ¿qué pasa si hay tres autos en el primer cuadro y cuatro autos en el segundo? ¿marco? Si esto sucede, solo necesitamos agregar un nuevo borde a nuestro ícono, este valor es nuestro valor máximo original.
Insertar descripción de la imagen aquí

Valor máximo vs valor mínimo

Si utilizamos la coincidencia de pagarés, lo que debemos optimizar es el valor máximo. Solo necesitamos realizar una transformación en el primer paso, como se muestra a continuación:
Insertar descripción de la imagen aquí

Por ejemplo, en la Detección 4, Seguimiento 1 (fila 4, columna 1), la métrica de costo es solo 10. Si es una coincidencia de pagaré, significa que el grado de coincidencia es muy bajo. Restamos este valor del valor máximo de todos los valores, como 10, dejamos 90 - 10 = 80.

4. Algoritmo de seguimiento de objetivos

Todos los algoritmos de seguimiento de objetivos convencionales actuales se basan en la estrategia de seguimiento por detección , es decir, el seguimiento de objetivos se basa en los resultados de la detección de objetivos. DeepSort utiliza esta estrategia.

La posición de una misma persona en distintos momentos del vídeo ha cambiado, ¿cómo podemos relacionarlo? La respuesta es el algoritmo húngaro y el filtrado de Kalman.

  • Algoritmo húngaro : haga coincidir un objetivo en el cuadro actual con un objetivo en el cuadro anterior;
  • Filtro de Kalman : predice la posición del momento actual en función de la posición del objetivo en el momento anterior, lo que puede estimar la posición del objetivo con mayor precisión que el detector de objetivos.

1. Cálculo de la distancia al marco objetivo.

Los algoritmos de seguimiento de múltiples objetivos MOT clásicos actuales son clasificación y clasificación profunda. El algoritmo de clasificación pasa primeroalgoritmo húngaroRealice la coincidencia máxima y luego pasefiltro de kalmanHacer predicciones.

En el seguimiento del objetivo real, obtenemos el seguimiento del cuadro de seguimiento del cuadro anterior y la detección del cuadro de detección del cuadro actual.¿Cómo se calcula la métrica de costo de distancia?

marco de detecciónEs el cuadro delimitador detectado por el detector de objetivos del cuadro actual,cuadro de seguimientoEs el cuadro predicho por la última salida del cuadro anterior, no el cuadro de detección.

Hay tres métodos comúnmente utilizados para calcular la distancia del marco objetivo: distancia euclidiana, coincidencia de IOU y similitud de apariencia (costo convolucional).

1.1 distancia euclidiana

Podemos calcular la distancia entre los puntos centrales de los cuadros objetivo de los dos cuadros:
d = ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 \mathrm{d}=\sqrt{(x_2-x_1 ) _2+(y_2-y_1)^2}d=( x2X1)2+( y2y1)2
Insertar descripción de la imagen aquí

Este método es el más simple, pero si la forma del objetivo cambia o el objetivo se superpone con otros, habrá muchos problemas.

1.2 Coincidencia de pagarés

Insertar descripción de la imagen aquí

Como se puede ver en la figura, hay un problema con este método, es decir, no buscamos el mínimo, sino el máximo, por lo que habrá algunas diferencias con el método mencionado anteriormente.

1.3 Similitud de apariencia (costo convolucional)

La coincidencia de pagarés se usa con mucha frecuencia, pero si hay problemas como la superposición de bloques de objetivos, el marco del objetivo también cambiará y la coincidencia de pagarés será inexacta.

Pero incluso si el objetivo está ocluido, si aún podemos detectar parte de él, ¿podemos usar una red convolucional para extraer las características y luego compararlas con las características del marco original? Como se muestra abajo:
Insertar descripción de la imagen aquí

Se agrega información de apariencia, se utilizan modelos de dominio ReID para extraer características y se reducen los cambios de ID. Esta es una de las innovaciones de DeepSort en comparación con Sort.

5. Algoritmo de clasificación profunda

Estudio preliminar sobre seguimiento de objetivos (DeepSORT)

deep_sort_pytorch

1. Introducción al algoritmo DeepSort

En el algoritmo DeepSort, el algoritmo húngaro se utiliza para asociar y hacer coincidir las pistas del cuadro de seguimiento en el cuadro anterior con las detecciones del cuadro de detección en el cuadro actual, y calcular la matriz de costos a través de la información de apariencia y la distancia euclidiana o IOU.

Interpretación del código fuente

#  linear_assignment.py
def min_cost_matching(distance_metric, max_distance, tracks, detections, 
                      track_indices=None, detection_indices=None):
    ...
    
    # 计算代价矩阵
    cost_matrix = distance_metric(tracks, detections, track_indices, detection_indices)
    cost_matrix[cost_matrix > max_distance] = max_distance + 1e-5
    
    # 执行匈牙利算法,得到匹配成功的索引对,行索引为tracks的索引,列索引为detections的索引
    row_indices, col_indices = linear_assignment(cost_matrix)
 
    matches, unmatched_tracks, unmatched_detections = [], [], []
 
    # 找出未匹配的detections
    for col, detection_idx in enumerate(detection_indices):
        if col not in col_indices:
            unmatched_detections.append(detection_idx)
     
    # 找出未匹配的tracks
    for row, track_idx in enumerate(track_indices):
        if row not in row_indices:
            unmatched_tracks.append(track_idx)
    
    # 遍历匹配的(track, detection)索引对
    for row, col in zip(row_indices, col_indices):
        track_idx = track_indices[row]
        detection_idx = detection_indices[col]
        # 如果相应的cost大于阈值max_distance,也视为未匹配成功
        if cost_matrix[row, col] > max_distance:
            unmatched_tracks.append(track_idx)
            unmatched_detections.append(detection_idx)
        else:
            matches.append((track_idx, detection_idx))
 
    return matches, unmatched_tracks, unmatched_detections

2. Proceso del algoritmo DeepSort

El flujo de procesamiento de DeepSORT para cada cuadro es el siguiente:

El detector obtiene el bbox → genera detecciones → predicción del filtro de Kalman → usa el algoritmo húngaro para hacer coincidir las pistas predichas con las deteciones en el cuadro actual (coincidencia en cascada y coincidencia de IOU) → actualización del filtro de Kalman.

**Cuadro 0:** El detector ha detectado 3 detecciones, actualmente no hay pistas y estas 3 detecciones se inicializan como pistas.
**Cuadro 1:** El detector detectó 3 detecciones más. Para las pistas en el Cuadro 0, primero prediga para obtener nuevas pistas y luego use el algoritmo húngaro para hacer coincidir las nuevas pistas con las detecciones para obtener (pista, detección) Emparejar pares , y finalmente actualizar el track correspondiente con la detección en cada par.

2.1 El detector obtiene bbox

Utilice Yolo como detector para detectar el bbox en el cuadro actual:

#  demo_yolo3_deepsort.py
def detect(self):
    while self.vdo.grab():
	...
	bbox_xcycwh, cls_conf, cls_ids = self.yolo3(im)  # 检测到的bbox[cx,cy,w,h],置信度,类别id
	if bbox_xcycwh is not None:
    	    # 筛选出人的类别
    	    mask = cls_ids == 0
  	    bbox_xcycwh = bbox_xcycwh[mask]
  	    bbox_xcycwh[:, 3:] *= 1.2
   	    cls_conf = cls_conf[mask]
            ...

2.2 Generar detecciones

Convierta bboxes detectados en detecciones:

#  deep_sort.py
def update(self, bbox_xywh, confidences, ori_img):
    self.height, self.width = ori_img.shape[:2]
    # 提取每个bbox的feature
    features = self._get_features(bbox_xywh, ori_img)
    # [cx,cy,w,h] -> [x1,y1,w,h]
    bbox_tlwh = self._xywh_to_tlwh(bbox_xywh)
    # 过滤掉置信度小于self.min_confidence的bbox,生成detections
    detections = [Detection(bbox_tlwh[i], conf, features[i]) for i,conf in enumerate(confidences) if conf > self.min_confidence]
    # NMS (这里self.nms_max_overlap的值为1,即保留了所有的detections)
    boxes = np.array([d.tlwh for d in detections])
    scores = np.array([d.confidence for d in detections])
    indices = non_max_suppression(boxes, self.nms_max_overlap, scores)
    detections = [detections[i] for i in indices]
    ...

2.3 Pistas de predicción del filtro de Kalman

Utilice el filtro de Kalman para predecir el estado de las pistas en el fotograma anterior en el fotograma actual:

#  track.py
def predict(self, kf):
    """Propagate the state distribution to the current time step using a 
       Kalman filter prediction step.
    Parameters
    ----------
    kf: The Kalman filter.
    """
    self.mean, self.covariance = kf.predict(self.mean, self.covariance)  # 预测
    self.age += 1  # 该track自出现以来的总帧数加1
    self.time_since_update += 1  # 该track自最近一次更新以来的总帧数加1

2.4 Coincidencia de asociaciones de algoritmos húngaros

Primero, la matriz de costos de seguimiento y detecciones se calcula para la distancia euclidiana en función de la información de apariencia, luego se realizan sucesivamente la coincidencia en cascada y la coincidencia IOU. Finalmente, se obtienen todos los pares coincidentes, pistas no coincidentes y detecciones no coincidentes del cuadro actual:

#  tracker.py
def _match(self, detections):
    def gated_metric(racks, dets, track_indices, detection_indices):
        """
        基于外观信息和欧式距离,计算卡尔曼滤波预测的tracks和当前时刻检测到的detections的代价矩阵
        """
        features = np.array([dets[i].feature for i in detection_indices])
        targets = np.array([tracks[i].track_id for i in track_indices]
	# 基于外观信息,计算tracks和detections的余弦距离代价矩阵
        cost_matrix = self.metric.distance(features, targets)
	# 基于欧式距离,过滤掉代价矩阵中一些不合适的项 (将其设置为一个较大的值)
        cost_matrix = linear_assignment.gate_cost_matrix(self.kf, cost_matrix, tracks, 
                      dets, track_indices, detection_indices)
        return cost_matrix

    # 区分开confirmed tracks和unconfirmed tracks
    confirmed_tracks = [i for i, t in enumerate(self.tracks) if t.is_confirmed()]
    unconfirmed_tracks = [i for i, t in enumerate(self.tracks) if not t.is_confirmed()]

    # 对confirmd tracks进行级联匹配
    matches_a, unmatched_tracks_a, unmatched_detections = \
        linear_assignment.matching_cascade(
            gated_metric, self.metric.matching_threshold, self.max_age,
            self.tracks, detections, confirmed_tracks)

    # 对级联匹配中未匹配的tracks和unconfirmed tracks中time_since_update为1的tracks进行IOU匹配
    iou_track_candidates = unconfirmed_tracks + [k for k in unmatched_tracks_a if
                                                 self.tracks[k].time_since_update == 1]
    unmatched_tracks_a = [k for k in unmatched_tracks_a if
                          self.tracks[k].time_since_update != 1]
    matches_b, unmatched_tracks_b, unmatched_detections = \
        linear_assignment.min_cost_matching(
            iou_matching.iou_cost, self.max_iou_distance, self.tracks,
            detections, iou_track_candidates, unmatched_detections)
	
    # 整合所有的匹配对和未匹配的tracks
    matches = matches_a + matches_b
    unmatched_tracks = list(set(unmatched_tracks_a + unmatched_tracks_b))
    
    return matches, unmatched_tracks, unmatched_detections


# 级联匹配源码  linear_assignment.py
def matching_cascade(distance_metric, max_distance, cascade_depth, tracks, detections, 
                     track_indices=None, detection_indices=None):
    ...
    unmatched_detections = detection_indice
    matches = []
    # 由小到大依次对每个level的tracks做匹配
    for level in range(cascade_depth):
	# 如果没有detections,退出循环
        if len(unmatched_detections) == 0:  
            break
	# 当前level的所有tracks索引
        track_indices_l = [k for k in track_indices if 
                           tracks[k].time_since_update == 1 + level]
	# 如果当前level没有track,继续
        if len(track_indices_l) == 0: 
            continue
		
	# 匈牙利匹配
        matches_l, _, unmatched_detections = min_cost_matching(distance_metric, max_distance, tracks, detections, 
                                                               track_indices_l, unmatched_detections)
        
	matches += matches_l
	unmatched_tracks = list(set(track_indices) - set(k for k, _ in matches))
    return matches, unmatched_tracks, unmatched_detections

2.5 Actualización del filtro Kalman

Para cada pista coincidente exitosamente, actualícela con su detección correspondiente y maneje las pistas y detecciones no coincidentes:

#  tracker.py
def update(self, detections):
    """Perform measurement update and track management.
    Parameters
    ----------
    detections: List[deep_sort.detection.Detection]
                A list of detections at the current time step.
    """
    # 得到匹配对、未匹配的tracks、未匹配的dectections
    matches, unmatched_tracks, unmatched_detections = self._match(detections)

    # 对于每个匹配成功的track,用其对应的detection进行更新
    for track_idx, detection_idx in matches:
        self.tracks[track_idx].update(self.kf, detections[detection_idx])
    
	# 对于未匹配的成功的track,将其标记为丢失
	for track_idx in unmatched_tracks:
        self.tracks[track_idx].mark_missed()
	
    # 对于未匹配成功的detection,初始化为新的track
    for detection_idx in unmatched_detections:
        self._initiate_track(detections[detection_idx])
		...

Supongo que te gusta

Origin blog.csdn.net/m0_37605642/article/details/132244570
Recomendado
Clasificación