Medición de distancias con una cámara web y un puntero láser

Basado en el artículo original de Todd Danko
que a su vez se basa en el tutorial
Traducido con autorización del autor.

Introducción
Existen en el mercado muchos medidores de distancia (o telémetros) en base a ultrasonido, infrarrojo y hasta con sistema láser. Todos estos dispositivos cumplen bien su función, pero en el campo de la robótica aérea, el peso del dispositivo es una cuestión primordial. Cada componente que se agrega a la estructura de un avión debe tener un máximo de utilidad y eficiencia. Una nave aérea robótica miniatura puede llevar apenas 100 gramos de carga útil.

Medidores varios
(Esto es válido, también, para cualquier robot móvil, aunque sea terrestre, porque en estos casos también es importante controlar el peso para evitar un gasto excesivo de energía y así darle autonomía al robot y un mayor tiempo de funcionamiento sin necesidad de una recarga de sus baterías.)

Se pueden realizar tareas de visión robótica, tales como la identificación y sorteo de obstáculos, utilizando una cámara web (webcam) o una mini cámara de video inalámbrica conectada a una computadora a través de USB. Mejor aún, dos webcams pueden proporcionar una visión estéreo que nos dé mejor capacidad de evitar obstáculos, debido a que se puede determinar la profundidad. Esto, por supuesto, tiene la desventaja de agregar el peso de una segunda cámara de imagen.
Este trabajo describe la manera de utilizar un mini puntero láser de bajo costo junto a una única cámara de imagen barata, del tipo webcam, para obtener información de distancia.


La teoría
El diagrama que sigue muestra cómo se puede calcular la distancia hasta un objeto ubicado en el campo visual de una cámara de imagen proyectando un punto láser sobre él. La matemática necesaria para el cálculo es simple, de modo que es posible utilizar esta técnica en aplicaciones de visión robótica que requieren velocidad.
Veamos entonces cómo debemos hacer.
Se proyecta el haz del puntero láser sobre un objeto en el campo visual de una cámara de imagen; lo ideal es que este haz sea paralelo al eje óptico de la cámara. Junto con el resto de la escena tomada por la cámara de imagen, capturamos el punto luminoso del láser. Se aplica un simple algoritmo sobre la imagen, a la búsqueda de los pixeles más brillantes.
Asumiendo que la luz del láser es el área más brillante de la escena (algo que se cumple en las fotografías de más abajo, realizadas en interiores con un puntero láser común y de bajo precio), se puede conocer la posición de este punto luminoso en el cuadro de imagen.
Ahora debemos calcular la distancia hasta el objeto, en base a la posición donde cae el punto brillante respecto al eje "y" de la imagen. Cuanto más cerca se encuentra el punto brillante del centro de la imagen, más lejos está el objeto. Tomando como base el diagrama anterior, se puede calcular la distancia (D):
Por supuesto que para resolver esta ecuación debemos conocer "h", que es una constante definida por la distancia entre el haz del láser y el centro visual de la cámara, y el ángulo theta. Theta se calcula:
Uniendo las ecuaciones, obtenemos:
Muy bien, la cantidad de pixeles desde el centro del plano focal hasta el lugar donde aparece el punto del láser se puede contar trabajando sobre la imagen (simplemente, es una cantidad de líneas de imagen). ¿Y qué pasa con los otros parámetros de la ecuación? Debemos hacer una calibración para obtenerlos.
Para calibrar el sistema, tomaremos una serie de mediciones en las que conozcamos la distancia hasta el blanco, y también tomamos como medición a qué cantidad de pixeles desde el centro de la imagen se encuentra el punto en cada caso. Veamos un ejemplo de recolección de datos:
Datos de Calibración
Pixeles desde
el centro
D real
(cm)
10329
8145
6558
5571
4990
45109
41127
39159
37189
35218
Usando la ecuación que sigue, podemos calcular el ángulo real en base al valor de h y también la distancia real para cada punto.
Ahora que tenemos un Thetareal para cada valor, podemos lograr una relación que nos permitirá calcular el ángulo theta a partir de la cantidad de pixeles desde el centro de la imagen. Usé una relación lineal, de modo que es necesario aplicar una ganancia y un ajuste de compensación. Esto parece funcionar bien aun cuando no se tiene en cuenta el hecho de que el plano focal es llano en lugar de una curva de radio constante alrededor del centro de la lente.
De mis datos de calibración, calculé:
Desplazamiento (ro) = -0,056514344 radianes

Ganancia (rpc) = 0,0024259348 radianes/pixel

Usando:
Obtuve las distancias calculadas, y además calculé el error contra la distancia real en los datos de calibración:
Datos de distancia calculados y reales
Pixeles desde
el centro
D calc
(cm)
D real
(cm)
% de error
10329,84292,88
8141,4645-7,87
6557,5558-0,78
5575,81716,77
4993,57903,96
45110,851091,70
41135,941277,04
39153,27159-3,60
37175,66189-7,06
35205,70218-5,64

El hardware
Este medidor de distancias se compone de pocos elementos. Utilicé un trozo de cartón para sostener el láser junto con la webcam, de manera que el puntero láser apunte en dirección paralela al eje de la cámara. Los elementos que se ven en la imagen están colocadas sobre una grilla de 1 pulgada de lado (25,4 mm) para dar una referencia de tamaño.
Este es el aspecto del medidor de distancias tal como quedó luego del montaje.
El software
Escribí el programa de dos maneras, en un caso utilizando Visual C++ y en el otro con Visual Basic. Es problable que la versión de Visual Basic sea mucho más fácil de seguir que el código en Visual C++, pero bueno, hay una compensación: el código en VC++ se puede compilar y utilizar así (asumiendo que usted tiene Visual studio), mientras que el código en VB requiere la compra de un paquete de software aparte (además del Visual Studio).
Visual Basic
El código en Visual Basic que escribí está disponible aquí: vb_laser_ranger.zip
Para que este código funcione se debe tener instalado en la computadora el componente ActiveX VideoOCX.
A continuación se pueden ver listadas las funciones que se encuentran en el formulario principal:


A continuación se ven imágenes registradas con este programa:
Visual C++
Nota del autor original: para correr este ejecutable, son necesarios los drivers de la webcam, que en el caso del ejemplo (Logitech) son qcsdk y qc543. Lamentamos no disponer de ellos, pero se podrán hallar con una búsqueda en internet. Nosotros encontramos estos, pero no los hemos probado aún. Aquí hay muchos archivos fuente del programa.


Mi código completo para este proyecto se puede bajar de: LaserRange.zip
O si usted quiere probar directamente el ejecutable, bájelo de aquí: LaserRange.exe
Para correr el ejecutable, usted deberá tener ambos drivers, qcsdk y qc543, instalados en su computadora.
A continuación se ven dos imágenes de ejemplo del medidor de distancia funcionando con este programa. Observe que en el segundo ejemplo aparecen dos puntos láser. Esta luz errónea es causada por reflejos internos en la cámara. El punto reflejado pierde intensidad al rebotar dentro de la cámara, de modo que no interfiere con el algoritmo que detecta el pixel de mayor brillo de la imagen. (Nota del traductor: las imágenes han perdido colores en alguna parte del manipuleo, pero de todos modos sirven de ejemplo).
Mejoras posibles
Una mejora concreta que se puede hacer en este medidor de distancia es proyectar sobre el blanco una línea horizontal en lugar de un punto. De esta manera, podemos calcular la distancia en cada columna, en lugar de en una sola. Una disposición así se podría utilizar para localizar las áreas de distancia máxima, que serían los lugares hacia los que se debería dirigir un vehículo. De la misma manera, todas las áreas de distancia mínima serían identificadas como obstáculos que se deben evitar.

Usted puede ver el artículo original en -> Webcam Based DIY Laser Rangefinder