Inputs:K holds the camera intrinsics: focal lengths fx=fy=1000 pixels on the diagonal and the principal point (cx,cy)=(320,240) in the third column. The point (X,Y,Z)=(0.1,0.1,1) is 1 unit in front of the lens.
Multiply by K:x′=1000(0.1)+0(0.1)+320(1)=420, y′=0(0.1)+1000(0.1)+240(1)=340, z′=0(0.1)+0(0.1)+1(1)=1.
Divide by depth: the bottom row of K is (0,0,1), so z′ is the depth Z=1, giving u=420/1=420 and v=340/1=340.
Output:[420.0, 340.0]: pixel column and row, rounded to 4 decimal places. Equivalently u=fxX/Z+cx: the point lands 100 pixels right of and 100 below the principal point.
Notice: perspective means pushing the same point to Z=2 halves that offset, giving (370,290). Any point on the axis, (0,0,Z), projects to (320,240) at every depth.
Constraints
K: 3x3 intrinsic matrix
point_3d: [X, Y, Z] point in camera coordinates (Z > 0)
Return [u, v] pixel coordinates rounded to 4 decimal places
To project a 3D point in camera coordinates to a 2D pixel, you apply a linear transform with the intrinsic matrix K and then normalize by the third coordinate to get (u,v).
1. Background Knowledge
In the pinhole camera model, a point in 3D camera coordinates (X,Y,Z) is mapped to the image plane by drawing a ray from the camera center through the point; where that ray intersects the image plane is the projection. Algebraically, this is modeled by a homogeneous linear transform followed by a division (perspective projection).
The intrinsic camera matrixK encodes the camera’s internal parameters:
focal lengths in pixels (fx,fy)
principal point (cx,cy)
optional skew (often 0)
A typical form is:
K=fx00sfy0cxcy1
Multiplying K by the 3D point (X,Y,Z) in camera coordinates gives a point in homogeneous image coordinates, which you convert to pixel coordinates by dividing by its third component.
2. Algorithm / Approach
General pattern to project a 3D point in camera coordinates to pixels:
Represent the 3D point as a homogeneous 3-vector (X,Y,Z).
Multiply by the camera intrinsic matrix K to get (x′,y′,z′).
Convert from homogeneous to Euclidean image coordinates:
u=x′/z′
v=y′/z′
Return (u,v) as the pixel coordinates.
This is just a matrix multiply + perspective divide.
3. Step-by-Step Strategy
Assume inputs:
Intrinsic matrix K (3×3)
3D point in camera frame (X,Y,Z)
Steps:
Matrix multiplication
import numpy as np
K =... # 3x3 intrinsic matrix
X_cam = np.array([X, Y, Z]) # shape (3,)
x_prime = K @ X_cam # shape (3,)
# x_prime = [x', y', z']
Perspective division
x_p, y_p, z_p = x_prime
u = x_p / z_p
v = y_p / z_p
Output
Return u, v as the pixel coordinates.
Optionally cast to int if you need discrete pixel indices (after any rounding).
Mathematically, you are implementing:
x′y′z′=KXYZ,u=z′x′,v=z′y′.
4. Common Pitfalls
Forgetting the division by z′: Just doing K @ X_cam gives homogeneous coordinates, not final pixel coordinates.
Using world coordinates instead of camera coordinates: This step assumes the point is already in the camera frame. If given world coordinates, you must first apply extrinsics [R∣t].
Z ≤ 0:
If Z≤0 (or z′≤0), the point is behind the camera or on the camera center; projection is invalid.
Integer rounding too early:
Do all math in floating point and only convert to int when you need to index into an image.
Row vs column convention:
Make sure your matrix multiplication is consistent (e.g., using column vectors and K@X as in the math).
5. Time & Space Complexity
For a single point:
Time complexity:
Matrix–vector multiply: constant work (3×3 with 3×1) → O(1).
Divisions and assignments: O(1).
Space complexity:
A few 3D vectors and scalars → O(1) extra space.
For N points, if you vectorize:
Time: O(N) (each point gets one 3×3 multiply + divide).