Laser Range Finder This C# programming example illustrates how to measure optical the distance to a target by triangulation.
Language: | .NET C#/Visual Basic
Version: | 3.3
Released: | 20070802
Author: | IC Imaging Control Support Department
Requirements: |
Software: | IC Imaging Control >3.0.3, Visual Studio™ 2005
Hardware: | Camera, converter or grabber with WDM Stream Class drivers.
Download C# sample | Laser Range Finder - C#

Introduction

This C# programming example illustrates how to calculate the distance to a random target though triangulation in the view of the camera.

The application's window looks as follows:

This is a laser based method for mearure the distance between the laser source and a target. It uses triangulation in order to calculate the distance. As shown in the picture, the camera and the laser are one unit and therefore the distance 'h' between the camera and the laser is determined. While the laser is used to illuminate the target, the camera measures the laser's movement in position along the x-axis (as the camera's field of view width is greater than the heigth, it must be rotated by 90° to get more pixels ). With the distance 'h' and the laser point position on the x-axis, the angle and the distance between the camera and the target can be calculated.

Example

What is needed in order to calculate the distance between camera and target automatically:

- A fixed camera and laser set-up in order to measure h.
- At least two camera to target distance measurements for applying them to a formula which will be used in the program.
- Configuration of the measurement software.

Let us start with the experimental set-up:

The laser is fixed on the camera parallel to the x-axis which, in itself, is fixed on a tripod (as shown in the picture below). Now it is possible to measure the distance "h" .

In our case, "h" is 102 mm.

Experimental set-up

Triangulation-sketch

In the next step calibration data is to be retrieved. The calibration consists of a manual measured distance 'd' between the laser and the target and the corresponding laser point position 'p' on the x-axis on the live image. This is done twice for "d1" and "d2" as seen in the triangulation-sketch which results in two laser point positons on the x-axis "p1" and "p2".

In our case the measuremnts are d1 = 150 mm : p1 = 64 , d2 = 200 mm : p2 = 196

With the following equation, it is possible to calculate the angle based on our fixed value of h as well as the actual distance corresponding to every pixel value.

atan(D/h) = angle

In our case, alpha1 = 55.78 degree ; alpha2 = 62.98 degree

Now we can use a linear relationship to get a formula which returns the angle for every pixel value. And using tan(angle)*h, we can calculate the distance to the target.

64m + b = 55,78

196m + b = 62,98

After solving this simple linear system, we get for m = 0,0545454545 and for b = 52,2890909091 from this it follows that our formula to calculate the angle is

0,0545454545 * pixel + 52,2890909091.

Programm

The method findLaserPoint implements the laser point search in the image. For more information about this method please check the Finding a Laser Point - Snippet on our homepage.

    C#

    private bool findLaserPoint(out int xLaser, out int yLaser)
    {
        TIS.Imaging.ImageBuffer imagebuffer = icImagingControl1.ImageActiveBuffer;
        int redPixel = 0;
        xLaser = 0;
        yLaser = 0;

        // Check each pixel in the image if the red value is greater than the desired threshold (230).

        for (int y = 0; y < imagebuffer.Lines; y++)
        {
            for (int x = 0; x < imagebuffer.PixelPerLine; x++)
            {
                // x and y index for the imagebuffer.
                int indexXred = x * 3 + 2;
                int indexY = imagebuffer.Lines - y - 1;

                if (imagebuffer[indexXred, indexY] > 230)
                {
                    // Count red pixels.
                    redPixel++;

                    xLaser = xLaser + x;
                    yLaser = yLaser + y;
                }
            }
        }
        // Calculate the center of all red pixels.
        if (redPixel > 0)
        {
            xLaser = xLaser / redPixel;
            yLaser = yLaser / redPixel;

            return true;
        }
        else
        {
            return false;
        }
    }

Upon clicking on the Start Live button the video will be started with a line parallel to the x-axis being drawn in the middle of the live video. The line serves to adjust the laser.

    C#

    private void cmdStartLive_Click(object sender, EventArgs e)
    {
        icImagingControl1.LiveStart();
        icImagingControl1.OverlayBitmap.DrawLine(Color.Blue, 0, icImagingControl1.LiveDisplayHeight / 2, icImagingControl1.LiveDisplayWidth, icImagingControl1.LiveDisplayHeight / 2);
        cmdStartLive.Enabled = false;
        cmdStopLive.Enabled = true;
    }

Since it is not recommended to change textbox.text from the ImageAvailable event directly, a Delegate should be used. The reason for this programming overhead is the use of different threads. The ImageAvailable event handler is called from IC Imaging Control's grabbing thread. The change of the textbox.text is performed in the application's thread. Crossthread calls to controls can lead to application locks.

First off all, the method that set the text is created:

    C#

    private void UpdateControlText(Control ctrl, string text)
    {
        ctrl.Text = text;
    }

Then, the Delegate is declared:

    C#

    private delegate void UpdateControlTextDelegate(Control ctrl, string text);

Finally, a method is created to call the Delegate by BeginInvoke.

    C#

    private void SetControlText(Control ctrl, string text)
    {
       BeginInvoke(new UpdateControlTextDelegate(UpdateControlText), new object[] { ctrl, text });
    }

In the ImageAvailable event, the range will be calculated like describeted in the example. The only step here to do is to define h , the distance between laser and camera and the formula for the angle.

Visual studio works with radians, not degrees. That is the reason why it is necessary to convert the angle in radians else the range would take a wrong value.

The final step is to call the SetControlText method to update all textboxes with the new information about the target.

    C#

    private void icImagingControl1_ImageAvailable(object sender, TIS.Imaging.ICImagingControl.ImageAvailableEventArgs e)
    {
        int x, y;
        double angle, angleradians;
        double range;
        double h = 102;

        if (chkRange.Checked)
        {
            if (findLaserPoint(out x, out y))
            {
                // Calculate the angle.
                angle = 0.0545454545 * x + 52.2890909091;
                // Convert degrees to radians.
                angleradians = (Math.PI/180) * angle;
                // Calculate the range Tan(angle) * h.
                range = Math.Round(Math.Tan(angleradians) * h, 0);
                // Update the textboxes.
                SetControlText(txtX, x.ToString());
                SetControlText(txtY, y.ToString());
                SetControlText(txtAngle, Math.Round(angle,2).ToString());
                SetControlText(txtRange, range.ToString() + " mm");
            }
            else
            {
                SetControlText(txtX,"No laser");
                SetControlText(txtY, "No laser");
            }
        }
    }