The Pinhole Camera — A Pixel Is a Ray
- 1The Pinhole Camera — A Pixel Is a Ray
- 2Where Is the Camera? — R, C and t
- 3Points at Infinity — Horizons, Vanishing Points and the Floor
- 4Finding the Camera From Known Points — P by Least Squares
- 5Lens Distortion — Bending Straight Lines Back
- 6What calibrateCamera Actually Does
- 7Epipolar Geometry — A Point Becomes a Line
- 8Triangulation — Two Rays That Almost Meet
- 9From Matches to Motion — Four Cameras, One Right Answer
- 10Stereo Depth — Rectification and Z = fB/d
- 11From Two Photos to a Point Cloud
Summary
How a camera turns a point in front of it into a pixel: similar triangles, a divide by depth, and one 3×3 matrix called K. After this read you can compute the pixel of a point by hand, say what every number in K does to the picture, and turn a pixel back into the ray it came from.
Table of Contents
- 1. A Dark Room With a Hole2
- 2. Moving the Origin to the Corner2
- 3. Add a 1, Divide by the Last Number2
- 4. What Each Number in K Does3
- 5. A Pixel Is a Ray3
- 6. Focal Length Is Not Distance4
- 7. In OpenCV4
- 8. What Came Next4
- 9. References4
- 10. Connections4
You hand OpenCV a 3-D point and it hands you back a pixel. Somewhere in between, a 3×3 matrix called K did all the work, and most of us have copied its numbers out of a calibration file without ever asking what each one does to the picture. This read opens that box.
Any camera in this series turns a point into a pixel in three steps:
- Look at the point from the camera's centre.
- Divide by its depth.
- Turn the result into pixels with K.
That's it. Everything else in the next ten reads (moving the camera, bending lenses, a second camera, depth from two photos) builds on these three steps.
Brush up on two things from outside the series:
- A matrix times a vector: a 3×3 matrix times a 3-vector, row by row. Nothing more is needed.
- Similar triangles: two triangles with the same angles have their sides in the same ratio.
One rig carries all eleven reads: a camera with a 640 × 480 picture, a focal length px and its principal point at (320, 240) (both explained below), and one point X = (0.3, −0.2, 4) in metres that we will follow from here to a point cloud.
1. A Dark Room With a Hole
Think of the oldest camera there is, the camera obscura: a dark room with a small hole in one wall. Light from the street comes through the hole and paints the street on the far wall, upside down. Now imagine moving that wall to the other side of the hole, the same distance in front of it. The picture is the same size, and it is the right way up. Every figure in this series draws the wall in front of the hole, because it saves us one flip.
Camera: focal length and principal point
Camera 1: move it and turn it
Let's read the figure:
- C₁ is the hole, the camera centre. The blue arrows are camera 1's own axes: x₁ to the right, y₁ down, z₁ forward.
- The dashed grey line out of C₁ along z₁ is the principal axis. The white rectangle across it is the image plane, and the small grey dot where the axis meets it is the principal point.
- The blue line is the ray from X to C₁. Where it crosses the image plane is the pixel. The camera's own picture is the inset titled "Camera 1 sees".
- The two grey triangles share the corner C₁. The big one has X's sideways offset (0.3 m) and its depth (4 m) as its sides. The small one has the pixel's offset and the distance from C₁ to the image plane, f, as its sides. Same angles, so the same ratio.
That last bullet is the whole camera. If the point sits Z metres in front and X metres to the side, the pixel sits fX/Z to the side of the principal point:
- : the point in the camera's frame, in metres. is the depth, the distance along the principal axis, not the straight-line distance from C₁.
- : the focal length, the distance from C₁ to the image plane, in pixels here (500 px).
- : the pixel's offset from the principal point, in pixels.
This is eq. 6.1 of [HART04] (Hartley & Zisserman, Ch. 6 Camera Models, §6.1, p. 154). The division by Z is the only step in the whole camera that is not a plain multiply-and-add. Our point gives:
- px to the right of the principal point.
- px, which is 25 px above it.
Why it exists. This is the camera in one line: a point sits in front of the hole, so where does its ray cross the image plane? Every other equation in this read is this one with something added, so nothing goes forward without it.
What it assumes. - Every ray passes through one point, C₁, and nothing bends it on the way: a straight line in the world stays straight in the picture. The book assumes this all the way through (H&Z Ch. 7 Computation of the Camera Matrix P, the opening of the chapter, p. 178). - X is written in the camera's own axes: centre at the origin, z along the principal axis. A point given in any other frame has to be moved into the camera's first; that is read 2. - The point is in front of the camera, Z > 0.
Where it breaks. - Z close to zero. A point on the principal plane, the plane through C₁ parallel to the image, has no pixel at all; it goes to the image's line at infinity (H&Z Ch. 6 Camera Models, p. 160). Just off that plane the numbers blow up: our X at a depth of 1 cm instead of 4 m sits 15 000 px to the right and 10 000 px above the principal point, far outside a 640 × 480 picture. Read 3 gives such points a home. - Z negative. The equation still answers. X moved to 4 m behind the camera gives u = −37.5 and v = 25: the real offsets, mirrored through the principal point, and nothing in them says "behind". Section 4 of read 2 has the test that catches it. - A real lens. It bends the ray by an amount set by how far out from the axis the point is (H&Z Ch. 7 Computation of the Camera Matrix P, eq. 7.7, p. 190), and the bend grows as the focal length and the price of the lens go down (H&Z Ch. 7 Computation of the Camera Matrix P, §7.4, p. 189). No f fixes that; read 5 adds the bend as its own step.
NOTE: The axes in this series: camera x points right, y points down, z points forward, and pixels count from the top-left corner. So up is −y, a negative v is above the centre, and the floor under the camera is y = +1. The book draws y up (H&Z Ch. 6 *Camera Models*, fig. 6.1, p. 154); OpenCV draws y down, and so does this whole series.
Try this: press play on Z. The pixel creeps toward the principal point, and the offset halves each time Z doubles.
2. Moving the Origin to the Corner
Camera: focal length and principal point
Camera 1: move it and turn it
This is the same figure, opened with X pushed twice as far away (Z = 8 m). Look at the inset's ticks this time:
- 0, 320 and 640 across, 0, 240 and 480 down. Pixels are not counted from the principal point (the grey cross); they are counted from the top-left corner of the picture.
- The pixel sits closer to the cross than it did at 4 m, but the cross itself has not moved.
Eq. 1 gave us an offset from the cross, so to get a real pixel we add where the cross is:
- : the principal point, in pixels from the top-left corner. Ours is (320, 240), the middle of a 640 × 480 picture.
- The book calls them (H&Z Ch. 6 Camera Models, p. 155, the line above eq. 6.3).
The numbers for X:
- and , so x₁ = (357.5, 215). That is the "pixel (u, v)" tile under the first figure.
- At Z = 8, the figure just above, it lands at (338.75, 227.5). The offset from (320, 240) halves; the principal point itself does not move.
Why it exists. Eq. 1 measures from the principal point, but the sensor counts from its top-left corner, and so does every pixel a library hands you. Without the shift, no number from eq. 1 can be compared with a real picture.
What it assumes. - One f for both directions: square pixels, with rows and columns at right angles. Section 4 drops both. - (c_x, c_y) belong to this picture size. They are pixels from the corner of this image, not of the sensor in general.
Where it breaks. - A resized or cropped picture with the old numbers. Crop it and the corner moves, so (c_x, c_y) move by the crop's corner; resize it and every entry scales. The resize NOTE at the end of Section 4 has the numbers.
Try this: click "on the axis". X lands exactly on (320, 240), whatever its depth.
3. Add a 1, Divide by the Last Number
Camera: focal length and principal point
Camera 1: move it and turn it
Back at our point X, look at the second tile, "K X before dividing": three numbers, (1430, 860, 4), and the last one lit up. Eq. 2 still has a division in it, and divisions do not fit in a matrix. The trick that fixes this is the backbone of the whole book, so we take it slowly.
Write the pixel (u, v) as the 3-vector (u, v, 1): add a 1 at the end. Then agree that any multiple of that vector means the same pixel:
- : "is the same pixel as".
- To read a pixel out of any 3-vector, divide by the last number.
These are homogeneous coordinates (H&Z Ch. 2 Projective Geometry and Transformations of 2D, §2.2.1, pp. 26–27). For x₁: , and 715 / 2 = 357.5, 430 / 2 = 215. Same pixel.
Where it breaks. - A last number of 0. There is nothing to divide by, so (u, v, 0) is no pixel we can draw, and (0, 0, 0) is no point at all, which is why k ≠ 0 (H&Z Ch. 2 Projective Geometry and Transformations of 2D, pp. 26–27). A last number of 0 is a point at infinity, and read 3 is about exactly those.
Why bother? Because now the divide by depth can wait until the very end. Multiply first, all of it linear, and divide once when you want a pixel. The whole camera becomes one matrix times one vector:
- : the calibration matrix, f on the diagonal and the principal point in the last column (H&Z Ch. 6 Camera Models, eq. 6.4, p. 155).
- : the point in the camera's frame, in metres.
- : the pixel, homogeneous. Its last number is the depth, 4.
Divide by the last number: 1430 / 4 = 357.5 and 860 / 4 = 215. The same x₁ as eq. 2, and nothing was divided until the last line. That is the "K X before dividing" tile in the figure above, with the 4 lit up.
Why it exists. It turns the whole camera into one matrix times one vector, with the divide pushed to the very end. That is what lets the later reads stack more matrices in front of K (a pose, a second camera) and still call the result one camera.
What it assumes. - K's last row is (0, 0, 1), so the third number of K X is the depth Z itself, and dividing by it gives back eq. 2. - X is in the camera's own axes, as in eq. 1. For any other camera, read 2 puts a pose in front of K.
Where it breaks. - Lens distortion cannot be written into a 3 × 3 matrix: it bends the normalised point by an amount that depends on its distance from the axis, after the divide and before K (H&Z Ch. 7 Computation of the Camera Matrix P, §7.4, p. 190). Read 5 slots that step in.
So, to the question "what does a camera do?": it is just a matrix multiply, followed by one divide. However many matrices we stack in front of K later, every camera in this series is still that.
Try this: drag f in the figure and watch K's diagonal light up in the K tile. Only the two f entries change; 320 and 240 stay put.
4. What Each Number in K Does
Camera: focal length and principal point
Camera 1: move it and turn it
K never sees the 3-D world. It acts on the picture after the divide by depth, so every number in it is a 2-D operation on a flat image:
- f scales the picture about the principal point. A long lens (the "long lens" button) blows everything up; nothing new appears in front of anything else.
- (c_x, c_y) shifts the picture. Drag the cross in the camera's picture and everything slides with it.
- s shears it: the "skewed sensor" button leans every vertical edge of the cubes.
- The tile "far-cube corners inside the near cube's outline" never changes, whatever you do to K. K cannot reveal anything that was hidden, because it only stretches and slides a picture that was already taken.
The book's most general K has five numbers (H&Z Ch. 6 Camera Models, eq. 6.10, p. 157):
- : the focal length in pixels, measured across and down. With square pixels they are equal, 500 px each here.
- : the principal point, our = (320, 240).
- : the skew, in pixels. It is non-zero only if the pixel rows and columns are not at right angles.
With a skew of 100 the pixel of X moves to , so x₁ = (352.5, 215). Only u moves, because s sits in the first row.
Why it exists. It is everything an upper-triangular 3 × 3 can do to a flat picture: two scales, a lean and a shift. Take any estimated camera matrix apart and the K that comes out has this shape (H&Z Ch. 6 Camera Models, §6.2.4, p. 163), so this is the K to expect from a calibration file.
What it assumes. - The sensor is a flat, regular grid: every pixel the same size and shape, so one α_x, one α_y and one s serve the whole picture (H&Z Ch. 6 Camera Models, eqs. 6.9–6.10, p. 157). - The lens setting does not change. Zooming by a factor k multiplies K by diag(k, k, 1) (H&Z Ch. 6 Camera Models, §6.3.1, p. 167), so every zoom setting has its own K.
Where it breaks. - A K from another zoom setting. Try this: press "long lens". f goes from 500 to 900 px and X moves from (357.5, 215) to (387.5, 195), so a K measured at 500 px misplaces every pixel but the principal point. - A non-zero skew out of a decomposition. A real sensor almost never has one, so it says more about the picture than the sensor; the first NOTE at the end of this section says when it turns up.
4.1 Focal length in pixels and in millimetres
A lens box says "4 mm", but K says 500 px. The bridge is the size of one pixel on the sensor (H&Z Ch. 6 Camera Models, eq. 6.9, p. 157):
- : the lens's focal length, in millimetres.
- : pixels per millimetre on the sensor (one over the pixel pitch).
A 4 mm lens on a sensor with 8 µm pixels gives px. From now on f always means pixels, and I will always write the unit.
Where it breaks. - Pixels that are not square have m_x ≠ m_y, so the same lens gives α_x ≠ α_y (H&Z Ch. 6 Camera Models, eq. 6.9, p. 157). One f in pixels is only right for both directions because our pixels are square.
Focal length in pixels is what sets the field of view: the picture is 640 px wide, so half of it, 320 px, sits at f px from the centre:
- : the field of view across and down, in degrees.
- 320 and 240 are half the picture's width and height, in pixels.
So our camera sees 65.2° across and 51.3° down; the blue arc in the K figure shows the first.
Where it breaks. - A principal point off the middle. Then the two halves of the picture are not 320 px each, and the field of view is . Try this: press "shift the centre" in the K figure. With c_x = 400 the tile reads 64.3°, not 65.2°.
NOTE: Modern sensors are etched as a square grid, so in practice s = 0 and α_x = α_y. The book says a non-zero skew is "very unlikely" in a real camera (H&Z Ch. 6 *Camera Models*, p. 164); it turns up when you photograph a photograph. OpenCV's pinhole camera matrix has no skew entry at all: its top row is (f_x, 0, c_x) [OPEN24].
NOTE: The resize trap. Halve the image and K must halve with it: f, c_x and c_y become (250, 160, 120). OpenCV's docs say exactly this, that every entry scales with the image [OPEN24]. If your pixel coordinates put (0, 0) at the centre of the top-left pixel, the exact map for the principal point is c′ = (c + 0.5)·½ − 0.5, which gives (159.75, 119.75). And (320, 240) is a value we chose for K, not a claim that the axis hits the middle of the sensor.
Try this: drag the principal point, then add skew. The picture slides and leans, and nothing new comes into view.
5. A Pixel Is a Ray
Camera: focal length and principal point
Camera 1: move it and turn it
Now run the camera backwards. You are given the pixel x₁ = (357.5, 215) and asked: where was the point?
- The blue line from C₁ through x₁ is the answer, all of it. Play λ: X runs along that line, and its pixel in the inset never moves.
- The hollow points are three more places X could have been. Hover them: each one says "still pixel (357.5, 215)".
- What the camera threw away is the depth. One photo cannot give it back; that is the problem the second half of this series solves with a second camera.
Let's undo K first. K is a 3×3 matrix with an inverse, so:
- : the pixel, homogeneous.
- : the normalised coordinates of the pixel, in metres per metre of depth. Row by row it is .
For x₁ that is x̂₁ = (0.075, −0.05, 1): the point that sits at depth 1 on the ray. The figure's first tile shows it. Every other point on the ray is a multiple of it:
- : the depth along the axis, in metres. Because x̂₁ ends in 1, λ is exactly the point's Z.
- The book writes the ray of any camera as (H&Z Ch. 6 Camera Models, §6.2.2, pp. 161–162); for a camera at the origin like ours, that is this same line.
The numbers:
- λ = 4 gives (0.3, −0.2, 4), our X back again.
- λ = 2, 6 and 9 give (0.15, −0.1, 2), (0.45, −0.3, 6) and (0.675, −0.45, 9). Put any of them through eq. 4 and the divide gives (357.5, 215) every time.
Why it exists. These two lines answer the question this section opened with: given only a pixel, where can the point be? Undo K, then scale along the result. Every later read that goes from pixels back into the world starts here.
What it assumes. - K is known, exactly. Every number of x̂₁ comes from it. - λ > 0. Only the half of the line in front of the camera can be seen in a picture (H&Z Ch. 6 Camera Models, p. 161).
Where it breaks. - A wrong K tilts every ray. Try this: open the camera panel and set c_x to 330 instead of 320. The same pixel now gives x̂₁ = (0.055, −0.05, 1), and the point at λ = 4 lands at (0.22, −0.2, 4), 8 cm from X. Getting K right is read 6. - A raw pixel from a real lens. K⁻¹ assumes the pixel sits where a pinhole would put it; with distortion it does not, and the ray points the wrong way, worst near the edges (H&Z Ch. 7 Computation of the Camera Matrix P, §7.4, pp. 189–190). Undistort the pixel first (read 5; the undistortPoints row of Table 1).
This is the sentence the whole series hangs on: a pixel is a ray. The later reads move that ray (read 2), send it to infinity (read 3), fit cameras to many of them (reads 4 and 6), bend it (read 5) and cross it with another camera's ray (reads 7 to 11).
Try this: click "the corner pixel". The ray swings out to the top-left corner of the picture, and x̂ becomes (−0.64, −0.48, 1), the last column of K⁻¹.
6. Focal Length Is Not Distance
Camera: focal length and principal point
Camera 1: move it and turn it
A last thing people mix up, because both "zoom in" and "walk closer" make the subject bigger: f and distance. Press play in the figure. The camera walks back from the 1 m post while f grows with it, so the post stays the same size in the picture, and the two posts 8 m behind it swell. Film people call this the dolly zoom.
No new equation is needed; it is eq. 1 with the post's height for Y. A 1 m post seen from dist metres away is pixels tall:
- At 4 m with f = 500 px the post is 125 px, and a post 8 m behind it is 500 / 12 = 41.67 px. The field of view is 65.2°.
- Walk in to 2 m and widen to f = 250 px: the post is still 125 px, the far post shrinks to 25 px, and the view opens up to 104°.
- Walk back to 12 m and zoom to f = 1500 px: the post is still 125 px, the far post grows to 75 px, and the view narrows to 24.1°.
So:
- f sets how big the picture is. It multiplies everything in eq. 1 by the same number, near and far alike.
- Distance sets how things stack up. The near post and the far post divide by different depths, and only moving the camera changes the ratio of those depths.
Keep walking back and zooming in, and the near and far posts end up at nearly the same depth as seen from the camera. In the limit it divides every point by one and the same depth; the book calls that an affine camera (H&Z Ch. 6 Camera Models, §6.3, p. 166), and the series leaves it there.
Try this: click "zoom held". The camera stands 12 m back with f still 500 px: the post drops to a third of its size and the posts behind it shrink much less. Walking changes how the two compare; zooming never did.
7. In OpenCV
| Here | OpenCV | Shape | Series value |
|---|---|---|---|
| K | cameraMatrix | 3×3 | [[500, 0, 320], [0, 500, 240], [0, 0, 1]] |
| f (as α_x, α_y) | cameraMatrix[0,0], [1,1] (f_x, f_y in the docs) | scalars, px | 500, 500 |
| c_x, c_y | cameraMatrix[0,2], [1,2] | scalars, px | 320, 240 |
| X → x₁ | projectPoints(objectPoints, rvec, tvec, cameraMatrix, distCoeffs) with rvec = tvec = 0 and empty distCoeffs (no distortion) | N×1, 2 channels | (357.5, 215) |
| fields of view | calibrationMatrixValues(cameraMatrix, imageSize, apertureWidth, apertureHeight) → fovx, fovy, … | degrees | 65.2, 51.3 |
| x̂₁ = K⁻¹x₁ | undistortPoints(src, cameraMatrix, distCoeffs) with no P: returns normalised coordinates | N×1, 2 channels | (0.075, −0.05) |
Table. 1 This read in OpenCV 4.x [OPEN24]. calibrationMatrixValues also returns the focal length and principal point in the sensor's units (apertureWidth is the sensor width in mm). undistortPoints is the subject of read 5; with zero distortion it is exactly K⁻¹.
8. What Came Next
Our camera sat at the world's origin, looking straight down z, so its frame and the world's were the same thing and X went straight into K. But a real camera sits somewhere in the room and points somewhere. How do we tell K where it is, and which way it is looking? That is three numbers for the position and three for the turn, and it is Where Is the Camera? — R, C and t.
9. References
- [HART04] R. Hartley, A. Zisserman, Multiple View Geometry in Computer Vision, 2nd ed., Cambridge University Press, 2004. Chapters used in this read: Ch. 2 Projective Geometry and Transformations of 2D; Ch. 6 Camera Models; Ch. 7 Computation of the Camera Matrix P.
- [OPEN24] OpenCV, Camera Calibration and 3D Reconstruction (calib3d), OpenCV 4.x documentation.
10. Connections
What this page builds on, cites or links to, and what points back at it. A plain box is a “builds on”; “cited” and “linked in the text” are the lighter links. Hover a box for a preview.
Related
- Read · same series: Multiple View Geometry
- Read · builds on this (next in the series)
- Read · same series: Multiple View Geometry
- Read · builds on this (next in the series)
- Read · same series: Multiple View Geometry
- Read · same series: Multiple View Geometry
Go deeper
-
You are hereThe Pinhole Camera — A Pixel Is a RayRead
-
ThenRead
-
Read
-
Read
-
Read
-
Read
-
Read
-
Read
-
Read
-
Read
-
Read
Go broader
- SeriesMultiple View Geometrypart 1 of 11 · start from the first part
- Its tags on the map
- Ask the mapWhat connects Pinhole camera and …type the other page's name; the map answers with the chain of links between them