计算边界框重叠的百分比,以进行图像检测器评估
computer-vision
object-detection
python
5
0

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

根据Pascal VOC的挑战,存在以下问题:

如果预测的边界框与真实边界框的重叠超过50%,则认为该边界框是正确的,否则,边界框被认为是误报。多次检测将受到处罚。如果系统预测与单个地面真实边界框重叠的多个边界框,则仅一个预测被认为是正确的,其他预测被认为是误报。

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

我进行了搜索,但没有找到标准的算法-这令人惊讶,因为我会认为这在计算机视觉中很常见。 (我是新来的)。我错过了吗?有谁知道这种类型的问题的标准算法是什么?

参考资料:
Stack Overflow
收藏
评论
共 4 个回答
高赞 时间 活跃

对于轴对齐的边界框,它相对简单。 “轴对齐”表示边界框未旋转;换句话说,框线平行于轴。这是计算两个与轴对齐的边界框的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

说明

在此处输入图片说明在此处输入图片说明

图片来自此答案

收藏
评论

如果您使用的是屏幕(像素)坐标,则投票最高的答案会出现数学错误!几周前,我提交一篇社论,对所有读者进行了详尽的解释,以便他们理解数学。但是审阅者无法理解该编辑内容,因此删除了该编辑内容,因此我再次提交了相同的编辑内容,但这次进行了更简短的总结。 (更新:已拒绝2vs1,因为它被认为是“重大更改”,呵呵)。

因此,我将在此单独的答案中通过数学完全解释BIG问题。

因此,是的,通常来说,票数最高的答案是正确的,并且是计算IoU的好方法。但是(正如其他人也指出的那样),它的数学运算对于计算机屏幕是完全不正确的。您不能只做(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)

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

1920x1080屏幕从索引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)错误area = (x_right - x_left) * (y_bottom - y_top) ,我们将得到: (1919 - 0) * (1079 - 0) 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)area = (x_right - x_left + 1) * (y_bottom - y_top + 1)area = (x_right - x_left + 1) * (y_bottom - y_top + 1)(1919 - 0 + 1) * (1079 - 0 + 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)
收藏
评论

一种简单的方法

例 (图像未按比例绘制)

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%

收藏
评论

对于相交距离,我们是否应该添加+1以使

intersection_area = (x_right - x_left + 1) * (y_bottom - y_top + 1)   

(与AABB相同)
喜欢在这个pyimage搜索帖子上

我同意(x_right-x_left)x(y_bottom-y_top)在具有点坐标的数学中工作,但是由于我们处理像素,因此我认为是不同的。

考虑一维示例:
-2分: x1 = 1x2 = 3 ,距离的确是x2-x1 = 2
-索引为2个像素: i1 = 1i2 = 3 ,从像素i1到i2的段包含3个像素,即l = i2-i1 + 1

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号