I am trying to find the point which intersects with the line and the ellipse. I can find the point manually as seen in the code but how can I find it automatically. Also when the red point is inside the ellipse the green point should also be projected on to the ellipse when extending the line. How can I solve this? Code examples are appreciated! Thanks!
import cv2
import numpy as np
# Parameters
ellipse_center = np.array([238, 239])
ellipse_axes = np.array([150, 100]) # Semi-major and semi-minor axes
ellipse_angle = np.radians(70) # Angle of rotation (in radians)
line_point1 = ellipse_center # Point on the line
line_point2 = np.array([341, 125]) # Another point on the line (moving point)
# Initialize OpenCV window
window_name = "Projecting Point on Rotated Ellipse"
cv2.namedWindow(window_name)
canvas = np.zeros((400, 400, 3), dtype=np.uint8)
while True:
# Clear canvas
canvas.fill(0)
# Draw the rotated ellipse
cv2.ellipse(canvas, tuple(ellipse_center), tuple(ellipse_axes), np.degrees(ellipse_angle), 0, 360, (255, 255, 255), 2)
# Draw the moving point
cv2.circle(canvas, (int(line_point2[0]), int(line_point2[1])), 5, (0, 0, 255), -1)
# Draw the center point of the ellipse
cv2.circle(canvas, tuple(ellipse_center), 5, (0, 255, 255), -1)
# Draw the line between moving point and the center of the ellipse
cv2.line(canvas, (int(line_point2[0]), int(line_point2[1])), tuple(ellipse_center), (0, 0, 255), 1)
intersection_points = (310, 159) # <- How to find this?
cv2.circle(canvas, intersection_points, 5, (0, 255, 0), -1)
# 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()
When using the ellipse equation and the line equation I get this:
import cv2
import numpy as np
from scipy.optimize import fsolve
# Parameters
ellipse_center = np.array([238, 239])
ellipse_axes = np.array([150, 100]) # Semi-major and semi-minor axes
ellipse_angle = np.radians(70) # Angle of rotation (in radians)
line_point1 = ellipse_center # Point on the line
line_point2 = np.array([341, 125]) # Another point on the line (moving point)
# Ellipse equation: (x - h)^2 / a^2 + (y - k)^2 / b^2 = 1, where (h, k) is the center of the ellipse
def ellipse_eq(params):
x, y = params
h, k = ellipse_center
a, b = ellipse_axes
return ((x - h) ** 2 / a ** 2) + ((y - k) ** 2 / b ** 2) - 1
# Line equation: y = mx + c
def line_eq(x):
m = (line_point2[1] - line_point1[1]) / (line_point2[0] - line_point1[0])
c = line_point1[1] - m * line_point1[0]
return m * x + c
# Intersection of the ellipse and the line
def intersection_point():
x_intercept = fsolve(lambda x: ellipse_eq([x, line_eq(x)]), line_point2[0])
y_intercept = line_eq(x_intercept)
return x_intercept[0], y_intercept[0]
# Initialize OpenCV window
window_name = "Projecting Point on Rotated Ellipse"
cv2.namedWindow(window_name)
canvas = np.zeros((400, 400, 3), dtype=np.uint8)
while True:
# Clear canvas
canvas.fill(0)
# Draw the rotated ellipse
cv2.ellipse(canvas, tuple(ellipse_center), tuple(ellipse_axes), np.degrees(ellipse_angle), 0, 360, (255, 255, 255), 2)
# Draw the moving point
cv2.circle(canvas, (int(line_point2[0]), int(line_point2[1])), 5, (0, 0, 255), -1)
# Draw the center point of the ellipse
cv2.circle(canvas, tuple(ellipse_center), 5, (0, 255, 255), -1)
# Draw the line between moving point and the center of the ellipse
cv2.line(canvas, (int(line_point2[0]), int(line_point2[1])), tuple(ellipse_center), (0, 0, 255), 1)
# Find and draw the intersection point
intersection_points = intersection_point()
cv2.circle(canvas, (int(intersection_points[0]), int(intersection_points[1])), 5, (0, 255, 0), -1)
# 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()
Which does not solve my problem. What am I doing wrong here?
EDIT: Using MBo's approach with the code:
import cv2
import numpy as np
# Parameters
ellipse_center = np.array([238, 239])
ellipse_axes = np.array([150, 100]) # Semi-major and semi-minor axes
ellipse_angle = np.radians(70) # Angle of rotation (in radians)
line_point1 = ellipse_center # Point on the line (ellipse center)
line_point2 = np.array([341, 125]) # Another point on the line (moving point)
# Initialize OpenCV window
window_name = "Projecting Point on Rotated Ellipse"
cv2.namedWindow(window_name)
canvas = np.zeros((400, 400, 3), dtype=np.uint8)
while True:
# Clear canvas
canvas.fill(0)
# Draw the rotated ellipse
cv2.ellipse(canvas, tuple(ellipse_center), tuple(ellipse_axes), np.degrees(ellipse_angle), 0, 360, (255, 255, 255), 2)
# Draw the moving point
cv2.circle(canvas, (int(line_point2[0]), int(line_point2[1])), 5, (0, 0, 255), -1)
# Draw the center point of the ellipse
cv2.circle(canvas, tuple(ellipse_center), 5, (0, 255, 255), -1)
# Draw the line between moving point and the center of the ellipse
cv2.line(canvas, (int(line_point2[0]), int(line_point2[1])), tuple(ellipse_center), (0, 0, 255), 1)
# Calculate the intersection point
t = np.arctan2(line_point2[1] - ellipse_center[1], line_point2[0] - ellipse_center[0]) - np.arctan2(np.sin(ellipse_angle) * ellipse_axes[0], np.cos(ellipse_angle) * ellipse_axes[1])
x_intersection = ellipse_center[0] + ellipse_axes[0] * np.cos(t) * np.cos(ellipse_angle) - ellipse_axes[1] * np.sin(t) * np.sin(ellipse_angle)
y_intersection = ellipse_center[1] + ellipse_axes[0] * np.cos(t) * np.sin(ellipse_angle) + ellipse_axes[1] * np.sin(t) * np.cos(ellipse_angle)
intersection_point = (int(x_intersection), int(y_intersection))
# Draw the intersection point
cv2.circle(canvas, intersection_point, 5, (0, 255, 0), -1)
# 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()
Gets me:
First rotate the line back by ellipse_angle so that it corresponds to the unrotated ellipse.
Substitute (for y) the equation of the line (y=mx+c) into the equation of the ellipse (x-h)2/a2+(y-k)2/b2=1. This will give a quadratic in x which can be solved by the usual quadratic-equation formula.
The quadratic is Ax2+Bx+C=0, where, on rearrangement,
A=a2m2+b2
B=2a2m(c-k)-2b2h
C=b2h2+a2(c-k)2-a2b2
Solve for x and get y from the equation of the line. Be careful to get the correct quadratic root.
Then rotate the intersection point back again by ellipse_angle.
As with any quadratic equation you can run into occasions with a single root (line just touches the ellipse) and no roots (line misses the ellipse).
Code below - I have indicated the modified section of your code.
import cv2
import numpy as np
# Parameters
ellipse_center = np.array([238, 239])
ellipse_axes = np.array([150, 100]) # Semi-major and semi-minor axes
ellipse_angle = np.radians(70) # Angle of rotation (in radians)
line_point1 = ellipse_center # Point on the line (ellipse center)
line_point2 = np.array([341, 125]) # Another point on the line (moving point)
# Initialize OpenCV window
window_name = "Projecting Point on Rotated Ellipse"
cv2.namedWindow(window_name)
canvas = np.zeros((400, 400, 3), dtype=np.uint8)
while True:
# Clear canvas
canvas.fill(0)
# Draw the rotated ellipse
cv2.ellipse(canvas, tuple(ellipse_center), tuple(ellipse_axes), np.degrees(ellipse_angle), 0, 360, (255, 255, 255), 2)
# Draw the moving point
cv2.circle(canvas, (int(line_point2[0]), int(line_point2[1])), 5, (0, 0, 255), -1)
# Draw the center point of the ellipse
cv2.circle(canvas, tuple(ellipse_center), 5, (0, 255, 255), -1)
# Draw the line between moving point and the center of the ellipse
cv2.line(canvas, (int(line_point2[0]), int(line_point2[1])), tuple(ellipse_center), (0, 0, 255), 1)
############## MODIFIED SECTION ############
# Rotate the line back to an unrotated ellipse
theta = np.arctan2( line_point2[1] - line_point1[1], line_point2[0] - line_point1[0] ) - ellipse_angle
m = np.tan( theta )
c = line_point1[1] - m * line_point1[0]
a, b, h, k = ellipse_axes[0], ellipse_axes[1], ellipse_center[0], ellipse_center[1]
A = ( a * m ) ** 2 + b ** 2
B = 2 * ( a ** 2 * m * ( c - k ) - b ** 2 * h )
C = ( b * h ) ** 2 + ( a * ( c - k ) ) ** 2 - ( a * b ) ** 2
discriminant = B ** 2 - 4 * A * C
# Intersection of back-rotated line with back-rotated ellipse (need correct root)
theta = np.mod( theta, 2 * np.pi )
x1 = ( -B + np.sqrt( discriminant ) ) / ( 2 * A ) # quadratic solution (larger root)
if theta > 0.5 * np.pi and theta < 1.5 * np.pi: x1 = -B/A - x1 # need other root
y1 = m * x1 + c
# Rotate the line forward again
x1, y1 = h + ( x1 - h ) * np.cos( ellipse_angle ) - ( y1 - k ) * np.sin( ellipse_angle ), k + ( x1 - h ) * np.sin( ellipse_angle ) + ( y1 - k ) * np.cos( ellipse_angle )
intersection_point = (int(x1), int(y1))
############## END OF MODIFIED SECTION ############
# Draw the intersection point
cv2.circle(canvas, intersection_point, 5, (0, 255, 0), -1)
# 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()