本文最后更新于:2024年5月7日 下午
正椭圆的外接矩形可以直接根据椭圆中心以及长短半轴确定,但一般的斜椭圆就要复杂一些,本文记录计算斜椭圆外接矩形的过程。
问题描述
- 如上述动图所示,给定一个一般但中心为原点的椭圆,长半轴 $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
$$
$$
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|$
解决方法
$$
\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}
$$
$$
\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/