2

I need to find the area of ​​intersection and union of two rectangles, as well as the ratio of the intersection area to the union area. What is the best way to do this? Picture

def intersection_over_union(a, b):
    ax1 = a['left']
    ay1 = a['top']
    aw = a['width']
    ah = a['height']
    ax2 = ax1 + aw
    ay2 = ay1 + ah

    bx1 = b['left']
    by1 = b['top']
    bw = b['width']
    bh = b['height']
    bx2 = bx1 + bw
    by2 = by1 + bh

    delta_x = max(ax1, bx1) - min(ax2, bx2)
    delta_y = max(ay1, by1) - min(ay2, by2)

    overlap = delta_x * delta_y
    union = aw * ah + bw * bh - overlap

    print(overlap, union)

    return overlap / union
Meetinger
  • 165
  • 8
  • I need areas of intersection and union – Meetinger Jun 29 '21 at 14:09
  • @TomKarzes I have the impression that these are just AABB as they have only position and size. – Jakub Dóka Jun 29 '21 at 14:15
  • If both boxes don't overlap, then, say box A is left of box B, ax1 < ax2 < bx1 < b2 and if I assume box A is on top, box B at the bottom, then ay1 < ay2 < by1 < by2. Hence delta_x = bx1 - bx2 < 0 and delty_y < 0 for a similar reason. The calculated positive overlap is incorrect. Hence if either delta_x or delta_y is negative, the overlap is zero. – Ronald Jun 29 '21 at 14:17
  • @TomKarzes The OP never mentioned triangles, OP is talking about rectangles. Why do you suggest everything with triangles? Am I missing something? – lifezbeautiful Jun 29 '21 at 14:27
  • 1
    @lifezbeautiful Oh, wow I totally misread that - thanks for pointing it out. For some reason I read "rectangle" as "triangle". – Tom Karzes Jun 29 '21 at 15:02

2 Answers2

3

Assuming you are dealing with AABB (axis aligned bounding box) this little class defines everything you need:

class Rect:
    def __init__(self, x, y, w, h):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
    
    def bottom(self):
        return self.y + self.h
    
    def right(self):
        return self.x + self.w
    
    def area(self):
        return self.w * self.h

    def union(self, b):
        posX = min(self.x, b.x)
        posY = min(self.y, b.y)
        
        return Rect(posX, posY, max(self.right(), b.right()) - posX, max(self.bottom(), b.bottom()) - posY)
    
    def intersection(self, b):
        posX = max(self.x, b.x)
        posY = max(self.y, b.y)
        
        candidate = Rect(posX, posY, min(self.right(), b.right()) - posX, min(self.bottom(), b.bottom()) - posY)
        if candidate.w > 0 and candidate.h > 0:
            return candidate
        return Rect(0, 0, 0, 0)
    
    def ratio(self, b):
        return self.intersection(b).area() / self.union(b).area()

if __name__ == "__main__":
    assert Rect(1, 1, 1, 1).ratio(Rect(1, 1, 1, 1)) == 1
    assert round(Rect(1, 1, 2, 2).ratio(Rect(2, 2, 2, 2)), 4) == 0.1111
Jakub Dóka
  • 2,477
  • 1
  • 7
  • 12
  • ```def iou(a, b): ax1 = a['left'] ay1 = a['top'] aw = a['width'] ah = a['height'] rectA = Rect(ax1, ay1, aw, ah) bx1 = b['left'] by1 = b['top'] bw = b['width'] bh = b['height'] rectB = Rect(bx1, by1, bw, bh) return rectA.ratio(rectB)``` This code returns ```return self.intersection(b).area() / self.union(b).area() AttributeError: 'NoneType' object has no attribute 'area'``` – Meetinger Jun 29 '21 at 14:52
  • I have no idea why i have to explicitly show you how to solve so trivial issue but whatever. This edit fixes it. @Meetinger – Jakub Dóka Jun 29 '21 at 15:02
  • @JakubDóka The union of two rectangles is not necessarily a rectangle. – SiLiKhon Sep 24 '21 at 14:45
  • @SiLiKhon yes I am aware that union can be a Point. How does that matter though? You can define a point and return it when necessary, it really depends on what you want. – Jakub Dóka Sep 25 '21 at 17:03
  • @JakubDóka the **union** is the set of all points belonging to **either** of the rectangles – SiLiKhon Sep 25 '21 at 21:05
  • now that i look at the question i understand what you mean, well, i ll edit it one day – Jakub Dóka Sep 26 '21 at 13:13
0

One way I believe you could do this (although I am not sure it is the best solution as you've asked for), is to develop a function that creates a rectangle in a plane, and stores all of its corners' coordinates in a list.

Every time you create a rectangle (let's say you create it from the bottom left, increasing its x and y coordinates as you go), check for each coordinate if the x coordinate is within the other rectangle's x-range i.e. x_min < x < x_max. If so, check the y-coordinate. If the coordinate is within the x and y ranges of another rectangle, it's part of the intersection.

Repeat for all coordinates as you create them and save the intersection coordinates, and find the intersection's corners. With that, you can calculate the area of intersection and union between the two triangles, and their ratio to one another.

Eantropix
  • 1
  • 3