<p>如果使用屏幕(像素)坐标,<a href="https://stackoverflow.com/a/42874377/8874388">top-voted answer</a>有数学错误!几周前,我向所有读者提交了<a href="https://stackoverflow.com/review/suggested-edits/24012424">an edit</a>一份冗长的解释,以便他们理解数学。但是那个编辑没有被评论人理解并且被删除了,所以我再次提交了同样的编辑,但是这次更简短的总结了一下。(更新:<a href="https://stackoverflow.com/review/suggested-edits/24148934">Rejected 2vs1</a>因为它被认为是一个“实质性的改变”,呵呵)。</p>
<p>所以我将在这个单独的答案中用它的数学完全解释这个大问题。</p>
<p>所以,是的,总的来说,最高投票的答案是正确的,是计算欠条的好方法。但是(正如其他人也指出的那样),它的数学对电脑屏幕来说是完全错误的。你不能只做<code>(x2 - x1) * (y2 - y1)</code>,因为这不会产生正确的面积计算。屏幕索引从像素<code>0,0</code>开始,到<code>width-1,height-1</code>结束。屏幕坐标的范围是<code>inclusive:inclusive</code>(两端都包含),因此在像素坐标中从<code>0</code>到<code>10</code>的范围实际上是11个像素宽,因为它包含<code>0 1 2 3 4 5 6 7 8 9 10</code>(11个项)。因此,要计算屏幕坐标的面积,必须向每个维度添加+1,如下所示:<code>(x2 - x1 + 1) * (y2 - y1 + 1)</code>。</p>
<p>如果您在其他坐标系中工作,其中的范围不包含(例如<code>inclusive:exclusive</code>系统,其中<code>0</code>到<code>10</code>表示“元素0-9而不是10”),则不需要额外的数学运算。但最有可能的是,您正在处理基于像素的边界框。好吧,屏幕坐标从<code>0,0</code>开始,然后从那里往上。</p>
<p>屏幕的索引从<code>0</code>(第一个像素)到<code>1919</code>(最后一个水平像素),从<code>0</code>(第一个像素)到<code>1079</code>(最后一个垂直像素)。</p>
<p>因此,如果在“像素坐标空间”中有一个矩形,为了计算它的面积,我们必须在每个方向上加1。否则,我们得到的面积计算结果是错误的。</p>
<p>假设我们的<code>1920x1080</code>屏幕有一个基于像素坐标的矩形,<code>left=0,top=0,right=1919,bottom=1079</code>(覆盖整个屏幕上的所有像素)。</p>
<p>我们知道<code>1920x1080</code>像素是<code>2073600</code>像素,这是1080p屏幕的正确区域。</p>
<p>但是如果使用错误的数学<code>area = (x_right - x_left) * (y_bottom - y_top)</code>,我们将得到:<code>(1919 - 0) * (1079 - 0)</code>=<code>1919 * 1079</code>=<code>2070601</code>像素!那是错误的!</p>
<p>这就是为什么我们必须将<code>+1</code>添加到每个计算中,这给了我们以下正确的数学公式:<code>area = (x_right - x_left + 1) * (y_bottom - y_top + 1)</code>,给了我们:<code>(1919 - 0 + 1) * (1079 - 0 + 1)</code>=<code>1920 * 1080</code>=<code>2073600</code>像素!这确实是正确的答案!</p>
<p>最简短的总结是:像素坐标范围是<code>inclusive:inclusive</code>,因此如果我们想要像素坐标范围的真实区域,必须将<code>+ 1</code>添加到每个轴。</p>
<p>关于为什么需要<code>+1</code>的更多细节,请参见Jindil的答案:<a href="https://stackoverflow.com/a/51730512/8874388">https://stackoverflow.com/a/51730512/8874388</a></p>
<p>以及这篇pyimagesearch文章:
<a href="https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/" rel="noreferrer">https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/</a></p>
<p>以及这个GitHub注释:
<a href="https://github.com/AlexeyAB/darknet/issues/3995#issuecomment-535697357" rel="noreferrer">https://github.com/AlexeyAB/darknet/issues/3995#issuecomment-535697357</a></p>
<p>由于固定的数学没有被批准,任何从最上面的投票答案复制代码的人都希望看到这个答案,并且将能够通过简单地复制错误固定的断言和下面的区域计算行(这些行已经为<code>inclusive:inclusive</code>(像素)坐标范围固定)来自行修复它:</p>
<pre class="lang-py prettyprint-override"><code> 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)
</code></pre>