判断两个矩形是否相交(Rect Intersection)

0x00 Preface

最近在开发一个2D组态图形组件的过程中,里面的数学模块,涉及到两个矩形是否相交的判断。

这个问题很多年前就写过,算是个小的算法吧。

网络上搜索一下,有很多思路,有一些思路要基于多种组合的判断,显得比较复杂。 比如两个矩形相交的情形,可能有下面的多种类型:

image.png

而每种类型又有多种子类型。

0x01 Body

其实可以反向来思考这个问题,就比较简单,两个矩形A和B,不相交的情况有哪些,然后通过bool 取反,就是相交的情况。
假设矩形的的定义如下:

class Rect {
    constructor(x,y,w,h) {
      this.x = x;
      this.y = y;
      this.w = w;
      this.h = h;
      
      this.r = x + w; // r表示矩形的右边
      this.b = y + h; // b 表示矩形的下边
    }
}

不相交的情况可以归纳为这几种情况:

  • A在B的左边 (A.r < B.x)
  • A在B的右边 ( B.r < A.x)
  • A在B的上边 (A.b < B.y )
  • A在B的下边 (B.b < A.y )

所以不相交的代码如下:

A.r < B.x || B.r < A.x || A.b < B.y || B.b <A.y

对于这种情况取反,就是相交的情况:

!(A.r < B.x || B.r < A.x || A.b < B.y || B.b <A.y)

取反之后 或变与:

A.r >= B.x && B.r >= A.x && A.b >= B.y && B.b >= A.y

尝试着问下ChatGPT,它给出的正是这种思路,如下图:

image.png

0x02 Conclusion

  • 有时候反过来思考问题,是一种很好的思路
  • ChatGPT 牛逼。

0x03 The Last

最后,关注公号“ITMan彪叔” 可以添加作者微信进行交流,及时收到更多有价值的文章。

<think>我们有一个任务:计算两个矩形区域的相交面积。用户提到了可能需要使用OpenCV(cv2)或纯Python实现。根据引用[1],OpenCV提供了一个函数`rotatedRectangleIntersection`用于计算两个旋转矩形相交区域,并返回相交区域的顶点。但用户的问题可能针对的是非旋转矩形(即轴对齐矩形)。不过,引用[2]也提到了多个矩形重叠区域的面积计算。注意:用户的问题没有明确矩形是否是旋转的。在计算机视觉中,矩形通常有两种:轴对齐矩形(无旋转)和旋转矩形。如果用户指的是轴对齐矩形(即矩形的边与坐标轴平行),那么问题可以简化。两个轴对齐矩形相交区域也是一个矩形(或空),其面积计算相对简单。但是,如果矩形是旋转的,那么相交区域将是一个多边形(可能有4到8条边),计算面积需要先得到相交多边形的顶点,然后使用多边形面积公式。由于用户没有明确,我们可以考虑两种情况:情况1:两个矩形都是轴对齐的(非旋转)。情况2:两个矩形是旋转的(任意角度)。根据引用[1]和引用[2],我们可以分别提供两种情况的解决方案。首先,对于轴对齐矩形:假设矩形1由左上角点(x1,y1)和右下角点(x1+width1,y1+height1)定义,矩形2由(x2,y2)(x2+width2,y2+height2)定义。相交矩形的计算如下:left=max(x1,x2)top=max(y1,y2)right=min(x1+width1,x2+width2)bottom=min(y1+height1,y2+height2)ifleft<rightandtop<bottom:area=(right-left)*(bottom-top)else:area=0#没有相交其次,对于旋转矩形:我们可以使用OpenCV的`rotatedRectangleIntersection`函数(需要OpenCV3.0以上版本)来计算两个旋转矩形相交区域,然后计算该相交多边形的面积。步骤:1.定义两个旋转矩形(使用中心坐标、宽高、旋转角度)。2.调用`cv2.rotatedRectangleIntersection(rect1,rect2)`得到相交区域(一个多边形)。3.如果返回的相交类型是`INTERSECT_FULL`或`INTERSECT_PARTIAL`,则计算多边形的面积;否则面积为0。4.计算多边形面积可以使用`cv2.contourArea`。注意:`rotatedRectangleIntersection`函数返回的相交区域是一个点集(轮廓)。由于用户要求使用Python,我们将提供两种情况的代码示例。另外,引用[2]提到多个矩形的重叠面积,但用户目前只问两个矩形,所以我们先解决两个矩形的情况。下面我们分别提供两种情况的代码实现。</think>### 计算两个矩形相交面积的方法 计算两个矩形区域的相交面积需根据矩形类型选择不同方法,以下是两种常见情况的解决方案: --- ### **1. 轴对齐矩形(边平行于坐标轴)** 若矩形未旋转(边平行于坐标轴),相交区域仍是矩形,计算逻辑简单: ```python def axis_aligned_intersection_area(rect1, rect2): # rect格式: (x1, y1, x2, y2) [左上角坐标+右下角坐标] left = max(rect1[0], rect2[0]) top = max(rect1[1], rect2[1]) right = min(rect1[2], rect2[2]) bottom = min(rect1[3], rect2[3]) if left < right and top < bottom: return (right - left) * (bottom - top) else: return 0.0 # 无重叠 # 示例 rect_a = (0, 0, 5, 5) # 矩形A: (x1,y1,x2,y2) rect_b = (3, 3, 8, 8) # 矩形B area = axis_aligned_intersection_area(rect_a, rect_b) # 输出: 4.0 ``` --- ### **2. 旋转矩形(任意角度)** 若矩形带旋转角度,需使用OpenCV计算相交多边形再求面积: ```python import cv2 import numpy as np def rotated_rect_intersection_area(rect1, rect2): """ 参数格式: ((中心x, 中心y), (宽, 高), 旋转角度) """ # 计算相交多边形顶点 intersect_type, points = cv2.rotatedRectangleIntersection(rect1, rect2) if intersect_type == cv2.INTERSECT_NONE: # 无相交 return 0.0 elif intersect_type in (cv2.INTERSECT_PARTIAL, cv2.INTERSECT_FULL): # 将顶点转换为轮廓并计算面积 contour = np.array(points).reshape(-1, 1, 2).astype(np.float32) return cv2.contourArea(contour) return 0.0 # 示例 rect_a = ((10, 10), (20, 10), 30) # 中心(10,10), 宽20高10, 旋转30度 rect_b = ((15, 15), (15, 15), 45) area = rotated_rect_intersection_area(rect_a, rect_b) ``` #### **关键函数说明** - `cv2.rotatedRectangleIntersection()`: 计算两个旋转矩形相交区域,返回相交类型和顶点列表[^1]。 - `cv2.contourArea()`: 计算多边形轮廓的面积,适用于相交区域[^1][^2]。 --- ### **注意事项** 1. **OpenCV版本要求**:`rotatedRectangleIntersection`需OpenCV 3.4.0+,安装命令: ```bash pip install opencv-python>=3.4.0 ``` 2. **顶点顺序**:相交区域顶点需按顺时针/逆时针排序,否则`contourArea()`可能返回负值。 3. **性能优化**:对轴对齐矩形优先使用纯数学计算,避免OpenCV开销。 --- ### **数学原理补充** 相交多边形的面积可通过**鞋带公式**(Shoelace formula)计算: $$ \text{Area} = \frac{1}{2} \left| \sum_{i=1}^{n} (x_i y_{i+1} - x_{i+1} y_i) \right| $$ 其中$(x_i, y_i)$为多边形顶点坐标,$x_{n+1}=x_1, y_{n+1}=y_1$。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值