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

Assume that I have a 3D circle with a center at $$(c_1, c_2, c_3)$$ in the circle coordinate frame $$C$$. The radius of the circle is $$r$$, and there is a unit vector $$(v_1, v_2, v_3)$$ (also in coordinate frame $$C$$) normal to the plane of the circle at the center point.

I have a pinhole camera located at point $$(k_1, k_2, k_3)$$ in the camera coordinate frame $$K$$. I have a known camera-to-circle transformation matrix $$T_{C}^{K}$$ that transforms any point in $$C$$ to coordinate frame $$K$$. The camera has a known intrinsic camera matrix $$N$$.

How do I project the 3D circle onto the image plane of the camera in order to find the parameters of the resulting ellipse / line segment / curve in the image plane.

• Choose another notation than $I$ for the intrinsic camera matrix, since $I$ usually denotes the identity matrix. Feb 7 at 8:05
• Are you asking for the parameters of the resulting ellipse? (I believe you can get a parabola as well) Feb 8 at 1:50
• Thanks @AlexK. Yes, clarified. Would like the parameters of the projected curve / line segment / point in the image plane. Feb 8 at 18:55
• Thanks @ChristopheLeuridan edited post. Feb 8 at 18:55

Coordinate frames:

Let $$\vec{p}_{c}=(x_c, \ y_c, \ z_c)$$ be a point in the coordinate frame $$C$$ and $$\vec{p}_{k}=(x_k, \ y_k, \ z_k)$$ the same point in the coordinate frame $$K$$. The way we transform one point to another is by a $$3 \times 3$$ matrix $$T_{ck}$$ such

$$\vec{p}_{k} = T_{ck} \cdot \vec{p}_{c} + \vec{s}_{k}$$

The vector $$\vec{s}_{k}$$ is position of the origin $$O_{c}$$ on $$K$$.

The same happens for the camera: There's a transformation matrix $$T_{kn}$$ to transform a point $$\vec{p}_{k} \in K$$ to the point $$\vec{p}_{n} \in N$$

$$\vec{p}_{n} = T_{kn} \cdot \vec{p}_{k} + \vec{h}_{n}$$

For the camera, the origin $$O_{k}$$ is represented at the position $$\vec{h}_{n}$$.

Therefore, transforming any point $$\vec{p}_{c}$$ to a point $$\vec{p}_{n}$$ is made by

$$\vec{p}_{n} = \vec{h}_{n} + T_{kn} \cdot \vec{s}_{k} + T_{kn} T_{ck} \cdot \vec{p}_{c}$$

Lose information:

In the coordinate frame $$K$$, there's a point $$\vec{k}_{k} = \left(k_1, \ k_2, \ k_3\right)$$, which we call the pin-hole. The pin-hole camera always loses information. Let $$\vec{n}_{k}$$ be a unit vector perpendicular to the plane of the camera.

All the points that lie on the line $$\vec{p}_{k} = \vec{k}_{k} + t \cdot \vec{n}_{k}$$ are the same for the camera. So

\begin{align}\vec{p}_{n} & = \vec{h}_{n} + T_{kn} \cdot \vec{p}_{k} \\ & = \vec{h}_{n} + T_{kn} \cdot \left(\vec{k}_{k} + t \cdot \vec{n}_{k} \right) \\ & = \vec{h}_{n} + T_{kn} \cdot \vec{k}_{k} + t \cdot T_{kn} \cdot \vec{n}_{k}\end{align}

$$\boxed{T_{kn} \cdot \vec{n}_{k} = \vec{0}}$$

Normally that happens cause $$T_{nk}$$ normally is a transformation from $$\mathbb{R}^{3}$$ into $$\mathbb{R}^{2}$$:

$$T_{nk} = \begin{bmatrix}\vec{a}_{k} \\ \vec{b}_{k} \end{bmatrix} = \begin{bmatrix}a_1 & a_2 & a_ 3 \\ b_1 & b_2 & b_3 \end{bmatrix}$$ $$\langle \vec{a}_{k}, \vec{n}_{k}\rangle = 0 \ \ \ \ \ \ \text{and} \ \ \ \ \ \ \ \ \langle \vec{b}_{k}, \vec{n}_{k}\rangle = 0$$

Therefore, we can transform a point $$\vec{p}_{k}$$ into $$\vec{q}_{k}$$ by taking out the projection to the line at first.

$$\vec{q}_{k} = \underbrace{\dfrac{\langle \vec{a}_{k}, \ \vec{p}_{k}\rangle}{\langle \vec{a}_k, \ \vec{a}_{k} \rangle }}_{\alpha} \cdot \vec{a}_{k} + \underbrace{\dfrac{\langle \vec{b}_{k}, \ \vec{p}_{k}\rangle}{\langle \vec{b}_k, \ \vec{b}_{k} \rangle }}_{\beta} \cdot \vec{b}_{k}$$

And for $$\vec{q}_{n}$$ we get

$$\vec{q}_{n} = \vec{h}_{n} + T_{kn} \cdot \left(\alpha \cdot \vec{a}_{k} + \beta \cdot \vec{b}_{k}\right)$$

$$\begin{bmatrix}q_{n1} \\ q_{n2}\end{bmatrix} = \begin{bmatrix}h_{n1} \\ h_{n2}\end{bmatrix} + \underbrace{\begin{bmatrix}1 & \dfrac{\langle \vec{b}_{k}, \ \vec{a}_{k}\rangle}{\langle \vec{b}_k, \ \vec{b}_{k} \rangle } \\ \dfrac{\langle \vec{a}_{k}, \ \vec{b}_{k}\rangle}{\langle \vec{a}_k, \ \vec{a}_{k} \rangle } & 1\end{bmatrix}}_{H_k}\begin{bmatrix}\langle \vec{a}_{k}, \ \vec{p}_{k}\rangle\\ \langle \vec{b}_{k}, \ \vec{p}_{k}\rangle\end{bmatrix}$$

The circle:

There's a circle which center is given by $$\vec{c}_{c} = (c_1, \ c_2, \ c_3)$$ and has radius $$r$$. Its perpendicular vector (to the plane which contains the circle) is $$\vec{v}_{c} = (v_1, \ v_2, \ v_3)$$.

Let $$\vec{g}_c$$ be a point in the circle, then

$$\|\vec{g}_{c} - \vec{c}_{c}\| = r\label{1}\tag{1}$$ $$\left(\vec{g}_{c} - \vec{c}_{c}\right) \times \vec{v}_{c} = \vec{0}\label{2}\tag{2}$$

Now, let's call $$\vec{u}_c$$ and $$\vec{w}_c$$ two unit vectors that are parallel to the plane of the circle, such

$$\vec{u}_c \perp \vec{w}_c \perp \vec{v}_c \perp \vec{u}_c$$ $$\|\vec{u}_c\| = 1 \ \ \ \ \ \ \ \ \ \|\vec{w}_c\| = 1$$

From \eqref{1} and \eqref{2}

$$\vec{g}_{c} = \vec{c}_c + \vec{u}_{c} \cdot r\cos \theta + \vec{w}_c \cdot r\sin \theta$$

Transforming to $$N$$:

\begin{align}\vec{g}_{n} & = \vec{h}_{n} + T_{kn} \cdot \vec{s}_{k} + T_{kn} T_{ck} \cdot \vec{g}_{c} \\ & = \vec{h}_{n} + T_{kn} \cdot \vec{s}_{k} + T_{kn} T_{ck} \cdot \vec{c}_{c} + r \cos \theta \cdot T_{kn} T_{ck} \cdot \vec{u}_{c} + r \sin \theta \cdot T_{kn} T_{ck} \cdot \vec{w}_{c}\end{align}

Renaming

$$\vec{g}_{n} = \vec{f}_{n} + r \cos \theta \cdot \vec{u}_{n} + r \sin \theta \cdot \vec{w}_{n}$$

With

\begin{align*}\vec{f}_{n} & = \vec{h}_{n} + T_{kn} \cdot \left( \vec{s}_{k} + T_{ck} \cdot \vec{c}_{c}\right) \\ \vec{u}_{n} & = T_{kn} T_{ck} \cdot \vec{u}_{c} \\ \vec{w}_{n} & = T_{kn} T_{ck} \cdot \vec{w}_{c} \end{align*}

Then you will get an ellipse of center $$\vec{f}_n$$ and axis $$\vec{u}_n$$ and $$\vec{w}_{n}$$. If one of this two vectors are zero, then you will get a line.

There's a python code below to represent a projection from a 3D space to a 2D space (of camera) using the coordinates. The symbol @ represents matrix multiplication.

import numpy as np
from matplotlib import pyplot as plt
Tck = np.array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
Tkn = np.array([[1, 0, 1],
[0, 1, 0]])
cc = [0, 0, 1]
uc = [1, 0, 0]
wc = [0, 1, 1]
sk = [0, 1, 0]
hn = [0, 1]
r = 1
uc /= np.linalg.norm(uc)
wc /= np.linalg.norm(wc)

cn = Tkn @ Tck @ cc
sn = Tkn @ sk
fn = hn + sn + cn
un = Tkn @ Tck @ uc
wn = Tkn @ Tck @ wc

theta = np.linspace(0, 2*np.pi, 129)
gnx = fn[0] + r * np.cos(theta) * un[0] + r * np.sin(theta) * wn[0]
gny = fn[1] + r * np.cos(theta) * un[1] + r * np.sin(theta) * wn[1]

plt.plot(gnx, gny, label="circle on C")
plt.scatter(cn[0], cn[1], label="origin of C")
plt.scatter(sn[0], sn[1], label="origin of K")
plt.axis("equal")
plt.legend()
plt.show()