13,046,184 members (84,486 online)
alternative version

#### Stats

38.1K views
57 bookmarked
Posted 30 Jan 2010

# Implementing a Basic Camera Model (Pinhole)

, 15 Jul 2016
 Rate this:
Implementing a basic camera model to extend the raytracing algorithms

## Introduction

Extending our ray tracing algorithms now we will implement a camera class.

The objective is to render the images setting the viewer at any position without restrictions since in our previous models, the viewer must be located at positive z axis, (0,0,z) z>0.

## Background

Although not implementing raytracing in this article, it is required to have an advanced level in mathematics and also read the previous articles on Raytracing on CodeProject.

The objective is to render the images setting the viewer at any position without restrictions as our previous model where the viewer must be located at positive z axis, (0,0,z) z > 0.

What is a pinhole camera?

"...A pinhole camera is a very simple camera with no lens and a single very small aperture. Simply explained, it is a light-proof box with a small hole on one side. Light from a scene passes through this single point and projects an inverted image on the opposite side of the box. Cameras using small apertures and the human eye in bright light both act like a pinhole camera.

The smaller the hole, the sharper the image, but the dimmer the projected image. Optimally, the size of the aperture should be 1/100 or less of the distance between it and the screen..."

A pinhole camera

## Step 1 - Defining Parameters

In order to perform all calculations, we do need some predefined parameters:

• Camera position Cp(x,y,z)
• Viewing direction vector V (x,y,z) normalized... means its module = 1 |V| = 1
• Focal length F (the distance between Camera position Cp and the camera projection plane S)

From the above parameters, we can retrieve other parameters which will be useful further:

• P, a point located at the plane

P = Cp-V*F(x,y,z)

• The S plane equation

From math books plane equation is in the form Ax+By+Cz+D=0

and also if we have a normal vector it is quite simple, and luckily we do have it and it is V.

From the same book...

A = Vx
B = Vy
C = VZ

we need to get D, but it simple now because we do have a point at the plane

so D = -(A*Px+B*PY+C*PZ)

A = normalVector.x;
B = normalVector.y;
C = normalVector.z;
D = -(normalVector.x * point.x + normalVector.y * point.y + normalVector.z * point.z);

## The Camera Coordinates System

Now let's call pinhole model as camera coordinates system.

So to represent a model, now we do have a Cartesian reference system x,y,z and also a camera coordinates system.

The plan is to translate and rotate our camera coordinates system to fit the reference Cartesian coordinates system, for this we need some equations on spherical coordinates to retrieve the theta and phi angles.

"...In mathematics, a spherical coordinate system is a coordinate system for three-dimensional space where the position of a point is specified by three numbers: the radial distance of that point from a fixed origin, its elevation angle measured from a fixed plane, and the azimuth angle of its orthogonal projection on that plane, measured from a fixed reference direction on the same. The elevation angle is often replaced by the inclination angle measured from a zenith direction perpendicular to the reference plane. ..."

Spherical coordinates

From my math book, we get how to represent a given R3 point into spherical coordinates and also conversions... (it will be used further).

Converting Cartesian coordinates to spherical

x = R sin (phi) cos (theta)
y = R sin (phi) sin (theta)
z = R cos (phi)

Converting spherical coordinates to Cartesian

R = sqrt(x2+y2+z2)
S = sqrt(x2+y2)
phi = acos(z/R)
theta = x>=0 asin(y/S)
x<0 PI - asin(y/S)

Follows how to calculate phi and theta angles, this will help us to rotate our coordinate system to fit the reference system

Point oNormalizedDirection = Algebra.Normalize(m_oDirection.x,
m_oDirection.y, m_oDirection.z);
// calculate frontpoint
m_oFrontPoint = new Point(m_oOrigin.x + oNormalizedDirection.x,
m_oOrigin.y + oNormalizedDirection.y,
m_oOrigin.z + oNormalizedDirection.z);
// 1 translate to origin
Point oTranslatedFrontPoint = new Point(m_oFrontPoint.x - m_oOrigin.x,
m_oFrontPoint.y - m_oOrigin.y,
m_oFrontPoint.z - m_oOrigin.z);
// calc phi & theta
double x2 = oTranslatedFrontPoint.x * oTranslatedFrontPoint.x;
double y2 = oTranslatedFrontPoint.y * oTranslatedFrontPoint.y;
double radius = Math.Sqrt(x2 + y2 + oTranslatedFrontPoint.z * oTranslatedFrontPoint.z);
double s = Math.Sqrt(x2 + y2);
m_dTheta = 0;
if (Math.Abs(s) > 1.0E-5)
{
if (oTranslatedFrontPoint.x >= 0)

{
m_dTheta = Math.Asin(oTranslatedFrontPoint.y / s);
}
else
{
m_dTheta = Math.PI - Math.Asin(oTranslatedFrontPoint.y / s);
}
}

## Calculating Projections

Projection

Our first objective is to calculate the projected point a at the plane S.

## How To Get This?

From my old math book again...

We can easily calculate the intersection between a line and a plane if we have both equations, and luckily again we do!

Our line equation in parametric form is r = p + t*v.

• p is any point at the line t is an scalar
• v is the line vector
• our p is the point a
• our v can be calculated from the Camera position to a as Cp-a

Using this parametric equation against the plane equation, we find the parameter t and so we do find the intersection point using

• t value at p + tv

#### Code

public Point GetIntersection(Point p, Point Origin)
{
Vector v = new Vector(p, Origin);
double E = (v.x * A + v.y * B + v.z * C);
if (Math.Abs(E)<1.0E-5)
{
return null;
}
v = Algebra.Normalize(v.x, v.y, v.z);
double t = -(A * p.x + B * p.y + C * p.z + D) / (E);
return new Point(p.x + t * v.x, p.y + t * v.y, p.z + t * v.z);
}

Our last objective is to map this intersection point into our screen.

For this, we need to fit the point into our reference coordinate system using the calculated phi and theta...

#### Code

public Point LocalToCartesian(Point point)
{
point.x -= m_oOrigin.x;
point.y -= m_oOrigin.y;
point.z -= m_oOrigin.z;

rtPoint.RotZ(-m_dTheta, ref point.x, ref point.y);
rtPoint.RotY(m_dPhi, ref point.x, ref point.z);

return new Point(point.x, point.y, point.z);
}

## Using the Code

All required code is in a project in the zip file at the top of the article, just download and compile.

## Points of Interest

It is very challenging to keep improving the algorithms on my own and using only math instead of using libraries. Many people ask me why to create something which is already in many libraries. The response is that I like the challenge, the discovery, and it is very satisfactory to see the results by my own hands and effort.

## History

Creating a camera class is a next step in the raytracing articles series, it will bring us to the next level and allow to start creating animations.

## Share

 Engineer Brazil
Senior Analyst

## You may also be interested in...

 First Prev Next
 My vote of 5 manoj kumar choubey26-Feb-12 21:46 manoj kumar choubey 26-Feb-12 21:46
 Broken link John Whitmire3-Feb-10 5:41 John Whitmire 3-Feb-10 5:41
 Re: Broken link andalmeida3-Feb-10 6:30 andalmeida 3-Feb-10 6:30
 Re: Broken link andalmeida1-Mar-10 14:15 andalmeida 1-Mar-10 14:15
 Are spherical coordinates necessary? supercat91-Feb-10 13:36 supercat9 1-Feb-10 13:36
 I would think that the simplest way to handle a pinhole camera would be to (1) assume that the lens is at (0,0,0) and the plane is at z coordinate h, in which case the coordinate on the 'film' will simply be (x*(h/z), y*(h/z)); (2) other placements of the 'camera' may be handled using a linear transformation matrix to map real coordinates to such a system. Note that assuming the film is horizontal at a fixed z coordinate will make it practical to handle cameras with lenses. For example, the x and y slopes (with respect to z) of a line that hits a horizontal lens (constant z coordinate) will be adjusted by (-x/f, -y/f) where (x, y) is the z intercept and f is the focal length. While it would be possible to handle lenses without mapping world coordinates to a fixed orientation, the formulas are so much simpler with such mapping that it's probably the way to go. Note that setting up the transformation matrix to handle the rotation and shifting will require using some trig functions, but those need only be used when the rotation is set or changed. Even if there are thousands of points that need to be mapped onto the camera plane, the trig functions won't have to be repeated.
 Re: Are spherical coordinates necessary? andalmeida2-Feb-10 0:14 andalmeida 2-Feb-10 0:14
 Nice... Alexander Müller30-Jan-10 23:01 Alexander Müller 30-Jan-10 23:01
 Last Visit: 31-Dec-99 18:00     Last Update: 23-Jul-17 7:50 Refresh 1