获取一般椭圆外接矩形

本文最后更新于:2022年7月4日 上午

正椭圆的外接矩形可以直接根据椭圆中心以及长短半轴确定,但一般的斜椭圆就要复杂一些,本文记录计算斜椭圆外接矩形的过程。

问题描述

  • 如上述动图所示,给定一个一般但中心为原点的椭圆,长半轴 $a$, 短半轴 $b$,角度 $\alpha$。
  • 需要求得在给定 $a,b,\alpha$ 下椭圆的外接矩形,可以将问题简化为在给定数据下求图中 $height$ 变量。

一般化方程

  • 正椭圆方程为:
$$ \frac{x^{2}}{a^{2}}+\frac{y^{2}}{b^{2}}=1 $$
  • 当顺时针旋转角度 $\alpha$ 后,$x,y$ 值可以表示为:
$$ \begin{array}{c} x=x^{\prime} \cos \alpha-y^{\prime} \sin \alpha \\ y=x^{\prime \prime} \sin \alpha+y^{\prime \prime} \cos \alpha \end{array} $$
  • 带入正椭圆方程得到中心在原点的一般椭圆方程:

$$
\frac { ( x ^ { \prime } \cos \theta - y ^ { \prime } \sin \theta ) ^ { 2 } } { a ^ { 2 } } + \frac { ( x ^ { \prime } \sin \theta + y ^ { \prime } \cos \theta) ^ { 2 } } { b ^ { 2 } } = 1
$$

  • 展开得到:
$$ \left(a^{2} \sin ^{2} \theta+b^{2} \cos ^{2} \theta\right) \cdot x^{\prime 2}+\left(a^{2} \cos ^{2} \theta+b^{2} \sin ^{2} \theta\right) \cdot y^{\prime 2}+2\left(a^{2}-b^{2}\right) \sin \theta \cos \theta \cdot x^{\prime} y^{\prime} -a^{2} b^{2}=0 $$
  • 对此我们将该种类的椭圆方程一般化,有方程:
$$ \mathrm{Ax}^{2}+\mathrm{Bxy}+\mathrm{Cy}^{2}+\mathrm{D}=0 $$
  • 对应得到:
$$ \begin{array}{c} A=a^{2} \sin ^{2} \theta+b^{2} \cos ^{2} \theta \\ B=2\left(a^{2}-b^{2}\right) \sin \theta \cos \theta \\ C=a^{2} \cos ^{2} \theta+b^{2} \sin ^{2} \theta \\ \quad D=-a^{2} b^{2} \end{array} $$
  • 即我们讨论的椭圆方程总可以化成一般方程的形式,之后我们均在一般化方程基础上讨论解法

方法一

求解思路

  • 需要解得 $y$ 对 $x$ 导数为 0 的点,取绝对值即可

解决方法

  • 我们的目的是寻找 $\frac{\partial y}{\partial x}$ 为 0 的点,那么直接对 $x$ 求偏导:
$$ \begin{array}{c} \mathrm{Ax}^{2}+\mathrm{Bxy}+\mathrm{Cy}^{2}+\mathrm{D}=0\\ 2Ax+B(y+x\frac{\partial y}{\partial x})+2Cy\frac{\partial y}{\partial x}=0 \end{array} $$
  • 令 $\frac{\partial y}{\partial x} = 0$,有:

$$
2Ax+By=0
$$

  • 不考虑 $A = 0$ 的情况下:

$$
x = - \frac{B}{2A}
$$

  • 带入一般方程:
$$ \begin{array}{c} \frac {B^2}{4A}y^2-\frac{B^2}{2A}y^2+Cy^2=-D\\ y^2=\frac{4AD}{B^2-4AC} \end{array} $$
  • 得到高度:

$$
height=|\sqrt{\frac{4AD}{B^2-4AC}}|
$$

方法二

解决思路

  • 将一般方程的 $ y$ 看做常数,$x$ 为自变量
  • 如果解得 $x$,那么就相当于给定 $y = t$ 的情况下,椭圆与该直线的交点 $x$ 坐标
  • 那么问题转化成了一元二次方程,当解的个数仅有一个的时候,直线 $y=t$与椭圆相切,也就是我们想要找的值
  • $height=|t|$

解决方法

  • 关于 $x$ 的一元二次方程
$$ \mathrm{Ax}^{2}+\mathrm{Bxy}+\mathrm{Cy}^{2}+\mathrm{D}=0 $$
  • 解为:

$$
x=\frac{-B y \pm \sqrt{(B y)^{2}-4 \cdot A \cdot\left(C y^{2}+D\right)}}{2 A}
$$

  • $x$ 仅有1个解等价于:
$$ \begin{array}{c} (B y)^{2}-4 \cdot A \cdot\left(C y^{2}+D\right)=0 \\ y^2=\frac {4AD} {B^2-4AC} \end{array} $$
  • 与上一方法殊途同归:

$$
height=|\sqrt{\frac{4AD}{B^2-4AC}}|
$$

python 实现

来自知乎大佬

  • 函数输入为:
参数 含义
major_radius 主轴的半径
minor_radius 短轴半径
angle (顺时针)旋转角度
center_x 中心点横坐标
center_y 中心点纵坐标
  • 首先是根据前三个函数输入得到椭圆参数方程的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
'''
根据椭圆的主轴和次轴半径以及旋转角度(默认圆心在原点),得到椭圆参数方程的参数,
椭圆参数方程为:
A * x^2 + B * x * y + C * y^2 + D = 0
'''
def get_ellipse_param(major_radius, minor_radius, angle):
a, b = major_radius, minor_radius
sin_theta = np.sin(-angle)
cos_theta = np.cos(-angle)
A = a**2 * sin_theta**2 + b**2 * cos_theta**2
B = 2 * (a**2 - b**2) * sin_theta * cos_theta
C = a**2 * cos_theta**2 + b**2 * sin_theta**2
F = -a**2 * b**2
return A, B, C, D
  • 根据参数计算矩形框的值两个点的坐标:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'''
根据椭圆参数方程的参数,得到椭圆的外接矩形top-left和right-bottom坐标。
'''
def calculate_rectangle(A, B, C, D):
'''
椭圆上下外接点的纵坐标值
'''
y = np.sqrt(4*A*D / (B**2 - 4*A*C))
y1, y2 = -np.abs(y), np.abs(y)

'''
椭圆左右外接点的横坐标值
'''
x = np.sqrt(4*C*D / (B**2 - 4*C*A))
x1, x2 = -np.abs(x), np.abs(x)

return (x1, y1), (x2, y2)
  • 综合两个函数
1
2
3
4
5
6
7
'''
按照数据集接口返回矩形框
'''
def get_rectangle(major_radius, minor_radius, angle, center_x, center_y):
A, B, C, D = get_ellipse_param(major_radius, minor_radius, angle)
p1, p2 = calculate_rectangle(A, B, C, D)
return (center_x+p1[0], center_y+p1[1]), (center_x+p2[0], center_y+p2[1])

mtutils 库

  • python 中的 OpenCV 有输出斜椭圆的结构 ellipse
  • 在库 mtutils 中的 ellipse2bbox 可以直接将该椭圆作为输入,得到外接矩形
1
2
from mtutils import ellipse2bbox
bbox = ellipse2bbox(ellipse)

参考资料


获取一般椭圆外接矩形
https://www.zywvvd.com/notes/study/math/ob-ellipse-close-rec/ob-ellipse-close-rec/
作者
Yiwei Zhang
发布于
2022年2月18日
许可协议