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

OpenCV中如何求解椭圆与直线的交点?

求解旋转椭圆与直线的交点

问题描述

我需要求解椭圆与直线的交点。已通过fitEllipse函数从图像中提取椭圆,得到对应的RotatedRect参数。现在有若干条理论上会与椭圆相交的直线,希望计算它们的交点。

原始图像

原始图

目标交点示意

目标交点示意

测试代码

import cv2
import numpy as np

ellipse_center = np.array([439, 326])
ellipse_axes = np.array([int(283/2), int(565/2)])  
ellipse_angle = np.radians(91)  

line_point1 = np.array([583, 450])  
line_point2 = np.array([292, 115])  

window_name = "Demo"
cv2.namedWindow(window_name)
canvas = np.zeros((600, 800, 3), dtype=np.uint8)

while True:
    # Clear canvas
    canvas.fill(0)

    cv2.ellipse(canvas, tuple(ellipse_center), tuple(ellipse_axes), np.degrees(ellipse_angle), 0, 360, (0, 0, 255), 2)
    cv2.line(canvas, (293,115), (584,450), (0,0,255), 2)
    cv2.line(canvas, (70,290), (404,279), (0,0,255), 2)
    cv2.line(canvas, (59,353), (411,285), (0,0,255), 2)
    cv2.line(canvas, (463,272), (755,220), (0,0,255), 2)


    # Show canvas
    cv2.imshow(window_name, canvas)

    # Exit if 'q' is pressed
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Close OpenCV window
cv2.destroyAllWindows()

解决方案思路

计算旋转椭圆与直线的交点,核心是通过坐标变换将旋转椭圆转为标准椭圆,代入直线方程求解后再转换回原坐标系:

  1. 坐标变换:先将所有点平移至椭圆中心为原点,再逆时针旋转抵消椭圆的旋转角度,得到椭圆局部坐标系
  2. 标准椭圆方程:局部坐标系中椭圆方程为(x'/a)² + (y'/b)² = 1,其中a、b为椭圆半长轴、半短轴
  3. 直线方程代入:将直线转换到局部坐标系,代入椭圆方程得到关于参数t的二次方程,求解t值
  4. 逆变换回原坐标系:将局部坐标系的交点通过旋转、平移转换回原图像坐标系

实现代码

import cv2
import numpy as np

def rotate_point(point, angle):
    """将点绕原点旋转指定弧度角度"""
    cos_theta = np.cos(angle)
    sin_theta = np.sin(angle)
    rot_matrix = np.array([[cos_theta, sin_theta], [-sin_theta, cos_theta]])
    return np.dot(rot_matrix, point)

def find_ellipse_line_intersection(ellipse_center, ellipse_axes, ellipse_angle, line_p1, line_p2):
    a, b = ellipse_axes[0], ellipse_axes[1]
    theta = ellipse_angle

    # 1. 将直线端点转换到椭圆局部坐标系(平移+旋转)
    p1_local = rotate_point(line_p1 - ellipse_center, -theta)
    p2_local = rotate_point(line_p2 - ellipse_center, -theta)

    # 2. 构建直线参数方程
    dx = p2_local[0] - p1_local[0]
    dy = p2_local[1] - p1_local[1]
    x1, y1 = p1_local[0], p1_local[1]

    # 3. 代入标准椭圆方程,整理为二次方程At² + Bt + C = 0
    A = (dx**2)/(a**2) + (dy**2)/(b**2)
    B = 2*(dx*x1)/(a**2) + 2*(dy*y1)/(b**2)
    C = (x1**2)/(a**2) + (y1**2)/(b**2) - 1

    # 4. 求解二次方程
    discriminant = B**2 - 4*A*C
    intersections = []
    if discriminant >= 0:
        sqrt_d = np.sqrt(discriminant)
        t1 = (-B + sqrt_d) / (2*A)
        t2 = (-B - sqrt_d) / (2*A)

        # 5. 将交点转换回原坐标系
        for t in [t1, t2]:
            x_local = x1 + t*dx
            y_local = y1 + t*dy
            p_rotated = rotate_point(np.array([x_local, y_local]), theta)
            p_original = p_rotated + ellipse_center
            intersections.append(p_original)
    
    return np.array(intersections, dtype=np.int32)

# 椭圆参数
ellipse_center = np.array([439, 326])
ellipse_axes = np.array([int(283/2), int(565/2)])  
ellipse_angle = np.radians(91)  

# 所有直线端点集合
lines = [
    [(293,115), (584,450)],
    [(70,290), (404,279)],
    [(59,353), (411,285)],
    [(463,272), (755,220)]
]

window_name = "Demo"
cv2.namedWindow(window_name)
canvas = np.zeros((600, 800, 3), dtype=np.uint8)

while True:
    canvas.fill(0)

    # 绘制椭圆和直线
    cv2.ellipse(canvas, tuple(ellipse_center), tuple(ellipse_axes), np.degrees(ellipse_angle), 0, 360, (0, 0, 255), 2)
    for p1, p2 in lines:
        cv2.line(canvas, p1, p2, (0,0,255), 2)
        # 计算并绘制交点(绿色圆点)
        intersections = find_ellipse_line_intersection(ellipse_center, ellipse_axes, ellipse_angle, np.array(p1), np.array(p2))
        for pt in intersections:
            cv2.circle(canvas, tuple(pt), 3, (0,255,0), -1)

    cv2.imshow(window_name, canvas)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()

代码说明

  • rotate_point:实现点的旋转变换
  • find_ellipse_line_intersection:核心计算函数,完成坐标变换、方程求解与逆变换
  • 主循环中对每条直线计算交点,并以绿色实心圆点标注在画布上

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:34:57