Click here to Skip to main content
Click here to Skip to main content

Range Finder

, 30 Apr 2009
Rate this:
Please Sign up or sign in to vote.
A simple program to find real size or distance of objects in your digital camera photos
Sample Image

Table of Contents

Introduction

After a trip and when you are looking at your travel photos, sometimes you want to know the distances or sizes of the objects in there. It’s somehow possible.

If you can find some objects in your photos whose sizes you know, you can measure their distances and if you know the distance of an object, you can find the size of it. For example if you know the height of a special building (e.g. Pharos or a tower) and you are some kilometers away from it, you can measure your distance using a simple photo. Sometimes it is funny!

How Does It Work?

Light rays refract when they pass through the lens and concentrate on the surface. This effect is used in our eyes and similar devices as cameras, microscopes, telescopes, etc.

In cameras, there are a group of lenses (instead of one) that work together to make more control on light and to get a better quality.

But the rules are the same for a single lens or a group of lenses. There are four variables that are important in our calculations.

  1. The size of the object (Y1)
  2. The distance of the object from the lens (X1)
  3. The size of the image on the sensor or the film (Y2)
  4. The distance between the sensor and the lens (X2)

And there is an equation for our variables as: X1/Y1 = X2/Y2

How Did We Find the Equation?

If we look at the previous figure, we can find two right triangles. There are some rules about triangles and we use them in this case.

a1 = a2 ==> tag a1 = tag a2

Tangent = Opposite Side / Adjacent

tag a1 = Y1/X1

tag a2 = Y2/X2

tag a1 = tag a2 ==> Y1/X1 = Y2/X2 ==> we can inverse both sides of the equation ==> X1/Y1 = X2/Y2

Now that we found the formula, if we know three variables, the fourth is in our hands.

The good news is we always know the X2 size. The usual name of X2 size is Focal Length and manufacturers of the lens print it on the body of the lens (measured in millimeters). The following lens has a focal length of 50 mm.

Some lenses have variable focal lengths. They call them Zoom lenses. The following figure shows an 18 to 55 mm zoom lens.

This figure is a Point and Shoot camera with focal lengths ranging from 7.4 to 44.4 mm (Zoom).

But remembering the focal length of our shots is difficult, especially when we take several pictures with different zoom values. The good news is that every digital camera saves some useful data in the image file and the focal length is one of them. So we don't need to remember anything. If you want to see what data are saved with your images, just do as follows:

  1. Right click on the image
  2. Select Properties
  3. In the new window, select Summary Tab and click on Advanced button (Windows XP) or select Details Tab (Windows Vista)

These data are named "EXIF" information.

The second variable that we need to measure is the image size on the sensor (Y2). We can measure it by some calculations. The important values here are Sensor’s width and height, and the width and the height of image. Again there is good news: we can find these values in EXIF information.

Consider that you cannot measure correct values if you cropped or resized the image file. So use the original image file without any changes.

Now, one side of our equation is solved. There are still 2 variables on the other side. It means if you know the size of the object (Y1), you can calculate the distance as: X1 = Y1 * (X2/Y2).

And when you know the distance (X1), you can calculate the size: Y1 = X1 / (X2/Y2).

There are usually some landmarks in the photo of which you know their sizes, such as your friends, historical places, towers, cars, flags or even people where you can estimate their sizes. (Above figures: my friend in Ukraine)

Using the Code

The algorithm is something like this:

Variables

Initially I declared some variables and a Class (Camera) for collecting all information about cameras. Consider that our EXIF information doesn't have Sensor width or height, but it contains camera name. I added an external file (Camera.lst) that contains popular digital cameras’ sensor size, sorting the cameras by name.

I also add camera models to main menu, so if your image file doesn't contain EXIF information, you can add values manually.

private float myZoom = 1;
private int startX = 0;
private int startY = 0;
private int movedX = 0;
private int movedY = 0;
private double myMeasure = 0;
private double mySize = 0;
private double myDistance = 0;
private double mySizeScale = .01;
private double myDistanceScale = 1;
private int myMeasureStartX = 0;
private int myMeasureStartY = 0;
private bool horiZontal = true;
private Bitmap myBitmap;
 
class Camera
{
    internal string Factory="";
    internal string Model = "";
    internal string AliasName = "";
    internal string SensorType = "";
    internal float SensorWidth = 0;
    internal float SensorHeight = 0;
}
private List<camera /> allCameraInfo=new List<camera /> ();
 
private void loadCameraInfo()
{
    // Open the file 
    string dataFile=Application.StartupPath +"\\Data\\camera.lst";
    if (System.IO.File.Exists(dataFile))
    {
        using (System.IO.StreamReader sr = System.IO.File.OpenText(dataFile))
        {
            string myLine = "";
            while ((myLine = sr.ReadLine()) != null)
            {
                if (!myLine.StartsWith("//") && myLine.Trim() != "")
                {
                    string[] myData;
                    myData = myLine.Split(new string[] { "," }, StringSplitOptions.None);
                    try
                    {
                        //Add Camera information to list collection
                        Camera myCameraInfo = new Camera();
                        myCameraInfo.Factory = myData[0].Trim ();
                        myCameraInfo.Model = myData[1].Trim ();
                        myCameraInfo.AliasName = myData[2].Trim ();
                        myCameraInfo.SensorType = myData[3].Trim();
                        myCameraInfo.SensorWidth = Convert.ToSingle(myData[4]);
                        myCameraInfo.SensorHeight = Convert.ToSingle(myData[5]);
                        allCameraInfo.Add(myCameraInfo);
 
                        //Add Camera manufacturer to the menu
                        bool newFactory = true;
                        foreach (ToolStripMenuItem  mi in mnuCamera.DropDownItems )
                        {
                            if (mi.Text.Contains(myCameraInfo.Factory)) 
						newFactory = false;
                        }
                        if (newFactory)mnuCamera.DropDownItems.Add(myCameraInfo.Factory);
 
                        // Add cameral model to the menu
                        foreach (ToolStripMenuItem mi in mnuCamera.DropDownItems)
                        {
                            if (mi.Text.Contains(myCameraInfo.Factory)) 
				mi.DropDownItems.Add(myCameraInfo.Model + 
                            	(myCameraInfo.AliasName == "" ? "" : " - " + 
				myCameraInfo.AliasName ),null, mnuCamera_Click);
                        }
                    }
                    catch (Exception ) { }
                }
            }
        }
    }
}

Loading New Image

Then the program is ready. Every time you load a picture from hard disk, the following procedure checks for its Sensor width, height and camera picture if it is available in the data directory.

//Finding camera info and picture
private void cameraSerach()
{
    txtSensorHeight.Text = "";
    txtSensorWidth.Text = "";
    txtSensorType.Text = "";
    picCamera.Image = Properties.Resources.noPhoto;
    toolTip1.SetToolTip(picCamera, "");
 
    string camControl = "MRK";	// this is for preventing finding 
				// camera names like D300 instead of D3 
    string camName = txtCameraFactory.Text.Replace
			(" ", "").Replace("-", "").ToLower() + camControl;
    bool camFound = false;
    byte camLoop = 0;
    do
    {
        foreach (Camera thisCamera in allCameraInfo)
        {
            if (camName.Contains(thisCamera.Factory.Replace(" ", "").ToLower()) 
							&& !camFound )
            {
                if (camName.Contains(thisCamera.Model.Replace
			(" ", "").Replace("-", "").ToLower() + camControl) || 
                   (camName.Contains(thisCamera.AliasName.Replace
			(" ", "").Replace("-", "").ToLower() + camControl) && 
                    thisCamera.AliasName != ""))
                {
                    txtSensorType.Text = thisCamera.SensorType;
                    txtSensorWidth.Text = thisCamera.SensorWidth.ToString();
                    txtSensorHeight.Text = thisCamera.SensorHeight.ToString();
                    toolTip1.SetToolTip(picCamera, thisCamera.Factory + " " + 
							thisCamera.Model);
                    string picFile = Application.StartupPath + "\\Data\\" + 
						thisCamera.Factory + "_" + 
                    thisCamera.Model.Replace(" ", "") + ".gif";
                    if (System.IO.File.Exists(picFile)) picCamera.Image = 
						Image.FromFile(picFile);
 
                    camFound = true;
                }
            }
        }
        camControl = "";
        camLoop++;
    } while (!camFound && camLoop < 2);
} 

35 mm Equivalent

Before the digital era, we usually used 35 mm film cameras. The film size (sensor size) was fixed at 36 mm X 24 mm. in this type of camera; a 50 mm lens has an angle of view about 46° (equals to that of our eyes) and is called Normal Lens. All lenses with lower focal lengths named as Wide Angle (e.g. 28mm) and lenses with higher values are called telephoto lens (e.g. 200mm).

Digital cameras have different sensor size, because of some mathematical reasons; the focal length of a lens is different when we use it on cameras with different sensor sizes. For example a 35 mm wide angle lens act as 35mm on a Full frame camera (e.g. Canon EOS 5D), acts as about 50 mm normal lens on a camera with APS-C sensor size(e.g. Nikon D60), and as 70 mm telephoto on a 4/3 ” sensor size camera (e.g. Olympus E-520).

To prevent the confusion about the focal length, all manufactures use equivalent values in presenting their cameras which show how the camera works, if it were a 35 mm film camera. For example, the following camera (Canon A590) has a zoom lens with 5.8 to 23.2 mm focal length, but in the catalogue, you see they use 35 - 140 mm equivalent value.

To calculate equivalent values, we need to divide the diagonal size of 35 mm film camera’s sensor (about 43.27 mm) by diagonal size of our camera’s sensor (here is about 7.18 mm). The result value is named as Focal length Multiplier. And the final formula is as follows:

Focal length equivalent = Focal length * FL Multiplier.

In the above camera, our calculations are as follows:

FL Multiplier = 43.27 / 7.18 = 6

Minimum focal length = 5.8 * 6 =34.8

Maximum focal length=23.2 * 6 = 139.2

And I used the following code to calculate 35 mm equivalent focal length:

private void txtPicFL_TextChanged(object sender, EventArgs e)
{
    string myEquivalent = "";
    try
    {
        double  eq =Math.Pow ( (Math.Pow(Convert.ToSingle(txtSensorWidth.Text), 2) + 
                    Math.Pow(Convert.ToSingle(txtSensorHeight.Text), 2)),.5);
        eq = Math.Round ((43.2666/eq) * Convert.ToSingle(txtPicFL.Text ));
        myEquivalent = eq.ToString();
    }
    catch (Exception) { }
 
    txtPicEquivalent.Text = myEquivalent;
}

Measuring the Size of the Object on the Sensor

When the user selects part of the image by mouse dragging, the following code measures its size on the sensor. It considers the orientation of the image (Landscape or Portrait), and shows the result on the status bar.

// measuring the selected part's size on the sensor
double xDiff = Math.Abs(myMeasureStartX - e.X) * myZoom * 
			Convert.ToSingle(txtSensorWidth.Text) / 
    Convert.ToSingle(horiZontal ? txtPicWidth.Text : txtPicHeight.Text);
double yDiff = Math.Abs(myMeasureStartY - e.Y) * myZoom * 
			Convert.ToSingle(txtSensorHeight.Text) / 
    Convert.ToSingle(horiZontal ? txtPicHeight.Text : txtPicWidth.Text);
myMeasure = Math.Pow((Math.Pow(xDiff, 2) + Math.Pow(yDiff, 2)), .5);
tssStatusM.Text = "Measure (mm):" + myMeasure.ToString();
 
// Drawing a red line to show the size of your selection
picMain.Refresh();
Graphics g = picMain.CreateGraphics();
g.ResetClip();
g.DrawLine(new Pen(Color.Red), myMeasureStartX, myMeasureStartY, e.X, e.Y);

Final Calculations

Now, we have focal length (X2) and size of the object on the sensor (Y2), if you know the distance of the object (X1), you can find the size by using the following code:

mySize = myDistance * (myMeasure / Convert.ToDouble(txtPicFL.Text));
tstSize.Text = Convert.ToString(Math.Round ( mySize / mySizeScale,2));

And if you know the size (Y1), the following code calculates the distance of the object:

myDistance = mySize / (myMeasure / Convert.ToDouble(txtPicFL.Text));
tstDistance.Text = Convert.ToString( Math.Round( myDistance / myDistanceScale,2));

Workshop

Now, we want to try the application. I downloaded the following image from the Imaging-Resource site and saved it to my hard disk. You can try it too.

I load the picture. The program gets the required information from the file and shows it on the left panel.

Click on the thumbnail picture on the upper left corner, you can move rapidly to the selected part. I found a flag here.

Then, move the zoom bar to the right. You can also move the image by dragging mouse on the main image.

You can find this place if you try more.

And with more zooming, you see a flag on the building.

Now click on the pen button on the tool bar, and draw a line on the flag (as its height). The program measures its size on the sensor and shows it in the status bar.

I don't know the exact size of the flag, but I guess it must be about 150 cm (5 feet), if so, I type 150 in the object size box. The program calculate the distance as about 3 Km.

Accuracy

Accuracy of this method depends on your camera sensor size, quality of lens, noise of the image, etc. You can test your camera by putting a ruler in the known distance and taking a picture. Then use the program to measure it.

The average accuracy is more than 95% .

Points of Interest

Some parts of this article are about photography and cameras. There are some interesting points here.

When you are talking about digital cameras, the first thing you may consider is its Megapixels. Usually people think that more megapixels are better but there are some issues in this megapixels race that manufactures don't admit.

When the sensor size is the same, more megapixels not only don't mean a better image, sometimes it makes a lower quality. For making more pixels, the manufacturers have to make smaller pixels on the sensor, it means each sensor’s pixel collect less light. In this situation, the ability to process on light is less and noise of each pixel rises. And you have an image with more pixels and more noise. This issue shows itself especially in low light situations.

If you want to pay more money for your digital camera, spend it on its sensor size. A digital camera with 8 megapixels and 1/1.7” sensor size is preferred to a 12 megapixel with 1/2.5” sensor size. 8 million buckets of water are more than 12 million cups of water.

History 

  • First release (April 6, 2009)
  • Update 1 (April 22, 2009)
    • On the fly calculation
  • Update 2 (April 30, 2009)
    • The decimal problem in some European languages fixed (comma instead of point)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mohammad Reza Khosravi
CEO
Iran (Islamic Republic Of) Iran (Islamic Republic Of)

Comments and Discussions

 
Generalabdullah shah Pinmemberabdullahcodeproject13-Aug-10 2:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 30 Apr 2009
Article Copyright 2009 by Mohammad Reza Khosravi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid