How to measure distance with a webcam, a laser pointer and OpenCV.
Many (about 10 or more) years ago I have found an interesting project: a distance measurement system with a webcam and a laser pointer. It's probably long gone, but after these years, I have decided to recreate it.
See my demostration video on youtube.
Figure 1. The measured distance in cm.
If the object (and the laser point) is further, then the dot's position is also different. This is what the rangefinder uses to get the distance.
The computer vision part is simple. It is created in OpenCV. The video stream [1] is turned into grayscale with cvtColor() [2]. After that, it is turned into black and white with binary threshold() [3]. Now only the laser is visible, as a white dot, everything else is black. In the black and white picture, it is possible to find the contours with findContours() [4] and get the moments [5] from it. With the help of moments, we can calculate the center of the laser dot.
To calculate the distance, I made some measurements of the relation between the laser dot's position and the object distance, as you can see it in Figure 3.
Figure 3. The measured values.
From these data, I created a look-up table and used linear interpolation [6] to calculate the values in between the measured values.
Finally, the system draws a circle [7] on the laser dot and writes a text [8] about the distance in cm.
Figure 4. Workflow of the laser rangefinder.
To build it, you need a GCC version, that supports c++14. For OpenCV I had the latest version, I am not sure if it works or not with others.
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
$ pkg-config --modversion opencv
4.0.0
If you have everything, you can clone it.
$ git clone https://github.com/ferenc-nemeth/opencv-laser-rangefinder.git
$ cd opencv-laser-rangefinder
$ cd Src
Inside this folder, you have to modify the magic constants inside laser.cpp: "cam_number"; "cam_width"; "cam_height". Later, you might need to modify the "threshold_min" value too. After you are done, you can build it.
$ make
$ ./laser
Now you can use it, but the distance is going to be wrong. You have to take measurements for different distances. You have to write down the values shown in the terminal window (see figure 3). After you took enough, you have to write them inside "pixel" and "cm" vectors.
You are done, enjoy.
[1] OpenCV docs - cv::VideoCapture Class Reference
[2] OpenCV docs - cvtColor()
[3] OpenCV docs - threshold()
[4] OpenCV docs - findContours()
[5] OpenCV docs - moments()
[6] Wikipedia - Linear interpolation
[7] OpenCV docs - circle()
[8] OpenCV docs - putText()