计算边界框重叠百分比,用于图像检测器评估

2024-05-15 12:31:05 发布

您现在位置:Python中文网/ 问答频道 /正文

在测试大图像中的目标检测算法时,我们将检测到的边界框与给定的地面真值矩形坐标进行比较。

根据帕斯卡VOC挑战赛,有以下几点:

A predicted bounding box is considered correct if it overlaps more than 50% with a ground-truth bounding box, otherwise the bounding box is considered a false positive detection. Multiple detections are penalized. If a system predicts several bounding boxes that overlap with a single ground-truth bounding box, only one prediction is considered correct, the others are considered false positives.

这意味着我们需要计算重叠的百分比。这是否意味着地面真值框被检测到的边界框覆盖了50%?或者50%的边界框被地面真相框吸收?

我已经搜索过了,但是我还没有找到一个标准的算法来解决这个问题——这是令人惊讶的,因为我会认为这在计算机视觉中是很常见的。(我是新手)。我错过了吗?有人知道这类问题的标准算法是什么吗?


Tags: the算法boxfalseiswithare边界
3条回答

A简单的方式

example (图像未按比例绘制)

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

结果将是0.138211...,这意味着13.82%

如果使用屏幕(像素)坐标,top-voted answer有数学错误!几周前,我向所有读者提交了an edit一份冗长的解释,以便他们理解数学。但是那个编辑没有被评论人理解并且被删除了,所以我再次提交了同样的编辑,但是这次更简短的总结了一下。(更新:Rejected 2vs1因为它被认为是一个“实质性的改变”,呵呵)。

所以我将在这个单独的答案中用它的数学完全解释这个大问题。

所以,是的,总的来说,最高投票的答案是正确的,是计算欠条的好方法。但是(正如其他人也指出的那样),它的数学对电脑屏幕来说是完全错误的。你不能只做(x2 - x1) * (y2 - y1),因为这不会产生正确的面积计算。屏幕索引从像素0,0开始,到width-1,height-1结束。屏幕坐标的范围是inclusive:inclusive(两端都包含),因此在像素坐标中从010的范围实际上是11个像素宽,因为它包含0 1 2 3 4 5 6 7 8 9 10(11个项)。因此,要计算屏幕坐标的面积,必须向每个维度添加+1,如下所示:(x2 - x1 + 1) * (y2 - y1 + 1)

如果您在其他坐标系中工作,其中的范围不包含(例如inclusive:exclusive系统,其中010表示“元素0-9而不是10”),则不需要额外的数学运算。但最有可能的是,您正在处理基于像素的边界框。好吧,屏幕坐标从0,0开始,然后从那里往上。

屏幕的索引从0(第一个像素)到1919(最后一个水平像素),从0(第一个像素)到1079(最后一个垂直像素)。

因此,如果在“像素坐标空间”中有一个矩形,为了计算它的面积,我们必须在每个方向上加1。否则,我们得到的面积计算结果是错误的。

假设我们的1920x1080屏幕有一个基于像素坐标的矩形,left=0,top=0,right=1919,bottom=1079(覆盖整个屏幕上的所有像素)。

我们知道1920x1080像素是2073600像素,这是1080p屏幕的正确区域。

但是如果使用错误的数学area = (x_right - x_left) * (y_bottom - y_top),我们将得到:(1919 - 0) * (1079 - 0)=1919 * 1079=2070601像素!那是错误的!

这就是为什么我们必须将+1添加到每个计算中,这给了我们以下正确的数学公式:area = (x_right - x_left + 1) * (y_bottom - y_top + 1),给了我们:(1919 - 0 + 1) * (1079 - 0 + 1)=1920 * 1080=2073600像素!这确实是正确的答案!

最简短的总结是:像素坐标范围是inclusive:inclusive,因此如果我们想要像素坐标范围的真实区域,必须将+ 1添加到每个轴。

关于为什么需要+1的更多细节,请参见Jindil的答案:https://stackoverflow.com/a/51730512/8874388

以及这篇pyimagesearch文章: https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/

以及这个GitHub注释: https://github.com/AlexeyAB/darknet/issues/3995#issuecomment-535697357

由于固定的数学没有被批准,任何从最上面的投票答案复制代码的人都希望看到这个答案,并且将能够通过简单地复制错误固定的断言和下面的区域计算行(这些行已经为inclusive:inclusive(像素)坐标范围固定)来自行修复它:

    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)

对于轴对齐的边界框,它相对简单。”“轴对齐”表示边界框未旋转;换句话说,框线与轴平行。下面是如何计算两轴对齐边界框的IoU。

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

解释

enter image description hereenter image description here

图片来自this answer

相关问题 更多 >