获取一般椭圆外接矩形

2022-08-06 17:29:20 浏览数 (1)

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

问题描述

如上述动图所示,给定一个一般但中心为原点的椭圆,长半轴 a, 短半轴 b,角度 alpha

  • 需要求得在给定 a,b,alpha 下椭圆的外接矩形,可以将问题简化为在给定数据下求图中 height 变量。

一般化方程

  • 正椭圆方程为:

  • 当顺时针旋转角度 alpha 后,x,y 值可以表示为:

  • 带入正椭圆方程得到中心在原点的一般椭圆方程:
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
  • 展开得到:

  • 对此我们将该种类的椭圆方程一般化,有方程:

  • 对应得到:

  • 即我们讨论的椭圆方程总可以化成一般方程的形式,之后我们均在一般化方程基础上讨论解法

方法一

求解思路
  • 需要解得 yx 导数为 0 的点,取绝对值即可
解决方法
  • 我们的目的是寻找 frac{partial y}{partial x} 为 0 的点,那么直接对 x 求偏导:

  • frac{partial y}{partial x} = 0,有:
2Ax By=0
  • 不考虑 A = 0 的情况下:
x = - frac{B}{2A}
  • 带入一般方程:

  • 得到高度:
height=|sqrt{frac{4AD}{B^2-4AC}}|

方法二

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

  • 解为:
x=frac{-B y pm sqrt{(B y)^{2}-4 cdot A cdotleft(C y^{2} Dright)}}{2 A}
  • x 仅有1个解等价于:

  • 与上一方法殊途同归:
height=|sqrt{frac{4AD}{B^2-4AC}}|

python 实现

来自知乎大佬

  • 函数输入为:

参数

含义

major_radius

主轴的半径

minor_radius

短轴半径

angle

(顺时针)旋转角度

center_x

中心点横坐标

center_y

中心点纵坐标

  • 首先是根据前三个函数输入得到椭圆参数方程的参数
代码语言:javascript复制
'''
根据椭圆的主轴和次轴半径以及旋转角度(默认圆心在原点),得到椭圆参数方程的参数,
椭圆参数方程为:
    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

  • 根据参数计算矩形框的值两个点的坐标:
代码语言:javascript复制
'''
根据椭圆参数方程的参数,得到椭圆的外接矩形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)

  • 综合两个函数
代码语言:javascript复制
'''
按照数据集接口返回矩形框
'''
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 可以直接将该椭圆作为输入,得到外接矩形
代码语言:javascript复制
from mtutils import ellipse2bbox
bbox = ellipse2bbox(ellipse)

参考资料

  • https://zhuanlan.zhihu.com/p/82184417
  • https://bbs.csdn.net/topics/390834307

0 人点赞