Projection of a 3D circle onto a 2D camera image

Question:

Asked this on math.stackexchange, but no responses so trying here, hopefully the computer vision people are more able to help out.

Assume that I have a 3D circle with a center at (c1, c2, c3) in the circle coordinate frame C. The radius of the circle is r, and there is a unit vector (v1, v2, v3) (also in coordinate frame C) normal to the plane of the circle at the center point.

I have a pinhole camera located at point (k1, k2, k3) in the camera coordinate frame K. I have a known camera-to-circle coordinate frame transformation matrix kTc that transforms any point in C to coordinate frame K so that point_k = np.dot(kTc, point_c) where point_k is a point in the K frame coordinates and point_c is a point in the C frame coordinates. The camera has a known intrinsic camera matrix I.

How do I project the 3D circle onto the image plane of the camera?

Ideally would like to do this in python.

Asked By: BeginnersMindTruly

||

Answers:

I think you want to use the scipy module in conjunction with numpy. The problem you are solving is the transformation of the sphere into a 2D plane and then transforming that plane (by rotating and shifting) to the camera plane (whichever that is).

First of all, some information is missing here about the camera plane (phi and/or theta wrt origin) or the equation of the plane and about the sphere (the equation of the sphere in radial coordinates). Transformations would be a bit tough without equations, angles, and plane(s) information. I agree you have given the information in variables, but it would be easy to have equations in handy OR the first step would be making equations (doing it by hand or using mathematica etc.)

I will be using this documentation to attempt to answer your question – https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html

Following is a pseudo code

do not attempt to execute it as is

import numpy as np
from scipy.spatial.transform import Rotation

# Define the center of the circle in the circle coordinate frame
c = np.array([c1, c2, c3])

# Define the normal vector of the circle in the circle coordinate frame
n = np.array([v1, v2, v3])

# Define the camera center in the camera coordinate frame
k = np.array([k1, k2, k3])

# Define the intrinsic camera matrix
I = np.array(..., dtype=np.float32)

# Define the rotation matrix part of kTc
R = np.array(..., dtype=np.float32)

# Define the translation vector part of kTc
t = np.array(..., dtype=np.float32)

# Convert R to a scipy Rotation object
R_obj = Rotation.from_dcm(R)

# Transform the center of the circle to the camera coordinate frame
c_k = R_obj.apply(c) + t

# Project the center of the circle onto the image plane
c_p = I @ c_k

# Normalize the center projection by dividing by its third component
c_p = c_p[:2] / c_p[2]

# Transform the normal vector to the camera coordinate frame
n_k = R_obj.apply(n)

# Project the normal vector onto the image plane
n_p = I[:2, :3] @ n_k

# Normalize the normal projection by dividing by its third component
n_p = n_p / n_p[2]

# Calculate the equation of the circle in the image plane
r_squared = r**2 - np.sum(n_p[:2]**2) / n_p[2]**2

And here’s an explanation of the equations used in the code:

c = np.array([c1, c2, c3]): The center of the circle in the circle coordinate frame is represented by the vector c = [c1, c2, c3].
n = np.array([v1, v2, v3]): The normal vector of the circle in the circle coordinate frame is represented by the vector n = [v1, v2, v3].
k = np.array([k1, k2, k3]): The camera center in the camera coordinate frame is represented by the vector k = [k1, k2, k3].
I = np.array(..., dtype=np.float32): The intrinsic camera matrix is represented by the 2D array I.
R = np.array(..., dtype=np.float32): The rotation matrix part of the kTc transformation matrix is represented by the 3x3 array R.
t = np.array(..., dtype=np.float32): The translation vector part

Answer algorithm:

To project the 3D circle onto the image plane of the camera, you’ll need to follow these steps:

  1. Transform the 3D circle from the circle coordinate frame (C) to the camera coordinate frame (K) using the transformation matrix kTc. The transformed circle’s center will be given by:

    center_k = np.dot(kTc, [c1, c2, c3, 1])

  2. Project the transformed circle’s center onto the image plane of the camera using the intrinsic camera matrix I. The projection of the center will be given by:

    center_p = np.dot(I, center_k)

  3. Transform the normal vector from the circle coordinate frame (C) to the camera coordinate frame (K) using the transformation matrix kTc. The transformed normal vector will be given by:

    normal_k = np.dot(kTc[:3, :3], [v1, v2, v3])

  4. Project the transformed normal vector onto the image plane of the camera using the intrinsic camera matrix I. The projection of the normal vector will be given by:

    normal_p = np.dot(I[:2, :3], normal_k)

  5. Using the center and normal projections, you can now find the equation of the 2D circle in the image plane of the camera. The equation of the circle in the image plane will be given by:

    (x – center_p[0]/center_p[2])^2 + (y – center_p[1]/center_p[2])^2 = r^2 – (normal_p[0]^2 + normal_p[1]^2)/(normal_p[2]^2)

where (x, y) are the image plane coordinates of the projected circle.

Note that you’ll need to normalize the center and normal projections by dividing each by their respective third components (center_p[2] and normal_p[2]) to get their actual image plane coordinates.

Answered By: Paritosh Kulkarni