Saltar al contenido

Cálculo del porcentaje de superposición del cuadro delimitador, para la evaluación del detector de imágenes

Posteriormente a indagar en diferentes repositorios y sitios de internet al concluir hallamos la solución que te enseñaremos más adelante.

Solución:

Para los cuadros delimitadores alineados con el eje, es relativamente sencillo. “Alineado con el eje” significa que el cuadro delimitador no está girado; o en otras palabras, que las líneas de las cajas son paralelas a los ejes. A continuación, se explica cómo calcular el IoU de dos cuadros delimitadores alineados con el eje.

def get_iou(bb1, bb2):
    """
    Calculate the Intersection over Union (IoU) of two bounding boxes.

    Parameters
    ----------
    bb1 : dict
        Keys: 'x1', 'x2', 'y1', 'y2'
        The (x1, y1) position is at the top left corner,
        the (x2, y2) position is at the bottom right corner
    bb2 : dict
        Keys: 'x1', 'x2', 'y1', 'y2'
        The (x, y) position is at the top left corner,
        the (x2, y2) position is at the bottom right corner

    Returns
    -------
    float
        in [0, 1]
    """
    assert bb1['x1'] < bb1['x2']
    assert bb1['y1'] < bb1['y2']
    assert bb2['x1'] < bb2['x2']
    assert bb2['y1'] < bb2['y2']

    # determine the coordinates of the intersection rectangle
    x_left = max(bb1['x1'], bb2['x1'])
    y_top = max(bb1['y1'], bb2['y1'])
    x_right = min(bb1['x2'], bb2['x2'])
    y_bottom = min(bb1['y2'], bb2['y2'])

    if x_right < x_left or y_bottom < y_top:
        return 0.0

    # The intersection of two axis-aligned bounding boxes is always an
    # axis-aligned bounding box
    intersection_area = (x_right - x_left) * (y_bottom - y_top)

    # compute the area of both AABBs
    bb1_area = (bb1['x2'] - bb1['x1']) * (bb1['y2'] - bb1['y1'])
    bb2_area = (bb2['x2'] - bb2['x1']) * (bb2['y2'] - bb2['y1'])

    # compute the intersection over union by taking the intersection
    # area and dividing it by the sum of prediction + ground-truth
    # areas - the interesection area
    iou = intersection_area / float(bb1_area + bb2_area - intersection_area)
    assert iou >= 0.0
    assert iou <= 1.0
    return iou

Explicación

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Las imágenes son de esta respuesta

¡La respuesta más votada tiene un error matemático si está trabajando con coordenadas de pantalla (píxeles)! Envié una edición hace unas semanas con una larga explicación para todos los lectores para que entendieran las matemáticas. Pero esa edición no fue entendida por los revisores y fue eliminada, así que envié la misma edición nuevamente, pero esta vez resumida más brevemente. (Actualización: Rechazado 2vs1 porque se consideró un "cambio sustancial", je).

Entonces, explicaré completamente el GRAN problema con sus matemáticas aquí en esta respuesta separada.

Entonces, sí, en general, la respuesta más votada es correcta y es una buena manera de calcular el IoU. Pero (como también han señalado otras personas) su matemática es completamente incorrecta para las pantallas de computadora. No puedes simplemente hacer (x2 - x1) * (y2 - y1), ya que eso no producirá los cálculos de área correctos en absoluto. La indexación de la pantalla comienza en el píxel 0,0 y termina en width-1,height-1. El rango de coordenadas de la pantalla es inclusive:inclusive (inclusive en ambos extremos), por lo que un rango de 0 para 10 en coordenadas de píxeles tiene en realidad 11 píxeles de ancho, porque incluye 0 1 2 3 4 5 6 7 8 9 10 (11 artículos). Entonces, para calcular el área de las coordenadas de la pantalla, DEBE agregar +1 a cada dimensión, de la siguiente manera: (x2 - x1 + 1) * (y2 - y1 + 1).

Si está trabajando en algún otro sistema de coordenadas donde el rango no es inclusivo (como un inclusive:exclusive sistema donde 0 para 10 significa "elementos 0-9 pero no 10"), entonces esta matemática adicional NO sería necesaria. Pero lo más probable es que esté procesando cuadros delimitadores basados ​​en píxeles. Bueno, las coordenadas de la pantalla comienzan en 0,0 y sube desde allí.

A 1920x1080 la pantalla está indexada desde 0 (primer píxel) a 1919 (último píxel horizontalmente) y desde 0 (primer píxel) a 1079 (último píxel verticalmente).

Entonces, si tenemos un rectángulo en "espacio de coordenadas de píxeles", para calcular su área debe agregue 1 en cada dirección. De lo contrario, obtenemos la respuesta incorrecta para el cálculo del área.

Imagina que nuestro 1920x1080 La pantalla tiene un rectángulo basado en coordenadas de píxeles con left=0,top=0,right=1919,bottom=1079 (que cubre todos los píxeles de toda la pantalla).

Bueno, sabemos que 1920x1080 píxeles es 2073600 píxeles, que es el área correcta de una pantalla de 1080p.

Pero con las matemáticas equivocadas area = (x_right - x_left) * (y_bottom - y_top), obtendríamos: (1919 - 0) * (1079 - 0) = 1919 * 1079 = 2070601 píxeles! ¡Eso está mal!

Por eso debemos agregar +1 a cada cálculo, lo que nos da las siguientes matemáticas corregidas: area = (x_right - x_left + 1) * (y_bottom - y_top + 1), dándonos: (1919 - 0 + 1) * (1079 - 0 + 1) = 1920 * 1080 = 2073600 píxeles! ¡Y esa es de hecho la respuesta correcta!

El resumen más corto posible es: Los rangos de coordenadas de píxeles son inclusive:inclusive, entonces debemos agregar + 1 a cada eje si queremos el true área de un rango de coordenadas de píxeles.

Para obtener algunos detalles más sobre por qué +1 es necesario, consulte la respuesta de Jindil: https://stackoverflow.com/a/51730512/8874388

Además de este artículo de pyimagesearch: https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/

Y este comentario de GitHub: https://github.com/AlexeyAB/darknet/issues/3995#issuecomment-535697357

Dado que la matemática corregida no fue aprobada, cualquiera que copie el código de la respuesta más votada con suerte verá esta respuesta y podrá corregirlo ellos mismos, simplemente copiando las afirmaciones corregidas y las líneas de cálculo de área a continuación, que han sido arreglado para inclusive:inclusive rangos de coordenadas (píxeles):

    assert bb1['x1'] <= bb1['x2']
    assert bb1['y1'] <= bb1['y2']
    assert bb2['x1'] <= bb2['x2']
    assert bb2['y1'] <= bb2['y2']

................................................

    # The intersection of two axis-aligned bounding boxes is always an
    # axis-aligned bounding box.
    # NOTE: We MUST ALWAYS add +1 to calculate area when working in
    # screen coordinates, since 0,0 is the top left pixel, and w-1,h-1
    # is the bottom right pixel. If we DON'T add +1, the result is wrong.
    intersection_area = (x_right - x_left + 1) * (y_bottom - y_top + 1)

    # compute the area of both AABBs
    bb1_area = (bb1['x2'] - bb1['x1'] + 1) * (bb1['y2'] - bb1['y1'] + 1)
    bb2_area = (bb2['x2'] - bb2['x1'] + 1) * (bb2['y2'] - bb2['y1'] + 1)

A Sencillo camino

ejemplo
(La imagen no está dibujada a escala)

from shapely.geometry import Polygon


def calculate_iou(box_1, box_2):
    poly_1 = Polygon(box_1)
    poly_2 = Polygon(box_2)
    iou = poly_1.intersection(poly_2).area / poly_1.union(poly_2).area
    return iou


box_1 = [[511, 41], [577, 41], [577, 76], [511, 76]]
box_2 = [[544, 59], [610, 59], [610, 94], [544, 94]]

print(calculate_iou(box_1, box_2))

El resultado sera 0.138211... lo que significa 13.82%.

Te mostramos reseñas y calificaciones

Si estás contento con lo expuesto, eres capaz de dejar una sección acerca de qué te ha parecido esta división.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *