You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已知椭圆两焦点及常数d时如何在图像上绘制椭圆

你可以通过椭圆的几何定义推导所需参数,完全可以在Pillow等直接操作图像的库中完成绘制,不需要依赖matplotlib,具体实现分两种方案:

方案1:计算边界框调用原生椭圆接口

多数绘图库的椭圆接口支持传入边界框+旋转角度参数,你可以按以下步骤计算参数:

  • 先明确已知量:两个焦点坐标记为F1=(x1,y1)、F2=(x2,y2),椭圆上任意点到两焦点的距离和为常数d,注意d必须大于两焦点的直线距离,否则无法构成有效椭圆
  • 计算椭圆基础几何参数
    • 椭圆中心为两焦点中点:center_x = (x1+x2)/2,center_y = (y1+y2)/2
    • 焦点到中心的距离:c = sqrt((x2-x1)**2 + (y2-y1)**2)/2
    • 椭圆长半轴:a = d/2(长轴长度等于d)
    • 椭圆短半轴:由椭圆几何关系a² = b² + c²推导得b = sqrt(a**2 - c**2)
    • 椭圆长轴旋转角度:即两焦点连线与x轴的夹角,theta = atan2(y2-y1, x2-x1)(弧度制)
  • 计算轴对齐外接边界框
    旋转椭圆的外接矩形半宽、半高计算公式如下:
    half_width = sqrt( (a * cos(theta))**2 + (b * sin(theta))**2 )
    half_height = sqrt( (a * sin(theta))**2 + (b * cos(theta))**2 )
    
    对应Pillow等库要求的边界框坐标(左上角、右下角)为:
    bbox = (
        center_x - half_width,
        center_y - half_height,
        center_x + half_width,
        center_y + half_height
    )
    

注意:如果你用的库只支持绘制轴对齐椭圆、不支持传入旋转角度,该方案仅在两焦点处于同一水平线/竖直线时生效,旋转椭圆请使用方案2。如果库支持图层旋转,也可以先在透明图层绘制轴对齐椭圆(bbox为(center_x-a, center_y-b, center_x+a, center_y+b)),再将图层旋转对应角度后贴回原图即可。

方案2:按椭圆定义逐点生成路径绘制(兼容所有场景)

该方法不需要依赖库的椭圆旋转能力,适配所有绘图工具,生成的椭圆精度可控:

  • 以椭圆中心为原点、长轴为x'轴建立局部坐标系,从0到2π按固定步长取角度t,生成局部坐标系下的椭圆点:(a*cos(t), b*sin(t)),步长越小最终椭圆越平滑,一般取0.01弧度即可满足日常需求
  • 对每个局部坐标点做旋转变换,旋转角度为之前计算的theta:
    x_rot = x_local * cos(theta) - y_local * sin(theta)
    y_rot = x_local * sin(theta) + y_local * cos(theta)
    
  • 将旋转后的点平移到图像实际坐标系:x = x_rot + center_x,y = y_rot + center_y
  • 按顺序连接所有点形成闭合多边形,即可得到目标椭圆。

Pillow 可运行实现代码

import math
from PIL import Image, ImageDraw

def draw_ellipse_by_foci(draw, focus1, focus2, d, fill=None, outline=None, width=1):
    x1, y1 = focus1
    x2, y2 = focus2
    # 校验参数合法性
    focal_distance = math.hypot(x2 - x1, y2 - y1)
    if d < focal_distance:
        raise ValueError("参数错误:d必须大于两焦点之间的直线距离")
    # 计算基础参数
    cx, cy = (x1 + x2)/2, (y1 + y2)/2
    a = d / 2
    c = focal_distance / 2
    b = math.sqrt(a**2 - c**2)
    theta = math.atan2(y2 - y1, x2 - x1)
    cos_t, sin_t = math.cos(theta), math.sin(theta)
    # 生成椭圆点集
    points = []
    step = 0.01  # 角度步长,越小椭圆越平滑
    for i in range(int(2 * math.pi / step) + 1):
        t = i * step
        x_local = a * math.cos(t)
        y_local = b * math.sin(t)
        # 坐标变换:旋转+平移
        x = x_local * cos_t - y_local * sin_t + cx
        y = x_local * sin_t + y_local * cos_t + cy
        points.append((x, y))
    # 绘制闭合多边形
    draw.polygon(points, fill=fill, outline=outline, width=width)

# 调用示例
if __name__ == "__main__":
    img = Image.new("RGB", (600, 600), "white")
    draw = ImageDraw.Draw(img)
    # 传入两个焦点、d值绘制红色椭圆
    draw_ellipse_by_foci(draw, focus1=(200, 200), focus2=(400, 350), d=350, outline="red", width=2)
    img.save("ellipse_demo.png")

内容的提问来源于stack exchange,提问作者GameDungeon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 01:36:47