You are on page 1of 191

ESCUELA TÉCNICA SUPERIOR DE INGENIERIA (ICAI)

INGENIERO ELECTROMECÁNICO

Desarrollo de un control visual basado en


un sensor Kinect para la navegación
autónoma en un entorno forestal

Autor: Aldo García Regueira


Directora: Ángela Ribeiro Seijas

Madrid

Julio 2015
AUTORIZACIÓN PARA LA DIGITALIZACIÓN, DEPÓSITO Y DIVULGACIÓN EN ACCESO
ABIERTO (RESTRINGIDO) DE DOCUMENTACIÓN

1º. Declaración de la autoría y acreditación de la misma.

El autor D. ALDO GARCÍA REGUEIRA, como ESTUDIANTE de la UNIVERSIDAD PONTIFICIA


COMILLAS (COMILLAS), DECLARA

que es el titular de los derechos de propiedad intelectual, objeto de la presente cesión, en


relación con la obra DESARROLLO DE UN CONTROL VISUAL BASADO EN UN SENSOR KINECT
PARA LA NAVEGACIÓN AUTÓNOMA EN UN ENTORNO FORESTAL1, que ésta es una obra
original, y que ostenta la condición de autor en el sentido que otorga la Ley de Propiedad
Intelectual como titular único o cotitular de la obra.

En caso de ser cotitular, el autor (firmante) declara asimismo que cuenta con el
consentimiento de los restantes titulares para hacer la presente cesión. En caso de previa
cesión a terceros de derechos de explotación de la obra, el autor declara que tiene la oportuna
autorización de dichos titulares de derechos a los fines de esta cesión o bien que retiene la
facultad de ceder estos derechos en la forma prevista en la presente cesión y así lo acredita.

2º. Objeto y fines de la cesión.

Con el fin de dar la máxima difusión a la obra citada a través del Repositorio institucional de la
Universidad y hacer posible su utilización de forma libre y gratuita ( con las limitaciones que
más adelante se detallan) por todos los usuarios del repositorio y del portal e-ciencia, el autor
CEDE a la Universidad Pontificia Comillas de forma gratuita y no exclusiva, por el máximo plazo
legal y con ámbito universal, los derechos de digitalización, de archivo, de reproducción, de
distribución, de comunicación pública, incluido el derecho de puesta a disposición electrónica,
tal y como se describen en la Ley de Propiedad Intelectual. El derecho de transformación se
cede a los únicos efectos de lo dispuesto en la letra (a) del apartado siguiente.

3º. Condiciones de la cesión.

Sin perjuicio de la titularidad de la obra, que sigue correspondiendo a su autor, la cesión de


derechos contemplada en esta licencia, el repositorio institucional podrá:

1
Especificar si es una tesis doctoral, proyecto fin de carrera, proyecto fin de Máster o cualquier otro
trabajo que deba ser objeto de evaluación académica

1
(a) Transformarla para adaptarla a cualquier tecnología susceptible de incorporarla a internet;
realizar adaptaciones para hacer posible la utilización de la obra en formatos electrónicos, así
como incorporar metadatos para realizar el registro de la obra e incorporar “marcas de agua”
o cualquier otro sistema de seguridad o de protección.

(b) Reproducirla en un soporte digital para su incorporación a una base de datos electrónica,
incluyendo el derecho de reproducir y almacenar la obra en servidores, a los efectos de
garantizar su seguridad, conservación y preservar el formato. .

(c) Comunicarla y ponerla a disposición del público a través de un archivo abierto institucional,
accesible de modo libre y gratuito a través de internet.2

(d) Distribuir copias electrónicas de la obra a los usuarios en un soporte digital. 3

4º. Derechos del autor.

El autor, en tanto que titular de una obra que cede con carácter no exclusivo a la Universidad
por medio de su registro en el Repositorio Institucional tiene derecho a:

a) A que la Universidad identifique claramente su nombre como el autor o propietario de los


derechos del documento.

b) Comunicar y dar publicidad a la obra en la versión que ceda y en otras posteriores a través
de cualquier medio.

c) Solicitar la retirada de la obra del repositorio por causa justificada. A tal fin deberá ponerse
en contacto con el vicerrector/a de investigación (curiarte@rec.upcomillas.es).

d) Autorizar expresamente a COMILLAS para, en su caso, realizar los trámites necesarios para
la obtención del ISBN.

2
En el supuesto de que el autor opte por el acceso restringido, este apartado quedaría redactado en los
siguientes términos:

(c) Comunicarla y ponerla a disposición del público a través de un archivo institucional, accesible de
modo restringido, en los términos previstos en el Reglamento del Repositorio Institucional

3
En el supuesto de que el autor opte por el acceso restringido, este apartado quedaría eliminado.

2
d) Recibir notificación fehaciente de cualquier reclamación que puedan formular terceras
personas en relación con la obra y, en particular, de reclamaciones relativas a los derechos de
propiedad intelectual sobre ella.

5º. Deberes del autor.

El autor se compromete a:

a) Garantizar que el compromiso que adquiere mediante el presente escrito no infringe ningún
derecho de terceros, ya sean de propiedad industrial, intelectual o cualquier otro.

b) Garantizar que el contenido de las obras no atenta contra los derechos al honor, a la
intimidad y a la imagen de terceros.

c) Asumir toda reclamación o responsabilidad, incluyendo las indemnizaciones por daños, que
pudieran ejercitarse contra la Universidad por terceros que vieran infringidos sus derechos e
intereses a causa de la cesión.

d) Asumir la responsabilidad en el caso de que las instituciones fueran condenadas por


infracción de derechos derivada de las obras objeto de la cesión.

6º. Fines y funcionamiento del Repositorio Institucional.

La obra se pondrá a disposición de los usuarios para que hagan de ella un uso justo y
respetuoso con los derechos del autor, según lo permitido por la legislación aplicable, y con
fines de estudio, investigación, o cualquier otro fin lícito. Con dicha finalidad, la Universidad
asume los siguientes deberes y se reserva las siguientes facultades:

a) Deberes del repositorio Institucional:

- La Universidad informará a los usuarios del archivo sobre los usos permitidos, y no garantiza
ni asume responsabilidad alguna por otras formas en que los usuarios hagan un uso posterior
de las obras no conforme con la legislación vigente. El uso posterior, más allá de la copia
privada, requerirá que se cite la fuente y se reconozca la autoría, que no se obtenga beneficio
comercial, y que no se realicen obras derivadas.

- La Universidad no revisará el contenido de las obras, que en todo caso permanecerá bajo la
responsabilidad exclusiva del autor y no estará obligada a ejercitar acciones legales en nombre
del autor en el supuesto de infracciones a derechos de propiedad intelectual derivados del
depósito y archivo de las obras. El autor renuncia a cualquier reclamación frente a la
Universidad por las formas no ajustadas a la legislación vigente en que los usuarios hagan uso
de las obras.

- La Universidad adoptará las medidas necesarias para la preservación de la obra en un


futuro.

3
ESCUELA TÉCNICA SUPERIOR DE INGENIERIA (ICAI)
INGENIERO ELECTROMECÁNICO

Desarrollo de un control visual basado en


un sensor Kinect para la navegación
autónoma en un entorno forestal

Autor: Aldo García Regueira


Directora: Ángela Ribeiro Seijas

Madrid

Julio 2015
Desarrollo de un control visual basado en un sensor Kinect
para la navegación autónoma en un entorno forestal

Autor: García Regueira, Aldo


Directora: Ribeiro Seijas, Ángela
Entidad colaboradora: Centro de Automática y Robótica - (CSIC-UPM)

RESUMEN DEL PROYECTO

Introducción

La robótica es una rama de la tecnología, se ocupa del estudio y funcionamiento de los


robots, mediante la manufactura y las aplicaciones de éstos.
Los robots son un grandes aliados en la realización de tareas repetitivas, que requieran
una alta precisión o se lleven a cabo en entornos adversos para el ser humano; estando
presentes en una amplia variedad de campos, desde robots quirúrgicos, brazos
mecánicos en líneas de montaje, robots enviados al espacio para la exploración, aviones
no tripulados etc.
Estos avances podrán producir en un futuro una mayor industrialización en ciertas áreas
como la agrícola, al asistir al operario a gestionar el cultivo, ya sea con tareas de
inspección o de tratamiento de cultivos, simplificando sus tareas, reduciendo costes y
aumentando la productividad
De la misma forma que el salto de animales de tiro a tractores, produjo grandes
desarrollos en la agricultura, por medio de la robótica se busca optimizar el guiado y la
gestión de las máquinas empleadas. [1]
Por tanto, el objetivo de este proyecto es hacer posible la navegación autónoma y segura
de un vehículo en entornos con árboles, como son los forestales o las zonas dedicadas al
cultivo de árboles con o sin frutos. El vehículo deberá recorrer una zona o un cultivo
con cobertura total, realizando tareas de inspección, para ello, será esencial disponer de
un sistema sensorial adecuado que le permita construir una imagen aproximada de su
entorno; se propone el uso de una cámara de profundidad, y en concreto del sensor
Kinect como base del desarrollo del sistema de guiado del vehículo, ya que dispone de
una aceptable velocidad de reacción para un rango medio (un orden de magnitud de
varios metros) a un precio bastante asequible en comparación con otros dispositivos.
Metodología

Tomando como base del control visual el sensor Kinect para obtener los datos del
entorno en tiempo real y elaborar un mapeado tridimensional, necesario para sentar las
bases de la navegación autónoma y poder generar las órdenes para guiar al vehículo.
El proceso seguido (tal y como es mostrado en la figura 1) consiste en procesar las
imágenes de color y profundidad del entorno, obtenidas por medio del sensor Kinect,
para recrear el entorno en tres dimensiones.

Figura 1. Proceso seguido [2][3][4]


Esta información del entorno, será tratada en el compilador de Visual Studio, aquí se
necesita recrear la escena a partir de los fotogramas que se vayan capturando en tiempo
real; por lo que es necesario emplear herramientas como OpenCV, más especializadas
en el campo de visión por ordenador, que permiten relacionar dos fotogramas distintos
mediante los puntos de interés (keypoints), cuanto más fuerte sea la relación de los
puntos de interés entre los dos fotogramas, mejor definida estará la escena, esto se
consigue creando una imagen panorámica formada por los fotogramas base
proporcionados por el sensor, y localizando dichos fotogramas en la panorámica,
obteniendo así las relaciones espaciales ente ellos, tal y como muestra la figura 2.
Figura 2, Panorámica y localización
Estas relaciones espaciales entre los distintos fotogramas, se van guardando, junto con
los valores de color y profundidad, en una matriz global, que almacena la nube de
puntos de todo el entorno, partiendo del fotograma base y añadiendo los siguientes
fotogramas, con las traslaciones calculadas previamente.
Con la escena ya totalmente determinada, es necesario representar la nube de puntos,
para ello se dispondrá de la herramienta de OpenGL, especializada en aplicaciones de
vectores gráficos. Para una mejor representación, se aplica una rotación a la escena
tridimensional mostrada y también la posibilidad de cambiar de escala, ya que el rango
inicial del display puede no ser suficiente para escenas de gran tamaño.

Resultados

Para determinar la viabilidad del proyecto, se han realizado a lo largo del trabajo varios
experimentos que se detallan a continuación. En primer lugar se realizaron pruebas al
sensor Kinect para comprobar su funcionamiento en entornos exteriores con árboles, sin
embargo, la imagen de profundidad proporcionada en condiciones de alta intensidad
luminosa, no era suficientemente fiable para desarrollar un control visual; por otra parte,
se llevaron a cabo experimentos para comparar la última versión del Kinect (Kinect
One) con el Kinect 360, que es el usado en este proyecto, aprobando el uso del nuevo
Kinect para entornos exteriores.
Debido a ciertos problemas con la velocidad de proceso, se realizaron experimentos
sobre la creación de la escena, mostrando poca fiabilidad a la hora de detectar los
fotogramas base en la panorámica y largos tiempos de procesamiento, que impiden que
el programa pueda trabajar a tiempo real.
Finalmente se logra representar con éxito la escena tridimensional (figura 3), sin
embargo, los cálculos para la localización espacial de los fotogramas, no son
suficientemente precisos para formar un mapeado detallado.

Figura 3 Escena tridimensional [5][6]


Conclusiones

Se ha desarrollado un programa basado en el sensor Kinect, que intenta responder a la


necesidad de la navegación autónoma de un vehículo, el programa procesa los datos
proporcionados por el sensor y localiza espacialmente los fotogramas, recreando con
éxito el mapeado tridimensional del entorno, sin embargo, problemas como la precisión
de cálculos o el largo tiempo de proceso, impiden que el programa funcione en tiempo
real, impidiendo satisfacer la necesidad pedida.

Referencias
[1] Revista ambienta, Agricultura de precisión
http://www.revistaambienta.es/WebAmbienta/marm/Dinamicas/secciones/articul
os/AP.htm
[2] Logo de Microsoft Visual Studio
https://www.visualstudio.com/
[3] Logo de OpenCV
http://opencv.org/
[4] Logo de OpenGL
https://www.opengl.org/
[5] Vídeo de la escena, disponible en YouTube
https://youtu.be/TM1jzjGJ7K0
[6] Vídeo de la escena, disponible en YouTube
https://youtu.be/eR4S4tpCaIE
Development of a visual control based on a Kinect sensor
for the autonomous navigation through a forest
environment

Author: García Regueira, Aldo


Director: Ribeiro Seijas, Ángela
Collaborating organization: Centro de Automática y Robótica - (CSIC-
UPM)

ABSTRACT

Introduction

Robotics is a branch of technology which deals with the study and functioning of
robots, along with their design, construction and use.
Robots are great allies in the performance of repetitive tasks which require high
accuracy or which take place in hostile environments for human beings. They can be
found in a wide variety of fields, going from surgical robots and mechanical arms in
assembly lines to space explorer robots or unmanned aircrafts.
These developments will produce a greater industrialization in some fields such as
agriculture, by assisting the operator on managing the crops, both in terms of crops
inspection or crops treatment tasks. It will simplify these tasks, decrease the costs and
increase the productivity.
Just like what happened with the leap from draft animals to tractors, which caused great
developments in agriculture, the main aim of robotics is to optimize the guiding and
management of the machines which are utilized. [1]
Therefore, the objective of this project is making the autonomous and safe navigation of
a vehicle possible in environments with trees, such as forests or tree cropping areas,
whether with or without fruit. The vehicle must go across an area or a crop with total
coverture, carrying out inspection tasks; for this, it will be essential to have a suitable
sensorial system which allows to construct an approximate image of its surroundings;
the Kinect sensor is proposed as the key element for the development of the guiding
system of the vehicle, because it provides an acceptable reaction speed for a medium
range (several meters) at a reasonable price if compared to other devices.
Methodology

Taking the Kinect sensor as the base of the visual control for getting the data of the
surroundings in real time and creating a tridimensional mapping, which is necessary for
setting the bases of the autonomous navigation and for being able to produce the
instructions for guiding the vehicle
The proceedings (as showed in figure 1) consist in the treatment of the Depth and Color
Image of the environment, which are obtained through the Kinect sensor, for the
recreation of an spatial representation of the surroundings.

Figure 1. Proceedings [2][3][4]


This information of the surroundings will be treated in the Microsoft Visual Studio
compiler, recreating the scene from the frames captured in real time; so, the use of tools
such as OpenCV is mandatory, due to the need of more specialized programs in the
field of computer vision, allowing to relate two different frames through the points of
interest (keypoints). The stronger the relation between two frames is, the better the
scene is recreated; this is achieved by creating a panoramic view composed by the two
base frames provided by the sensor and by locating those frames in the panoramic
scene, getting through this proceeding, then, the spatial relations between the two base
frames, as shown in figure 2.
Figure 2, Panoramic and location
These spatial relations between two frames are saved along with the values of color and
depth of each image in a global matrix which stores the point cloud of the entire
environment, starting from the initial frame and adding the next frames with the
movements previously computed.
With the surroundings finally defined, it is necessary to represent the point cloud; for
this, the OpenGL tool is used. This tool is specialized in graphic vectors applications.
For a better display, a rotation is applied to the tridimensional scene and there is also the
possibility to change the scale in case that the initial size of the displayed figures may
not be adequate for bigger scenes.

Results

For determining the viability of the project, several experiments have been carried out
The details of these experiments are the ones which go next:
First of all, some tests were carried out for verifying the functioning of the Kinect
sensor outdoors, in spaces without trees; however, the depth image given by the sensor
in cases of high light intensity conditions was not reliable enough for developing a
visual control. Besides, certain tests were also carried out to compare the newest version
of Kinect (Kinect One) with Kinect 360, which is the one utilized in this project; the
results where favorable for the new one, showing its reliability outdoors.
Due to certain problems with processing speed, experiments involving the creation of
the panoramic image were executed, showing low reliability when it came to the
detection of the base frames in the panoramic image and also showing long processing
times, which make functioning in real time impossible for the program.
Finally the tridimensional scene is successfully displayed (figure 3); however, the
calculations required for the spatial location of the frames are not accurate enough to
create a detailed mapping.

Figure 3 Tridimensional scene [5][6]


Conclusions

A program which intends to solve the need for the autonomous navigation of a vehicle
has been developed using the Kinect sensor. The program processes the data provided
by the sensor and spatially locates the frames; this way, it successfully recreates the
tridimensional mapping of the surroundings. However, certain problems related to the
accuracy of calculations or to the long time of processing make it impossible for the
program to work in real time, and this does not allow the program to fulfill the
requested need.

References
[1] Ambienta Magazine, mechanization on agriculture
http://www.revistaambienta.es/WebAmbienta/marm/Dinamicas/secciones/articul
os/AP.htm
[2] Microsoft Visual Studio
https://www.visualstudio.com/
[3] OpenCV Logo
http://opencv.org/
[4] OpenGL Logo
https://www.opengl.org/
[5] Scene video, available on YouTube
https://youtu.be/TM1jzjGJ7K0
[6] Scene video, available on YouTube
https://youtu.be/eR4S4tpCaIE
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

ÍNDICE DE LA MEMORIA

Índice de la memoria

Parte I Memoria descriptiva ....................................................................... 7

Capítulo 1 Introducción ................................................................................... 9

1.1 Estudio de las tecnologías existentes .................................................................. 10

1.2 Motivación del proyecto...................................................................................... 12

1.3 Objetivos .............................................................................................................. 12

1.4 Metodología desarrollada ................................................................................... 13

1.5 Recursos / herramientas empleadas .................................................................. 14

Capítulo 2 Desarrollo ..................................................................................... 15

2.1 Esquema general.................................................................................................. 15

2.2 Extracción de datos del entorno ......................................................................... 17

2.2.1 Qué es y cómo funciona el Kinect ................................................................... 17

2.2.2 Software del Kinect ......................................................................................... 20

2.2.3 Extracción de datos ......................................................................................... 26

2.3 Tratamiento de imagen y obtención de panorámica ........................................ 30

2.3.1 OpenCV y el formato Mat ............................................................................... 30

2.3.2 RGB y RGBA .................................................................................................. 32

2.3.3 Stitching........................................................................................................... 34

2.3.4 Localización en la escena ................................................................................ 37

2.3.5 Posicionamiento en la escena .......................................................................... 39

2.3.6 Mat_Omega, la matriz de almacenamiento ..................................................... 42

2.3.7 Giro, rotación y traslación en los nuevos fotogramas ..................................... 44

2.4 Tratamiento del mapa de bits en 3D .................................................................. 50


UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

ÍNDICE DE LA MEMORIA

2.4.1 Las bases de la representación 3D, OpenGL ................................................... 50

2.4.2 Creando la nube de puntos .............................................................................. 52

Capítulo 3 Resultados/Experimentos ............................................................. 61

3.1 Experimentos de extracción de datos ................................................................ 61

3.1.1 El Kinect en exteriores, para diversos grados de iluminación ......................... 61

3.1.2 El Kinect One frente al Kinect 360 ................................................................. 63

3.1.3 Detección de cristales ...................................................................................... 65

3.2 Experimentos en la creación de la escena ......................................................... 67

3.2.1 Funcionamiento de Homography .................................................................... 67

3.2.2 Funcionamiento de Stitching ........................................................................... 70

3.2.3 Stitching en escenas luminosas ....................................................................... 82

3.2.4 Stitching en escenas no estáticas ..................................................................... 82

3.3 Experimentos y resultado en el espacio tridimensional ................................... 85

3.3.1 Análisis de las herramientas disponibles en el espacio tridimensional ........... 85

3.3.2 Representación de un fotograma ..................................................................... 90

3.3.3 Recreación de la escena tridimensional ........................................................... 92

Capítulo 4 Conclusiones ................................................................................. 97

Capítulo 5 Futuros desarrollos ...................................................................... 99

Bibliografía................................................................................................................ 103

Parte II Estudio económico...................................................................... 107

Parte III Presupuesto ................................................................................. 111

Capítulo 1 Mediciones .................................................................................. 113

1.1 Componentes de Hardware y herramientas .................................................. 113

1.2 Componentes de Software ............................................................................... 114

1.3 Mano de obra directa ....................................................................................... 114


UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

ÍNDICE DE LA MEMORIA

Capítulo 2 Precios unitarios ......................................................................... 115

2.1 Componentes de Hardware y herramientas ................................................. 115

2.2 Componentes de Software .............................................................................. 115

2.3 Mano de obra directa ...................................................................................... 116

Capítulo 3 Sumas Parciales.......................................................................... 117

3.1 Componentes de Hardware y herramientas ................................................. 117

3.2 Componentes de Software .............................................................................. 118

3.3 Mano de obra directa ...................................................................................... 118

Capítulo 4 Presupuesto General .................................................................. 119

Parte IV Código fuente .............................................................................. 121

Parte V Manual del usuario .................................................................... 157

Capítulo 1 Instalación de librerías ............................................................... 159

1.1 Instalación de OpenCV .................................................................................... 159

1.1 Instalación de OpenGL .................................................................................... 163

Capítulo 2 Funcionamiento del programa .................................................. 165


UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Memoria

Índice de tablas

Tabla 1 Tiempo Homography ............................................................................... 69


Tabla 2 Tiempo Stitching ...................................................................................... 81
Tabla 3 Medición de Hardware ........................................................................... 113
Tabla 4 Medición de Software ............................................................................ 114
Tabla 5 Medición de mano de obra ..................................................................... 114
Tabla 6 Precio de Hardware ................................................................................ 115
Tabla 7 Precio de Software ................................................................................. 116
Tabla 8 Precio de mano de obra .......................................................................... 116
Tabla 9 Suma de Hardware ................................................................................. 117
Tabla 10 Suma de Software................................................................................. 118
Tabla 11 Suma de mano de obra ......................................................................... 118
Tabla 12 Presupuesto general .............................................................................. 119
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

ÍNDICE DE FIGURAS

Índice de figuras

Figura 1. Sensores para la conduccion autónoma (Nissan) ................................... 10


http://www.coches.net/noticias/coches-sin-conductor

Figura 2. Sistema sensorial del robot de la universidad de Almería ..................... 11


http://www.ual.es/personal/rgonzalez/papers/279.pdf

Figura 3. Mars Rover............................................................................................. 11


http://mars.nasa.gov/msl/mission/instruments/

Figura 4. Esquema de metodología ...................................................................... 14


Figura 5. Esquema del desarrollo. ......................................................................... 16
Figura 6. Visión Binocular .................................................................................... 17
http://blog.panasonic.es/tecnologia/tecnologia-3d-a-fondo/
Figura 7. Sensor Kinect ......................................................................................... 19
http://support.xbox.com/es-ES/xbox-360/kinect/kinect-sensor-components
Figura 8. Escáner de luz 3D .................................................................................. 20
https://en.wikipedia.org/wiki/Structured-light_3D_scanner
Figura 9. Kinect SDK V 1.8 .................................................................................. 21
https://www.microsoft.com/en-us/download/details.aspx?id=40278

Figura 10. Kinect Studio, Panel Central ................................................................ 21


Figura 11. Kinect Studio, Color ............................................................................ 22
Figura 12. Kinect Studio, Profundidad .................................................................. 22
Figura 13. Kinect Studio, Color y Profundidad..................................................... 23
Figura 14. Depth D2D-Origen ............................................................................... 24
Figura 15. Kinect Explorer D2D-Origen ............................................................... 25
Figura 16. Imagen Reflejo ..................................................................................... 25
http://www.disfrutalasmatematicas.com/geometria/images/reflect-labels.gif
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

ÍNDICE DE FIGURAS

Figura 17. Entorno Visual Studio .......................................................................... 26


https://www.visualstudio.com/en-us/products/visual-studio-ultimate-with-msdn-vs.aspx

Figura 18. Paleta RGB........................................................................................... 31


http://www.informatikzentrale.de/rgb-farbmodell.html
Figura 19. RGB formato Mat ................................................................................ 31
http://docs.opencv.org/doc/tutorials/core/mat_the_basic_image_container
Figura 20. Color RGBA error................................................................................ 33
Figura 21. RGB omitiendo capa alpha .................................................................. 34
Figura 22. Imágenes 30º Stitching......................................................................... 35
Figura 23. Stitiching image, escena....................................................................... 36
Figura 24. Las aristas y el origen .......................................................................... 40
Figura 25. Esquema proceso ................................................................................. 43
Figura 26. Intersección de fotogramas .................................................................. 44
Figura 27. Dentro o fuera de un polígono ............................................................. 45
Figura 28. Determinacion de ángulos .................................................................... 48
Figura 29. Representacion tridimensional estática ................................................ 53
Figura 30. Imagen de la representación estática.................................................... 53
Figura 31. Localizacion del sensor en la escena 3D.............................................. 54
Figura 32. Rotacion de la figura 3D ...................................................................... 55
Figura 33. Representación tridimensional, errores marcados ............................... 56
Figura 34. Recreacion de la escena ....................................................................... 57
Figura 35. . Diferencias de reescalado, imagen pequeña y base ........................... 59
Figura 36. Diferencias de reescalado, imagen grande ........................................... 59
Figura 37. Exterior diurno ..................................................................................... 62
Figura 38. Exterior anocheciendo ......................................................................... 62
Figura 39. Exterior noche cerrada ......................................................................... 63
Figura 40. Kinect One, exterior ............................................................................. 64
Figura 41. Kinect 360, exterior ............................................................................. 65
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

ÍNDICE DE FIGURAS

Figura 42. Detección del cristal 1 .......................................................................... 66


Figura 43. Detección del cristal 2 .......................................................................... 66
Figura 44. Fotogramas Homography..................................................................... 67
Figura 45. Homography errónea ........................................................................... 68
Figura 46. Homography correcta........................................................................... 68
Figura 47. Stitching frente a Homography ............................................................ 69
Figura 48. Imágenes base-ligero desplazamiento.................................................. 70
Figura 49. Stitching-ligero desplazamiento........................................................... 71
Figura 50. Localización-ligero desplazamiento .................................................... 71
Figura 51. Imágenes base-avance .......................................................................... 72
Figura 52. Imágenes base-arriba 1 ........................................................................ 72
Figura 53. Imágenes base-arriba 2 ........................................................................ 73
Figura 54. Stitching-arriba 2 ................................................................................. 73
Figura 55. Localización-arriba 2 ........................................................................... 74
Figura 56. Imágenes base-abajo ............................................................................ 75
Figura 57. Stitching-abajo ..................................................................................... 75
Figura 58. Localización-abajo ............................................................................... 76
Figura 59. Imágenes base-derecha ........................................................................ 77
Figura 60. Stitching-derecha ................................................................................. 77
Figura 61. Localización-derecha ........................................................................... 78
Figura 62. Imágenes base-izquierda ...................................................................... 78
Figura 63. Stitching-izquierda ............................................................................... 79
Figura 64. Localización-izquierda ......................................................................... 80
Figura 65. Stitching-luz ......................................................................................... 82
Figura 66. Imágenes base-imágenes no estáticas .................................................. 83
Figura 67. Stitching-imágenes no estáticas ........................................................... 83
Figura 68. Localización-imágenes no estáticas ..................................................... 84
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

ÍNDICE DE FIGURAS

Figura 69. Traslación y ejes .................................................................................. 86


Figura 70. Rotación eje X...................................................................................... 86
Figura 71. Rotación eje Y...................................................................................... 87
Figura 72. Normal vs grande ................................................................................. 88
Figura 73. Normal vs pequeño vs más pequeño .................................................... 88
Figura 74. Imagen límite ....................................................................................... 89
Figura 75. Representación tridimensional-Resultado 1 ........................................ 90
Figura 76. Representación tridimensional-Resultado 2 ........................................ 90
Figura 77. Escena formada con tres fotogramas ................................................... 92
Figura 78. Segunda escena formada por tres fotogramas ...................................... 93
Figura 79. Escena formada por dos fotogramas .................................................... 94
Figura 80. Escena formada por dos fotogramas, vista perpendicular ................... 95
Figura 81. Escena formada por dos fotogramas, vista posterior ........................... 96
Figura 82. Distición de objetos en el mapeado tridimensional ........................... 101
http://www.pointclouds.org/blog/gsoc12/cpotthast/index.php
Figura 83. Configuración Avanzada del Sistema ................................................ 159
Figura 84. Variables de entorno .......................................................................... 160
Figura 85. Editando las variables de entorno ...................................................... 161
Figura 86. Propiedades ........................................................................................ 162
Figura 87. C/C++ General ................................................................................... 162
Figura 88. Directorio de Bibliotecas Adicionales ............................................... 163
Figura 89. C\C++ Editar ...................................................................................... 164
Figura 90. Vinculador General ............................................................................ 164
Figura 91. Visual Studio Compilar...................................................................... 165
Figura 92. Kinect Explorer D2D ......................................................................... 166
Figura 93. Representación 3D ............................................................................. 167
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Parte I MEMORIA

7
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

8
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Introducción

Capítulo 1 INTRODUCCIÓN

La robótica es una rama de la tecnología, se ocupa del estudio y


funcionamiento de los robots, mediante la manufactura y las aplicaciones
de éstos.

El concepto de crear maquinas que puedan operar de forma autónoma


parte de hace tiempo (China Siglo III a.C.), pero está en constante
evolución, además está presente en muchos aspectos de la vida cotidiana,
investigación e industria.

Entre los ejemplos podemos encontrar los robots enviados al espacio para
la exploración, brazos mecánicos en las cadenas de montaje, robots
quirúrgicos, aspiradoras etc.

Los robots son un gran aliado en la realización de tareas monótonas y


repetitivas o en aquellas que requieran de una alta precisión o se lleven a
cabo en entornos adversos como zonas contaminadas o con explosivos,
que en resumen, serian inseguras para un ser humano.

Es tal el crecimiento, que día a día nos llegan nuevas noticias de avances
en el campo de la navegación automática, ya sea en aviones no tripulados,
popularmente conocidos por drones, o en coches que pueden circular sin
ayuda humana por carreteras o incluso en la conducción sin piloto de un
tractor agrícola. [1]

Estos desarrollos podrán producir en un futuro una mayor


industrialización en ciertas áreas como la agrícola lo que mejorará su
competitividad frente a otros sectores.

El objetivo de este proyecto es hacer posible la navegación autónoma y


segura de un vehículo en entornos con árboles, como son los forestales o
las zonas dedicadas al cultivo de arboles con o sin frutos. El vehículo
deberá recorrer una zona o un cultivo con cobertura total, realizando

9
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Introducción

tareas de inspección, para ello, será esencial disponer de un sistema


sensorial adecuado que le permita construir una imagen aproximada de su
entorno.

1.1 ESTUDIO DE LAS TECNOLOGÍAS EXISTENTES

La mayoría de robots de navegación autónoma emplean cámaras para


analizar sus alrededores y ser capaces de evitar obstáculos. Algunos usan
un GPS para determinar la localización y evitan obstáculos con sensores
láser [2] otros emplean radares (con un alcance de orden de magnitud de
cientos de metros, como el coche de la figura 1) o cámaras mucho más
potentes.

Figura 1 Sensores para la conducción autónoma (Nissan)

Otros usan sonares en conjunto con una cámara simple (webcam), como
forma de evitar obstáculos [3] [4], como ejemplo, el robot de la figura 2.

10
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Introducción

Figura 2 Sistema sensorial del robot de apoyo en invernaderos de la universidad


de Almería

Estas cámaras (digitales) pueden tener muy baja resolución o muy alta,
pero para una navegación más efectiva, es mejor conocer la profundidad,
y para ello, no sirve con una imagen sin más, que es todo lo que
proporciona una cámara, para tener visión estereoscópica, se requiere
conocer la profundidad, y esto se realiza por medio de más cámaras o
sensores adicionales (infrarrojos por ejemplo), como ejemplo, el Mars
Rover de la figura 3.

Figura 3 Mars Rover

11
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Introducción

El tipo de cámaras y elementos (sensores) que se usen, estarán


determinados por la actividad a la que se quiera aplicar el vehículo,
dependiendo de la precisión, velocidad de proceso, cantidad de datos,
rango etc.

1.2 MOTIVACIÓN DEL PROYECTO

Como la percepción de la profundidad de la escena es un elemento


fundamental para navegar evitando obstáculos y las imágenes RGB son un
buen punto de partida en la detección de las estructuras naturales que
pueden guiar la navegación del vehículo (control visual), se propone el
uso de una cámara de profundidad, y en concreto del sensor Microsoft
KinectTM como base del desarrollo del sistema de guiado del vehículo.

En definitiva, además de la imagen RGB (640×480 32-bit @ 30 fps), el


sensor Kinect suministra una nube de puntos capturados por el sensor de
infrarrojos (320×240 16-bit @ 30 fps) dando lugar a una imagen 3D de la
zona. [4] [5]

El sensor Kinect dispone de una aceptable velocidad de reacción para un


rango medio (un orden de magnitud de varios metros), a un precio
bastante asequible en comparación con otros dispositivos.

1.3 OBJETIVOS

El objetivo se basa en la futura integración de un sensor Kinect en un quad


para la navegación autónoma en entornos de árboles y viñedos.

12
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Introducción

Por tanto el objetivo es construir, con la ayuda del Kinect, una imagen en
tiempo real de la que se puedan extraer características de la escena que
nos permitan en un futuro generar las órdenes para que el vehículo
navegue en el entorno siguiendo la información proveniente de dicho
sensor.

En definitiva el proyecto tiene por objetivo sentar las bases de un control


visual empleando el sensor Kinect como el elemento de percepción.

1.4 METODOLOGÍA DESARROLLADA

En el mapeado tridimensional, es necesario conocer la relación espacial


entre los distintos fotogramas que componen la escena, para ello es
necesaria la representación visual y formar una visión panorámica
además, también se requiere la información de profundidad de dichos
fotogramas para llevar a cabo la representación del entorno en tres
dimensiones, como se muestra en la figura 4.

Para llevar a cabo una navegación autónoma, es necesario un análisis del


entorno por parte del sensor, que proporciona los datos, de imagen
(colores) y profundidad (milímetros).

Una vez concluida y verificada la extracción de datos, se procede a


elaborar la visión del entorno, para ello es necesario conocer la
localización relativa de las imágenes entre sí, consiguiendo una imagen
panorámica del entorno.

Una vez creada la panorámica del entorno y las variaciones de posición


del sensor, se procede a generar un mapa tridimensional de la escena a
partir de los fotogramas con información recibida, además de las imágenes
de profundidad.

13
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Introducción

Figura 4 Esquema metodología

1.5 RECURSOS / HERRAMIENTAS EMPLEADAS

Para este proyecto se ha usado:

Hardware:

- Ordenador portátil

Toshiba Satellite A 500-1EJ

Procesador Intel Core (TM) i3 CPU M330 @2.13GHz 2.13GHz

4GB de RAM Sistema operativo de 64 bits

- Sensor Kinect

- Cable de conexión USB (Kinect-Ordenador)

Software:

- Microsoft Visual Studio Ultimate 2013

- Librería OpenCV

- Librería OpenGL

14
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Capítulo 2 DESARROLLO

2.1 ESQUEMA GENERAL

En esta parte se van a explicar las distintas partes en los que se organiza el
trabajo y la relación entre ellas, siguiendo la figura 5.

El proyecto consiste en el tratamiento de las imágenes proporcionadas por


el sensor Kinect, tanto imagen RGB como de profundidad, para integrar la
capa de percepción en un vehículo de modo que sea capaz de navegar de
forma autónoma, detectando estructuras de interés en su entorno.

El programa consta de varias partes diferenciadas, la obtención de datos


recibidos por las cámaras del Kinect, profundidad y color (o RGB de Red
Green y Blue), el tratamiento de las imágenes de color por medio del
comando Stitching de OpenCV, para obtener una escena panorámica del
entorno, y su posterior representación tridimensional con OpenGL.

El esquema de colores en la figura 5 sirve para identificar la jerarquía de


los bloques, en azul se encuentra el sensor Kinect, el cual procesa la
información recibida del entorno y la convierte en datos que podemos
aprovechar. Estos datos pasan al bloque violeta, donde está el programa
base, en el que asimismo existen bloques correspondientes a las tareas que
se tienen que realizar, rojo para la obtención de la escena panorámica y
verde para su representación en tres dimensiones.

15
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 5 Esquema desarrollo

Todo ello es necesario para conseguir una visión estereoscópica, que es la


que permite recoger información tridimensional, dotando al usuario de
una percepción de la profundidad, esto es, detectando las distancias y los
volúmenes del entorno.

Para ello se requieren al menos dos lentes, situadas en posiciones distintas,


pero que puedan ver la figura objetivo (figura 6), la visión de cada lente
será ligeramente distinta, estas pequeñas diferencias serán procesadas por
el cerebro para determinar la profundidad de la figura en cuestión. [6][7]

16
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 6 Visión binocular

2.2 EXTRACCIÓN DE DATOS DEL ENTORNO

Como ya se ha comentado anteriormente, para la creación del mapeado


tridimensional, se requiere como base la imagen de color y profundidad,
la información necesaria se obtiene por medio del sensor Kinect de
Microsoft.

2.2.1 QUÉ ES Y CÓMO FUNCIONA EL KINECT

Este sensor (originalmente llamado Project Natal) [8], fue diseñado por
Alex Kipman, y Microsoft lo desarrolló durante veinte años, como un
conjunto de sensores detectores de presencia (para responder a los
movimientos físicos), su objetivo inicial era permitir a los usuarios

17
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

interactuar y controlar la consola Xbox sin tener contacto físico con ella,
mediante un interfaz de usuario, por medio de gestos y comandos de voz.

Anunciado por primera vez el 2 de junio de 2009 en la E3 (Electronic


Entertainment Expo) y lanzado al público en 2010 para la consola Xbox
360, no sería hasta el 16 de Junio de 2011, cuando el Kinect podría ser
utilizado desde un ordenador gracias al lanzamiento del Software
Development Kit (SDK) para Windows 7, que permitiría desarrollar
aplicaciones para el Kinect en C++, C# o Visual Basic. [9]

Este SDK ha sufrido varias actualizaciones, incluida una segunda


generación de Kinect, que salió para Xbox One en 2014 (versión 2.0).

En este proyecto se utiliza la primera generación de Kinect, con su


software más desarrollado, la versiona 1.8, (2013). [10]

Las características técnicas que posee son las siguientes:

Kinect 1.8

Campo de visión horizontal 57º

Campo de visión vertical: 43º

Rango de inclinación física: +-27º (el soporte)

Rango de profundidad de 0.8 a 4 metros

Flujo de datos

320x240 a 16 bits de profundidad a 30fps

640*480 bits de color a 30fps

Audio de 16 bit a 16kHz

Sensores:

Lentes de color y sensación de profundidad

Micrófono (con sistema de cancelación de eco)

Ajuste del sensor con su motor de inclinación

18
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Las cámaras identificadas con el 1 en la figura 7 son las encargadas de


suministrar la imagen de profundidad, con una resolución de 640x480
pixeles y una frecuencia de 30Hz.

La cámara identificada con 2 en la figura 7, es la que proporciona la


imagen RGB, también con una resolución de 640x480 pixeles, 32 bits de
color (y una frecuencia de 30Hz).

Además, en la figura 7, se han identificado los micrófonos (3) y una


unidad motorizada de la base (4).

Figura 7 Sensor Kinect

El Kinect es un tipo de escáner de luz estructurada, que se basa en la


proyección de un patrón de luz (Infrarroja) hacia un objeto y desde otro
punto de vista, se capturan esos mismos patrones deformados por las
formas del objeto (figura 8); con esa deformación, se obtiene la distancia
desde cada punto (el emisor y el receptor).Estos focos emisor y receptor
son las cámaras marcadas con un 1 en la figura 7.

19
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 8 Escáner de luz 3D

2.2.2 SOFTWARE DEL KINECT

Para poder trabajar con el sensor, se necesitan los programas adecuados,


en este caso el Software Development Kit de Microsoft (SDK).

La figura 9 muestra el Kinect SDK 1.8 (es la versión que corresponde al


modelo de sensor utilizado en el presente trabajo), que es el software
necesario para empezar a usar el sensor, ya que permite el uso y descarga
de los programas base para trabajar con el sensor Kinect. [11]

20
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 9 Kinect SDK

Los programas empleados en este trabajo fueron: Kinect Studio, Kinect


Depth Basics-D2D C++ y Kinect Explorer-D2D C++.

Kinect Studio: Este programa, actúa paralelamente al programa principal,


y proporciona información al usuario (únicamente) sobre el flujo de datos
del sensor.

Este es el panel central (figura 10), permite hacer grabaciones, y analizar


cada frame de datos que transmite un programa ya activo (es decir, no
puede funcionar por su cuenta).

Figura 10 Kinect Studio-Panel Central

21
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Además del panel central, tiene ventanas secundarias que informan del
color (figura 11) y la profundidad (figura 12), donde las zonas más claras
indican una mayor profundidad

Figura 11 Kinect Studio-Color

Figura 12 Kinect Studio-Profundidad

Como ayuda al usuario, en estas ventanas es posible obtener para un


píxel la información de color (RGB) o de profundidad tan solo situando el
cursor encima de dicho pixel.

22
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Otra ventana secundaria de interés (figura 13) suministra un visor en tres


dimensiones, que puede ser rotado, permitiendo ver la escena desde
distintos ángulos (rotación).

Figura 13 Kinect Studio-Color y Profundidad

Otro programa disponible es el que permite trabajar únicamente con los


valores de profundidad, Kinect Depth Basics-D2D C++. Aunque en un
inicio se considero utilizarlo por su simplicidad, fue desechado al no
permitir la manipulación de datos de color.

Este programa (véase figura 14) devuelve los valores de profundidad en


números de 8 bits, sin embargo, no lo representa de manera uniforme,
debido a que la escala de grises empleada en la imagen no corresponde al
valor de profundidad.

23
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 14 Depth D2D-origen

Finalmente Kinect Explorer-D2D C++: este programa cuyo interfaz se


muestra en la figura 15 es el que se ha utilizado como base en este
proyecto, ya que proporciona información de profundidad y color,
además de indicar la frecuencia de trabajo (frame rate). Asimismo,
proporciona otras funcionalidades que podrán ser útiles en futuros
desarrollos, como la detección de audio y el ángulo de origen de la fuente
del ruido, la detección de personas y un acelerómetro.

24
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 15 Kinect Explorer D2D Origen

Es importante destacar que las imágenes proporcionadas por el sensor,


son imágenes reflejadas, no la imagen de la realidad (véase la figura 16,
A’B’C’ son las imágenes reflejadas frente al triangulo real ABC), no a la
imagen real, por lo que habrá que tenerlo en cuenta, modificando los datos
para poder obtener la imagen real cuando se quiera trabajar con ella.

Figura 16 imagen reflejo

Asimismo es necesario un compilador para poder trabajar con los


programas anteriores. Se ha elegido como entorno integrado de desarrollo
Microsoft Visual Studio Ultimate 2013, por su alta compatibilidad y
versatilidad de librerías.

25
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

La figura 17 ilustra alguna de las ventanas que proporciona este entorno


de desarrollo.

Figura 17 Entorno Visual Studio

En el Kinect SDK (o Kinect Toolkit Browser 1.8) se pueden encontrar los


programas para distintos lenguajes de programación, fundamentalmente
C++ y C#.

En este trabajo se han escogido los programas escritos en C++ que aunque
presenten una interfaz más simple (menos vistosa) a cambio tienen mayor
compatibilidad con otras librerías de tratamiento de imagen, por ejemplo
OpenCV.

2.2.3 EXTRACCIÓN DE DATOS

El software que se ha tomado de partida está compuesto por un gran


número de archivos .cpp y .h, de los cuales inicialmente los más
interesantes son los que trabajan con la imagen RGB y de profundidad.

26
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Así, KinectWindow.cpp actúa casi como el principal, NuiImageBuffer.cpp


contiene el trozo de código donde se procesan los datos de color y
profundidad (este es el trozo de código que sufrirá mas modificaciones).
Por último, NuiColorStream.cpp y NuiDepthStream.cpp son los ficheros
que contienen el código para adquirir los datos del sensor Kinect. Estos
módulos también habrá que cambiarlos para adaptarlos al nuevo uso.

El programa Kinect Explorer-D2D C++ es un bucle constante, en el los


datos se van actualizando por medio de las siguientes funciones:
/// <summary>
/// Process color, depth and skeleton streams
/// </summary>
void KinectWindow::UpdateStreams()
{
//OutputDebugStringA("\n alpha \n");
m_pColorStream->ProcessStreamFrame();
m_pDepthStream->ProcessStreamFrame();
m_pSkeletonStream->ProcessStreamFrame();
}
De cada uno de los ProcessStreamFrame, partimos a las diversas
funciones, donde el propio programa extrae los valores de color y
profundidad, para representarlos en pantalla (figura 13) por ejemplo los
valores de profundidad (en milímetros) vienen de la función
NuiImageBuffer::CopyDepth del archivo NuiImageBuffer.cpp, cuyo
código es el siguiente:
void NuiImageBuffer::CopyDepth(const BYTE* pImage, UINT size, BOOL
nearMode, DEPTH_TREATMENT treatment)
{

// Allocate buffer for color image. If required buffer size hasn't


changed, the previously allocated buffer is returned
UINT* rgbrun = (UINT*)ResetBuffer(m_width * m_height *
BYTES_PER_PIXEL_RGB);
// Initialize pixel pointers to start and end of image buffer
NUI_DEPTH_IMAGE_PIXEL* pPixelRun =
(NUI_DEPTH_IMAGE_PIXEL*)pImage;
NUI_DEPTH_IMAGE_PIXEL* pPixelEnd = pPixelRun + m_srcWidth;//
*m_srcHeight;

Partiendo de esta función, y analizando el programa, se logran extraer los


valores de profundidad asignados al comando depth (la función devuelve

27
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

NUI_DEPTH_IMAGE_PIXEL* pPixelRun de la que por medio de dicho


comando se puede extraer los valores).
USHORT depth = pPixelRun->depth; /// este es el valor
USHORT index = pPixelRun->playerIndex;

Una vez obtenidos dichos valores, se procede a almacenarlos en una

matriz de 640x480, asignando un valor de profundidad a cada pixel. El

almacenamiento de las matrices de profundidad se realiza de la siguiente

manera:
int p = 0;

int l;
int inv_d[640];
int inv_I[640];
for (int k = 0; k <= 479; k++){
l = 0;
for (l = 0; l <= 639; l++){
USHORT depth = pPixelRun->depth;
USHORT index = pPixelRun->playerIndex;

inv_d[l] = depth;
inv_I[l]=index;
pPixelRun++;
}
for (int h = 0; h <= 639; h++){
LUT_depth[frame_complete] = inv_d[639 - h];
LUT_index[frame_complete] = inv_I[639 - h];

++rgbrun;

*rgbrun =
m_depthColorTable[LUT_index[frame_complete]][LUT_depth[frame_complete]];

if (n_image == 1){
LUT_depth_matrixIMPAR[h][k] = LUT_depth[p] *
255 / 1250;
}else{
LUT_depth_matrixPAR[h][k] = LUT_depth[p] * 255
/ 1250;
}
p++;
frame_complete++;
}
}

28
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Para obtener las componentes RGB se utiliza la función


NuiImageBuffer::CopyRGB, que sigue una estructura similar al caso de la
información de profundidad:
void NuiImageBuffer::CopyRGB(const BYTE* pImage, UINT size){

// Allocate buffer for image


UINT* pBuffer = (UINT*)ResetBuffer(m_width * m_height *
BYTES_PER_PIXEL_RGB);

A partir del código anterior los valores se guardan en una variable


llamada m_pBuffer[] que se usara para almacenar en las matrices RGB a
partir del código siguiente:
for (LONG y = 0; y < m_height; ++y){
for (LONG x = 0; x < m_width; ++x){
if (n_image == 1){
LUT_B_matrixIMPAR[x][y] = m_pBuffer[p];
LUT_B_matrix[x][y] = m_pBuffer[p];
p++;
LUT_G_matrixIMPAR[x][y] = m_pBuffer[p];
LUT_G_matrix[x][y] = m_pBuffer[p];
p++;
LUT_R_matrixIMPAR[x][y] = m_pBuffer[p];
LUT_R_matrix[x][y] = m_pBuffer[p];
p++;
p++;
}else{

LUT_B_matrixPAR[x][y] = m_pBuffer[p];
LUT_B_matrix[x][y] = m_pBuffer[p];
p++;
LUT_G_matrixPAR[x][y] = m_pBuffer[p];
LUT_G_matrix[x][y] = m_pBuffer[p];
p++;
LUT_R_matrixPAR[x][y] = m_pBuffer[p];
LUT_R_matrix[x][y] = m_pBuffer[p];
p++;
p++;
}
}
}

En definitiva se utilizan un total de 4 matrices, 3 para almacenar los tres


planos de color y una cuarta para almacenar los valores de profundidad,
(LUT_R_matrix, LUT_G_matrix y LUT_B_matrix, son las matrices de
color).

29
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Los motivos de duplicación (PAR-IMPAR) de las matrices de color y


también las de profundidad; así como el uso de la variable n_image, se
explicarán más adelante, con la creación de la matriz global de datos
(apartado 2.3.6, Mat_Omega, la matriz de almacenamiento).

2.3 TRATAMIENTO DE IMAGEN Y OBTENCIÓN DE

PANORÁMICA

Una vez obtenidos y almacenados los valores de profundidad y color, es


necesario recrear la escena a partir de los fotogramas, para ello
necesitaremos herramientas más especializadas al campo de la visión por
ordenador, la que se ha usado en el presente desarrollo ha sido la librería
OpenCV.

2.3.1 OPENCV Y EL FORMATO MAT

En lo que sigue veremos los fundamentos de OpenCV (Open Source


Computer Vision), que es una librería de programación libre, orientada al
desarrollo de aplicaciones de visión por computador, Esta librería que está
disponible desde hace más de 15 años, está desarrollada por Intel y se
emplea en el desarrollo de software para multitud de campos, desde
sistemas de seguridad hasta sistemas de reconocimiento de objetos [12]

Por otra parte, el formato más común de representación de una imagen en


color es el espacio de color RGB, donde cada píxel tiene asociados tres
valores de intensidad correspondientes a tres planos de color R (Red), G
(Green) y B (Blue), tal como se muestra en la figura18. [13]

30
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Es decir, que cada imagen tiene tres valores en cada pixel,


correspondientes a la intensidad luminosa de cada color base.

Figura 18 Paleta RGB

Una vez tenemos los valores de las imágenes RGB, tenemos que pasarlos
al formato adecuado para trabajar con ellos, en este caso el formato Mat,
que no es más que una versión alterada de una matriz normal, en la que
cada componente de la matriz almacena tres valores, estos valores pueden
ir de 0 a 255 como en la figura 18 o como números decimales entre el 0 y el
1, tal como se muestra en la figura 19. [14]

Figura 19 RGB formato Mat

Para obtener las imágenes, se desarrolla el siguiente código para gestionar


los valores dados por las matrices de color:
void Mat_Image(Mat pImage,int unoo2)
{
for (int rw = 0; rw <479; rw++){
for (int cl = 0; cl < 639; cl++){

31
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Mat paso_punto(1, 1, CV_8UC3,


Scalar(LUT_B_matrix[639-cl][rw], LUT_G_matrix[639-cl][rw],
LUT_R_matrix[639-cl][rw]));
paso_punto.copyTo(pImage.row(rw).col(cl));
}
}
}

Dada la imposibilidad de copiar todos los valores directamente, tengo que


copiar los valores agrupados de tres en tres (Blue, Green y Red),
almacenándose en la matriz imagen, por medio de la función .copyTo().

Es importante resaltar que la imagen obtenida es aquí invertida para que


corresponda con la imagen real.

2.3.2 RGB Y RGBA

El flujo de datos de imagen proporcionado por el Kinect, no es RGB puro,


si no que incluye información sobre la opacidad (capa alpha o de
transparencia) Ahora bien, en nuestro caso, esta información no es
relevante para la construcción de la escena, y además ralentiza
significativamente los cálculos, por lo que se omite del proceso. [15]

En caso de no eliminar la componente de opacidad, el fotograma creado,


quedara algo similar a la figura 20:

32
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 20 Color RGBA error

Una vez corregido ese error, es decir, omitiendo correctamente la capa


alpha, la imagen quedaría como la figura 21.

33
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 21 RGB omitiendo capa alpha

2.3.3 STITCHING

Una vez obtenidos los fotogramas en el formato adecuado, el siguiente


objetivo es localizar la zona de solapamiento de dos imágenes adquiridas
de forma consecutiva, de modo que se pueda recrear la escena entera a
partir de la unión de los dos fotogramas, esto puede realizarse de varias
formas, empleando herramientas como Homography o Stitching.

El método Homography [16] fue el inicialmente usado, debido a su gran


velocidad, sin embargo, a pesar de ser más rápido que el Stitching, el
Homography daba lugar a un mayor número de errores, como la
imposibilidad de unir la segunda imagen en el lado que no fuese el
predeterminado, es decir, en el propio código tenía que ir indicado a qué
lado iba cada imagen, por esto y debido también a algunos problemas

34
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

respecto a la creación de panorámicas que aparecían cuando el nuevo


fotograma estaba ya incluido en la imagen de partida, fue necesario
reconsiderar este método y finalmente aplicar Stitching.

La figura 22 muestra un ejemplo de imágenes de entrada tomadas


mediante el sensor Kinect y convertidas al formato Mat (también fueron
invertidas para coincidir con la realidad). Estas imágenes fueron tomadas
una a continuación de la otra girando ligeramente el sensor.

En la figura 23 se muestra la escena resultante de la función Stitching,


formada por las imágenes de la figura 22, las nuevas dimensiones van a
ser totalmente distintas, y dependerán de posición de cada imagen.

Figura 22 Imágenes 30º Stitching

35
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 23 Stitching image, escena

Es interesante saber que se puede juntar más de dos imágenes en la


imagen final, pero para simplificar las cosas y acortar el tiempo entre
fotogramas, se hacen de dos en dos (esto ralentizaría mucho el proceso de
creación de la escena).

La función desarrollada para conseguir la unión de dos imágenes es la


siguiente:
void StichMix(Mat image1, Mat image2){
vector< Mat > vImg;
vImg.push_back(image1);
vImg.push_back(image2);

Stitcher stitcher = Stitcher::createDefault();

Stitcher::Status status = stitcher.stitch(vImg, Stitch);


}

36
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

2.3.4 LOCALIZACIÓN EN LA ESCENA

Ahora que se ha creado la escena a partir de las imágenes provenientes del


sensor, es necesario saber localizarlas entre sí, es decir, hallar la
localización espacial de la imagen nueva respecto a la previa.

Para esto se hace un recorte de ambas imágenes, estos recortes se han de


localizar en la escena creada con la herramienta Stitching. La localización
de dichos recortes se basa en la detección de los puntos de interés
(“keypoints”) por medio del algoritmo Sift en ambas imágenes (la escena y
el recorte).

Estos puntos de interés son lugares de la imagen que están bien definidos,
tanto matemáticamente como gráficamente en la imagen, y permanecen
estables frente a perturbaciones (filtrado de imagen, cambios de color, su
estructura sigue destacando frente a los demás), aquí se comparan estos
puntos de interés en dos imágenes, y se detecta la correlación ambas.
[16][17]

Para detectar la relación entre los puntos de interés y más adelante


localizar y acotar la región de la escena ocupada por el recorte, se
desarrolla la función llamada fcn_Square.

El inicio de la función, y donde se detectan todos los puntos de interés de


ambas imágenes es el siguiente:
void fcn_Square(Mat queryImg_N, Mat trainImg_N, int BaseorNew){
SiftFeatureDetector detector(400);
vector<KeyPoint> queryKeypoints_N, trainKeypoints_N;
detector.detect(queryImg_N, queryKeypoints_N);
detector.detect(trainImg_N, trainKeypoints_N);
Mat queryDescriptors_N, trainDescriptors_N;
extractor.compute(queryImg_N, queryKeypoints_N,
queryDescriptors_N);
extractor.compute(trainImg_N, trainKeypoints_N,
trainDescriptors_N);
Size size = queryDescriptors_N.size();
size = trainDescriptors_N.size();

37
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Una vez tengo los puntos de interés detectados, para evitar tiempo de
trabajo y posibles errores debidos a pequeñas deformaciones, se hace un
filtrado de puntos de interés, para obtener solo los más relevantes, y que
puedan determinar con certeza la localización del recorte en la escena, por
medio del siguiente código:
BFMatcher matcher(NORM_L2);

vector<DMatch> matches_N;
matcher.match(queryDescriptors_N, trainDescriptors_N, matches_N);
Mat img_matches_N;
drawMatches(queryImg_N, queryKeypoints_N, trainImg_N,
trainKeypoints_N, matches_N, img_matches_N);
vector< DMatch > good_matches;
double min_dist = 100;
for (int i = 0; i < queryDescriptors_N.rows; i++)
{
if (matches_N[i].distance < 3 * min_dist)
{
good_matches.push_back(matches_N[i]);
}
}

Una vez detectados los puntos de interés más importantes, se pasa a


detectar los bordes de la imagen recortada en la escena, para ello se utiliza
el código siguiente:
vector<Point2f> scene_corners(4);
perspectiveTransform(obj_corners, scene_corners, H);
vector<Point2f> obj_N;
vector<Point2f> scene_N;
for (int i = 0; i < good_matches.size(); i++){

obj_N.push_back(queryKeypoints_N[good_matches[i].queryIdx].pt);
scene_N.push_back(trainKeypoints_N[good_matches[i].trainIdx].pt);
}

Mat H = findHomography(obj_N, scene_N, CV_RANSAC);

vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0, 0); obj_corners[1] =
cvPoint(queryImg_N.cols, 0);
obj_corners[2] = cvPoint(queryImg_N.cols, queryImg_N.rows);
obj_corners[3] = cvPoint(0, queryImg_N.rows);
perspectiveTransform(obj_corners, scene_corners, H);

38
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Tras obtener las esquinas de la posición del recorte a buscar dentro de la


escena, se procede a almacenar las coordenadas de la siguiente forma:
int X_coordinate0 = scene_corners[0].x;
int Y_coordinate0 = scene_corners[0].y;
int X_coordinate1 = scene_corners[1].x;
int Y_coordinate1 = scene_corners[1].y;
int X_coordinate2 = scene_corners[2].x;
int Y_coordinate2 = scene_corners[2].y;
int X_coordinate3 = scene_corners[3].x;
int Y_coordinate3 = scene_corners[3].y;

Finalmente, se guardan estas coordenadas en un vector externo a la


función para utilizarlas más adelante.

Es importante notar que la imagen que se va a buscar en la escena


formada mediante Stitching, es un recorte de la imagen original con la que
se formo dicha escena; el tamaño del recorte debe ser ligeramente inferior
al de la foto base (no puede ser superior evidentemente) para poder
localizarla correctamente en la imagen conjunta (escena) pero tampoco
puede ser muy pequeña ya que esto podría conducir a la aparición de
varias coincidencias y en consecuencia, a la perdida (o debilitamiento) de
puntos de interés, resultando en una localización errónea o inexistente.

2.3.5 POSICIONAMIENTO EN LA ESCENA

Tras obtener la localización de las imágenes que conforman la escena (los


dos recortes) en la misma, es necesario conocer la relación entre esas dos
imágenes, de forma que pueda localizar espacialmente la nueva imagen
respecto a la anterior.

De esta forma, es necesario localizar el punto central de ambos recortes, y


así obtener la diferencia de posiciones ente las dos imágenes.

A partir de las aristas que delimitan el área perteneciente a los recortes en


la escena (obtenidas anteriormente, con la función fcn_Square), se puede
determinar el punto central tal y como muestra la figura 24:

39
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 24 Las aristas y el origen

Una vez despejadas las variables , , y de las ecuaciones de la recta,


se procede a calcular el origen de la siguiente manera:
void intersect_central(int vecX[], int vecY[], int select){
long float alfaB_up = (vecY[0] - vecY[2]);
long float alfaB_dw = (vecX[0] - vecX[2]);
long float alfaB = alfaB_up / alfaB_dw;
long float betaB = vecY[0] - alfaB*vecX[0];

///////// ecuacion de los otros puntos


long float gamaB_up = (vecY[1] - vecY[3]);
long float gamaB_dw = (vecX[1] - vecX[3]);
long float gamaB = gamaB_up / gamaB_dw;
long float sigmB = vecY[1] - gamaB*vecX[1];

/// juto los dos


long float x_up = -(betaB - sigmB);
long float x_dw = alfaB - gamaB;
long float x_central = x_up / x_dw;
long float y_central = alfaB*x_central + betaB;

if (select == 0){

X_Base = x_central;
Y_Base = y_central;

}else{
X_New = x_central;
Y_New = y_central;
}
}

La diferencia de puntos centrales, es decir el vector que une el punto


central de la antigua imagen con la siguiente, se calcula mediante la
diferencia de puntos centrales, es decir la diferencia ente el punto central

40
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

de la nueva imagen y el de la imagen previa. Aunque para ello debemos


conocer cuál es la imagen nueva y cuál es la previa.

2.3.6 MAT_OMEGA, LA MATRIZ DE ALMACENAMIENTO

Tras obtener la localización de una segunda imagen, surge el problema de


almacenamiento de los valores, se requiere una variable para almacenar
todos los puntos que deben ser representados, es decir, una matriz global
donde almacenar la nube de puntos.
Esta Matriz global, llamada Mat_Omega, guarda los valores en un punto
por fila, con los datos agrupados de tal forma que en la primera columna
se tiene el numero de punto, en la segunda la coordenada X, seguida por
la coordenada Y y por la coordenada Z; finalmente, se almacenan también
los valores RGB. El origen de las coordenadas XYZ será el origen de la
primera imagen, es decir, la localización del sensor Kinect en el primer
fotograma registrado.

La diferencia en el valor de la coordenada Z frente al valor de


profundidad se considera nula, tanto por la poca diferencia como por el
incremento de tiempo que produciría.

El almacenamiento en una matriz global (llamada Mat_Omega), del


fotograma inicial se hace desarrollando el siguiente código:
for ( int k = 0; k < 480; k++){

for (int l = 0; l <= 640; l++, numero++){


Mat_Omega[numero][0] = numero;

Mat_Omega[numero][1] = -l + 640 / 2;
Mat_Omega[numero][2] = -k + 480 / 2;
Mat_Omega[numero][3] = LUT_depth_matrixPAR[l][k];
Mat_Omega[numero][4] = LUT_1RGB[640 - l][k][0];
Mat_Omega[numero][5] = LUT_1RGB[640 - l][k][1];
Mat_Omega[numero][6] = LUT_1RGB[640 - l][k][2];
}
vueltas++;

41
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Hasta ahora, no había importado el orden de las imágenes que


conformaban la escena, ya que lo único que se ha hecho ha sido adaptarlas
al formato Mat, conformar una escena y localizar las imágenes en dicha
escena, pero ahora es necesario saber cuál es la imagen nueva y cual la
antigua, para ello, nos ayudaremos de unas variables llamadas n_image y
mezcla, ambas con valor inicial 0. Además llamaremos al fotograma base
LUT_1 y al siguiente fotograma LUT_2 (atención, LUT_2 no será
necesariamente el fotograma nuevo, simplemente es el siguiente al
fotograma base y el previo al tercer fotograma que se almacenará en
LUT_1, como se muestra en la figura 25).

En el momento en el que empieza el proceso de reconstrucción n_image


aumenta su valor en 1; se escanea una primera imagen, el fotograma base
(en LUT_1) y se continua con el proceso.

En el siguiente fotograma, n_image se vuelve a incrementar en uno, esta


vez con un valor de 2, se escanea la imagen y se almacena en LUT_2, acto
seguido se procede a cambiar el valor de mezcla a la unidad, esto permite
la unión de las dos imágenes, siendo la imagen antigua LUT_1 y la nueva
LUT_2, cuando n_image es 0 (su valor fue reiniciado justo después de
escanear LUT_2).

En el tercer frame, se aumenta n_image en una unidad, y se procede a


escanear la imagen LUT_1 (sobrescribiendo la LUT_1 anterior), se permite
la reconstrucción con la variable mezcla y formando la imagen conjunta;
como n_image aquí vale 0, se procede analizar la escena sabiendo que
LUT_1 es la nueva y LUT_2 es la antigua, de forma opuesta al anterior.

La figura 25 muestra un esquema detallado del proceso:

42
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Fig25 Esquema proceso

2.3.7 GIRO, ROTACIÓN Y TRASLACIÓN EN LOS NUEVOS FOTOGRAMAS

Para recrear la escena, es necesario determinar donde se encuentran los


nuevos fotogramas respecto a los antiguos, por tanto, además de conocer
la diferencia de centros entre fotogramas (calculada en el apartado 2.3.5),
es necesario conocer el ángulo de giro y la variación de profundidad de los
fotogramas respecto al fotograma inicial.

Esto se logra calculando los puntos que delimitan el área de intersección


de las dos imágenes que conforman la escena, más concretamente los
puntos 2 y 0´de la imagen 26, que muestra un ejemplo de intersección.

43
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 26 Intersección de fotogramas

Para determinar los puntos 2 y 0´de la figura 26, tengo que determinar
cuáles son los puntos del recuadro gris que se encuentran dentro del rojo,
para ello tengo que determinar con cuantos lados del polígono
interseccionan avanzando en la misma dirección (y paralelamente a un
eje), esto se puede apreciar en la figura 27, donde se muestran varios
puntos R.V y N y se aprecia el numero de intersecciones; la prolongación
de los puntos que están dentro del polígono, interseccionan una sola vez
con los lados, mientras que los que no pertenecen al área interna del
polígono, interseccionan dos veces o ninguna.

44
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 27, Dentro o fuera de un polígono

Mediante la siguiente función, se determina si la prolongación del punto


dado intersecciona con la recta hacia el lado derecho (como mostraba la
figura 27).
int inter_recta(int r1, int r2, int w_X, int w_Y){
int rtr = 0;
if (w_Y >= vecY_Base[r2]){ ///la de abajo

if (w_Y <= vecY_Base[r1]){ ///la de arriba


///recta
float C_X = 0;
float alpha1 = 0;

if (vecX_Base[r1] != vecX_Base[r2]){
alpha1 = (vecY_Base[r1] - vecY_Base[r2]) /
(vecX_Base[r1] - vecX_Base[r2]);
}
char szb[255];
sprintf_s(szb, "\n alpha: %f ", alpha1);
float Beta1 = vecY_Base[r1] - alpha1*vecX_Base[r1];
sprintf_s(szb, "\n beta: %f ", Beta1);

if (alpha1!=0){
C_X = (w_Y - Beta1) / alpha1;
}
else{
C_X = vecX_Base[r1];

45
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

sprintf_s(szb, "\n CX: %f ", C_X);

if (w_X <= C_X){


rtr = 1;
///intersecciona
}
}
}
if (w_Y <= vecY_Base[r2]){ ///la de abajo

if (w_Y >= vecY_Base[r1]){ ///la de arriba


///recta
float C_X = 0;
float alpha1 = 0;

if (vecX_Base[r1] != vecX_Base[r2]){

alpha1 = (vecY_Base[r1] - vecY_Base[r2]) /


(vecX_Base[r1] - vecX_Base[r2]);
}
char szb[255];

sprintf_s(szb, "\n X2: %f ", vecX_Base[r1]);

sprintf_s(szb, "\n X3: %f ", vecX_Base[r2]);

sprintf_s(szb, "\n alphaDIF: %f ", alpha1);

float Beta1 = vecY_Base[r1] - alpha1*vecX_Base[r1];


sprintf_s(szb, "\n betaDIF: %f ", Beta1);

if (alpha1 != 0){
C_X = (w_Y - Beta1) / alpha1;
}
else{
C_X = vecX_Base[r1];
}

if (w_X <= C_X){


rtr = 1;
///intersecciona
}
}
}
return rtr;
}

El funcionamiento es similar al proceso realizado en el apartado 2.3.5;


ahora que se si la prolongación de un punto intersecciona con una recta,
por lo que ahora tengo que verificar la prolongación de ese mismo punto.
Una vez que se conocen las intersecciones de dicho punto con las rectas

46
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

que forman el polígono, se determina si el punto está o no dentro de dicho


polígono de la siguiente forma:
int intersec_Punto(float w_X1, float w_Y1){
int rr = 0;

/// wx, primera recta con 0-3

int primera = inter_recta(0,3,w_X1,w_Y1);


OutputDebugStringA("priemro escaneado\n");
/// segunda 1-2

int segunda = inter_recta(1, 2, w_X1, w_Y1);


OutputDebugStringA("segundo escaneado\n");
///tercera 01

int tercera = inter_recta(0, 1, w_X1, w_Y1);


OutputDebugStringA("tercero escaneado\n");
///cuarta 32

int cuarta = inter_recta(3, 2, w_X1, w_Y1);


char sza[255];

sprintf_s(sza, "\n p1: %d ,p2: %d,p3: %d,p4: %d \n ",


primera,segunda, tercera,cuarta);

OutputDebugStringA(sza);
if (primera+segunda+tercera+cuarta==1){
rr = 1;
///pertenece
}
return rr;

Tras repetir el para el otro polígono y para todos los puntos, finalmente
obtengo al menos dos puntos que se encuentran en el área de intersección.
Comparando las diferencias en los valores de profundidad de los puntos
(estos puntos pertenecen a los dos fotogramas al mismo tiempo)
determino el ángulo de giro respecto al eje X y al eje Y, determinándolo a
partir de las diferencias de valores de profundidad y las coordenadas en
X, como se explica en la figura 28, cabe resaltar que ciertas operaciones
trigonométricas, necesarias para realizar los cálculos, ralentizan o incluso
pueden detener el proceso.

47
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 28, determinación de ángulos

A partir de estos ángulos, determino la diferencia de profundidad entre


los puntos centrales, de tal forma que la diferencia que exista entre los
puntos más alejados (la arista de la nueva imagen, Bn-B0 de la figura 28)
sea nula en esos puntos, es la línea amarilla que se aprecia en la figura 28.

Una vez tengo el ángulo de giro, el de rotación, la translación y la


variación de profundidad, voy almacenando estos valores en la matriz
para proceder a su construcción en 3D:
for (int k = 0; k < 480; k++){

for (int l = 0; l <= 640; l++, numero++){

Mat_Omega[numero][0] = numero;

Mat_Omega[numero][1] = -l + 640 / 2 + X_New - X_Base +


centros[cuenta2][0] - (-l + 640 / 2)*(1 - cos(giro));///x

Mat_Omega[numero][2] = -k + 480 / 2 + Y_New - Y_Base +


centros[cuenta2][1] - (-k + 480 / 2)*(1-cos(giro2));///y

Mat_Omega[numero][3] = centros[cuenta2][2] + Z_prof - (-l +


640 / 2)*sin(giro) - (-k + 480 / 2)*sin(giro2);+
LUT_depth_matrixIMPAR[l][k];///z

Mat_Omega[numero][4] = LUT_R_matrixPAR[640 - l][k];///R

48
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Mat_Omega[numero][5] = LUT_G_matrixPAR[640 - l][k];///G

Mat_Omega[numero][6] = LUT_B_matrixPAR[640 - l][k];///B

}
vueltas++;
}

Es importante resaltar que las diferencias, ya sean de traslación, de


profundidad o los ángulos se van acumulando, es decir, si en el primer
fotograma adicional, el giro es de 25º, y en el siguiente es de -15º, el ángulo
de este nuevo fotograma será de 10º (25-15) respecto el fotograma inicial,
que es el valor aplicado en Mat_Omega.

El proceso se repite sobre todas las imágenes que se van adquiriendo,


almacenando las variaciones con respecto a la imagen anterior, y
buscando así la reconstrucción continua de la escena.

49
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

2.4 TRATAMIENTO DEL MAPA DE BITS EN 3D

Ahora que ya se tiene la escena totalmente determinada y la nube de


puntos almacenada hay representar dicha nube de puntos, para ello, hay
multitud de librerías relacionadas, en este proyecto se escoge la
herramienta OpenGL por su versatilidad y su buena compatibilidad con la
representación de nubes de puntos bit a bit.

2.4.1 LAS BASES DE LA REPRESENTACIÓN 3D, OPENGL

OpenGL (Open Graphics Library) es una Aplicación de Interfaz de


Programación (API) multilenguaje para aplicaciones de vectores gráficos
de dos o tres dimensiones, desarrollada por Silicon Graphics en los 90, es
una de las plataformas graficas más utilizadas.

Se emplea en desarrollo de videojuegos, donde compite con DirectX de


Microsoft. [18][19]
Con OpenGL queremos disponer de herramientas que nos permitan
trabajar con la componente de profundidad de la imagen. Así, para cada
fotograma, tenemos los valores de profundidad para cada bit en concreto
una imagen de 640x480 pixeles. Para representarlos en un espacio
tridimensional, necesitamos convertir los valores de profundidad,
(originalmente milímetros) para cada pixel a vectores XYZ.

Con las funciones de OpenGL es posible construir un programa que


interpreta una serie de coordenadas y las representa en el espacio
añadiendo color al punto (es decir, los valores de intensidad asociados a
cada uno de los planos en el espacio de color RGB).

De cada fotograma de imagen tenemos los valores de profundidad, bit a


bit (640x480) Para representarlos necesitamos convertir los valores de

50
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

profundidad (originalmente milímetros) a vectores XYZ para poder ser


representados.

La función desarrollada en este proyecto es la siguiente:

void OpenGL_3D(int argc){

glutInitDisplayMode(GLUT_DOUBLE);
glutInitWindowSize(1280, 960);
glutInitWindowPosition(50, 50);

gluPerspective(45, width / (GLdouble)height, 0.1, 1000);

glutCreateWindow(title);

glutDisplayFunc(display);
glutReshapeFunc(reshape);

initGL();

glutTimerFunc(0, timer, 0);


glutMainLoop();
}

Donde GLUT_DOUBLE indica que se usa la técnica del doble buffer,


necesaria para no tener un grafico estático, y que permitirá en un futuro
trabajar con mayor facilidad con el mapeado tridimensional, ya sea para
girar la figura o para reescalarla; emplea un buffer para pintar y el otro
para visualizar la pantalla.

Los comandos glutDisplayFunc y glutReshapeFunc, son dos callbacks, que


pasan una función cada uno (display y reshape respectivamente) y que la
función llamará cuando considere oportuno. El primero se encarga de
pintar la imagen y el segundo de su escala.

InitGL es el comando que activa la representación, sin él no se mostraría la


ventana del display 3D.

Por otra parte, glutMainLoop es un bucle infinito, (el que mantiene la


ventana del display abierta y actualizada), este bucle genera un grave
problema, ya que interrumpe el programa principal, sin embargo, existen
formas de evitar esto, como rompiendo el bucle editando la librería o
convirtiendo el bucle en el bucle general del programa. Se ha escogido la

51
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

primera opción, ya que es más simple e interfiere menos con el programa


principal. [20]

2.4.2 CREANDO LA NUBE DE PUNTOS

Ahora que se conoce la estructura base de la herramienta OpenGL,


procedo a representar la nube de puntos, dicha nube de puntos esta
almacenada en la matriz global llamada Mat_Omega (apartado 2.3.6).

Como ya se comentó anteriormente, el comando display sirve para pintar


la imagen a partir de los datos que le proporcionemos, en este caso de la
matriz Mat_Omega, que almacena los valores de las escenas, el código
desarrollado es el siguiente:
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -1 * Mat_Omega[3][153600]);
glRotatef(angleCube, 0, 1, 0);
glPointSize(1);

glBegin(GL_POINTS);
for (int i = 0; i < numero;i++){

glColor3f(Mat_Omega[i][4]/255.f, Mat_Omega[i][5]/255.f,
Mat_Omega[i][6]/255.f);

glVertex3f(Mat_Omega[i][1]/3, Mat_Omega[i][2]/3,
Mat_Omega[i][3]/3);

}
glEnd();
glutSwapBuffers();

angleCube -= 0.2;
}

Dada la representación tridimensional obtenida (figura 29), es necesario el


giro de la imagen para una mejor apreciación de la misma, por lo que es
necesario rotar la escena.

52
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 29, representación tridimensional estática

Además, tal y como se ve en la figura 30, la imagen tridimensional,


aparece vista desde atrás, es decir, al otro lado de la figura 3D, se
encuentra el sensor.

Figura 30 Imagen de la representación estática

Para añadir la rotación, se emplean los comandos glTranslate y glRotate,


éstos realizan la translación y la rotación de la matriz. En translación, se
hace retroceder el punto central de la primera imagen un cierto número de

53
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

unidades para que el centro absoluto de rotación no esté en la imagen, si


no el punto correspondiente a la posición del sensor, tal y como muestra la
figura 31, en la que la estrella amarilla representa el punto de rotación y el
sensor.

Figura 31, localización del sensor en la escena 3D

En la rotación se requiere de otro callback, glutTimerFunc, cuya tarea es


llamar a otra función (un timer en este caso) y se encarga de la frecuencia
de llamada de los otros callbacks, en otras palabras, regula la actualización
del la representación tridimensional.

Para indicar el ángulo de rotación, se crea la variable angleCube, que varia


al final de la función (display), e indica cuanto se va a rotar la imagen cada
vez que el callback del timer vuelve a llamar al display, creando una
rotación de la imagen tridimensional, basada en el incremento de ese
ángulo cada vez que el glutTimerFunc lo actualice, tal y como se ve en la
figura 32, en la que la imagen rota sobre el eje rojo, en la imagen de la
derecha, ha pasado cierto número de ciclos y el rectángulo blanco y el
punto que le acompaña, ha rotado.

54
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 32, Rotación de la figura 3D

Ahora que se ha resuelto el problema de la visualización, procedo a


representarlo nuevamente, esta vez, se puede apreciar mejor la escena,
gracias al movimiento de rotación de esta, que permite ver el mapeado
desde todos los ángulos.

Una vez representado, queda como en la figura 33, es importante resaltar


las nubes de puntos resaltadas, estas, son las medidas que el sensor Kinect
toma como erróneas, es decir, les da un valor de profundidad nulo.

55
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 33, Representación tridimensional, errores marcados

Una vez se han eliminando los valores residuales (medidas con valor de
profundidad nulo) detectados antes, se procede a juntar varios fotogramas
y representarlos, como muestra la figura 34; en esta representación, se
puede apreciar un círculo rojo, éste señala áreas que quedan inaccesibles a
la vista (el display tiene un rango limite en la distancia de los puntos), que
se mostraran en el display conforme se vallan acercando.

56
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 34, recreación de la escena [21]

El problema del rango de representación se irá agravando al tener


mapeados más grandes, por lo que se necesita alejar el punto de vista para
tener una mejor visión de la escena, es decir, es necesario reescalar la
escena.

Esto se resuelve añadiendo comandos a la representación tridimensional,


por medio de otro callback, llamado glutKeyboardFuncn, que llama a una
función (de igual manera que la función display en el apartado 2.4.1) que
permite al usuario introducir comandos, estos varian el valor de una
variable (llamada reescalado) de forma que afecte de manera

57
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

inversamente proporcional a las dimensiones espaciales de la nube de


puntos, es decir, cuando el valor del reescalado sea mayor, la escala de la
figura representada será menor; el código creado para solucionar el
problema del reescalado es el siguiente:
void keyboard(unsigned char key, int x, int y){
switch (key)
{
case 'p':
case 'P':
reescalado++;
break;
case 'o':
case 'O':
reescalado = 1;
break;
case 'i':
case 'I':
reescalado = reescalado/2;
break;
case 27: // escape
exit(0);
break;
}

Tal y como se aprecia, al pulsar la tecla “p” la variable reescalado


aumentara, disminuyendo de tamaño la figura, al contrario que al pulsar
la tecla “i”; además al pulsar la tecla “o”, la variable reescalado vuelve a su
valor original y finalmente, si se pulsa la tecla Esc, se termina la
representación.

En la figura 35, se puede apreciar el efecto del reescalado al aumentar la


variable.

58
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Desarrollo

Figura 35 diferencias de reescalado, imagen pequeña y base

Mientras que en la siguiente imagen (figura) se ha disminuido su valor,


resultando una escena mucho más detallada (tanto la figura 35 como la 36
están a la misma escala).

Figura 36 diferencias de reescalado, imagen grande

59
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

60
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Capítulo 3 RESULTADOS/EXPERIMENTOS

En este capítulo, se llevaran a cabo experimentos para determinar la


viabilidad del trabajo, ya que a lo largo del desarrollo han surgido
problemas que dificultaban continuar, es necesario conocer los motivos de
dichos problemas, y como pueden afectar al desarrollo del control visual.

Debido a su naturaleza, se han clasificado según al bloque al que


pertenecen, es decir, a extracción de datos, recreación de la escena o
representación tridimensional.

3.1 EXPERIMENTOS DE EXTRACCIÓN DE DATOS

Aquí se llevaran a cabo los experimentos relacionados con la obtención de


datos del entorno por medio del sensor Kinect.

3.1.1 EL KINECT EN EXTERIORES, PARA DIVERSOS GRADOS DE

ILUMINACIÓN

El quad al que se le quiere añadir el sistema de control visual, va a recorrer


exteriores, por tanto, es necesario realizar pruebas para verificar que el
sensor es capaz de funcionar en estas condiciones, para ello se realizan las
siguientes mediciones(en exteriores) a distintos grados de iluminación:

En la figura 37, la captura se toma en condiciones de máxima intensidad


lumínica, se puede observar que las barras y ciertas partes de la estructura,
aparecen en color verde oscuro (indica 0 milímetros o error), algunas,

61
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

pertenecen a zonas donde se está reflejando la luz del sol, por lo que se
están produciendo pequeños deslumbramientos.

Figura 37 Exterior diurno

En la siguiente figura, tomada con poca intensidad de luz, se aprecian


mejor los contornos de las estructuras, y menos zonas en color verde
oscuro y por supuesto, ninguna zona de deslumbramiento(las superficies
tienen colores más uniformes).

Figura 38 Exterior anocheciendo

62
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Por último, la figura 39 fue tomada durante la noche, sin fuentes de luz, tal
y como se aprecia en la imagen a color, sin embargo, la imagen de
profundidad aparece bien definida, no existen zonas de deslumbramiento
y se perciben perfectamente los contornos de las figuras.

Figura 39 Exterior noche cerrada

A la vista de estos resultados, se concluye que el Kinect que se usa en este


proyecto, es poco apto para entornos con alta intensidad luminosa, sin
embargo, es perfectamente capaz de trabajar en entornos exteriores con
baja intensidad, también funciona de noche, sin embargo, solamente con la
imagen de profundidad, por lo que el programa desarrollado no es capaz
de recrear la escena al no poseer los fotogramas de color.

3.1.2 EL KINECT ONE FRENTE AL KINECT 360

En este apartado se compararán las dos versiones del sensor Kinect, por
un lado, la más reciente, y perteneciente a la segunda generación, el Kinect
One, y por el otro el Kinect 360 que es la versión previa, y el que se usa en
este proyecto.

63
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

El objetivo de este experimento es comparar ambos sensores y determinar


cuál es el más apto para la tarea.

Para ello, se van a tomar capturas en entornos con alta luminosidad (que
como se vio en el apartado 3.1.1, son las que inhabilitan al Kinect 360 para
su uso en exteriores).

La figura 40 muestra la captura del Kinect One, tanto imagen a color como
de profundidad, el Kinect One es capaz de captar la imagen de
profundidad con pocos errores, además de tener una calidad superior.

Figura 40 Kinect One, exterior

Por otra parte, la figura 41, muestra la captura que el sensor Kinect 360 es
capaz de realizar en entornos luminosos, en este caso, el sensor no percibe
imagen de profundidad alguna.

64
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 41 Kinect 360, exterior

Como conclusión, se observa en la comparación que el sensor Kinect One


es superior, ya que es capaz de trabajar en entornos muy luminosos, en los
que el Kinect 360 no puede.

3.1.3 DETECCIÓN DE CRISTALES

Aunque en el entorno forestal al que está destinado el quad, no abundan


los objetos cristalinos o transparentes, resulta conveniente estar preparado
para esta eventualidad.

Por tanto, se realizará el siguiente experimento con el objetivo de


determinar si el sensor es capaz de detectar objetos transparentes.

Se han realizado dos capturas; en la figura 42, se muestra la detección del


cristal aunque con ciertos errores, ya que la imagen de profundidad en la
región del cristal no es estable.

65
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 42 Detección del cristal 1

Mientras que en la figura 43, el sensor no es capaz de detectarlo.

Figura 43 Detección del cristal 2

Por tanto, se observa que el Kinect no es capaz de detectar obstáculos


transparentes con fiabilidad, esto es importante a tener en cuenta para
saber en qué entornos puede o no funcionar.

66
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

3.2 EXPERIMENTOS EN LA CREACIÓN DE LA ESCENA

En esta parte se llevaran a cabo experimentos relacionados con la unión de


fotogramas y la creación de la escena panorámica que ayudará a crear el
mapeado.

3.2.1 FUNCIONAMIENTO DE HOMOGRAPHY

La herramienta Homography fue considerada inicialmente en vez del


Stitching como se cuenta en el apartado 2.3.3, aquí se pretende demostrar
las cualidades y desventajas de dicha herramienta.

Para ello, se capturan las imágenes mostradas en la figura 44, que serán las
que conformen la escena mediante ambas herramientas, para comparar su
efectividad.

Figura 44 Fotogramas Homography

Primeramente se crea la panorámica con Homography, sin embargo, esta


corresponde con la segunda imagen (figura 44 a la derecha), siendo
incapaz de recrear la escena.

67
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 45 Homography errónea

Ahora se han invertido las posiciones de los fotogramas base en el


programa, realizando otra vez la operación de Homography, esta vez se
obtiene la escena con éxito (figura 46).

Figura 46 Homography correcta

Para comparar esta herramienta con la que se usa en este proyecto, se


toma la recreación de la escena por medio de Stitching (figura 47).

68
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 47 Stitching frente a Homography

Además, se ha cronometrado el tiempo que tarda en hacer estas pruebas,


mostrado en la Tabla 1, se han realizado varias pruebas con cada
herramienta, el tiempo mostrado es la media.

Herramienta Tiempo(s)

Homography derecha-izquierda 6.2

Homography izquierda- derecha 6.3

Stitching 11.5

Tabla 1 Tiempo Homography

Se observa que la herramienta Homography es más rápida, sin embargo,


requiere conocer la disposición espacial antes de recrear la escena, esto es
un problema ya que el proceso de recreación de la escena se emplea para
conocer la posición relativa de los fotogramas.

69
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

3.2.2 FUNCIONAMIENTO DE STITCHING

La herramienta seleccionada para recrear la escena es el Stitching, que une


dos fotrogramas y conforma una escena, en esta escena se buscarán
fragmentos de dichos fotogramas para localizarlos y así determinar su
localización relativa, tal y como se explica en los apartados 2.3.3 y 2.3.4.

Entonces es necesario saber cuáles son las capacidades de esta


herramienta, cuando falla y el tiempo que tarda en realizar el proceso,
para ello, se han realizado varios fotogramas con el objetivo de mostrar las
diferentes uniones que se realizarán en el programa.

En la primera prueba, se llevara a cabo la unión de dos imágenes


similares, con muy pequeñas variaciones, las imágenes base empleadas
son las mostradas en la figura 48.

Figura 48 Imágenes base-ligero desplazamiento

Una vez realizado el proceso de Stitching, se obtiene la escena de la figura


49, que no se corresponde demasiado con la realidad.

70
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 49 Stitching-ligero desplazamiento

Sin embargo, a la hora de buscar la localización de los frames base (figura


50), se tienen puntos centrales bastante próximos, por lo que se podrían
obtener resultados precisos.

Figura 50 Localización-ligero desplazamiento

71
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

En la siguiente prueba, se va a simular un avance frontal del sensor, es


decir un acercamiento al objetivo, para ello se emplean las imagens de la
figura 51.

Figura 51 Imágenes base-avance

El resultado de esta prueba es negativo, ya que la función Stitching no es


capaz de devolver la escena, resultado en error y un cierre del programa;
esto mismo sucede con las imágenes de la figura 52, en las que por la poca
correlación entre los puntos de interés de las imágenes, no se puede lograr
la construcción de la panorámica.

Figura 52 Imágenes base-arriba 1

Realizo ahora un experimento similar al anterior, con cuidado de que las


imágenes compartan más zonas en común, este experimento simula la
unión de un fotograma y el que está justo encima de él (Figura 53).

72
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 53 Imágenes base-arriba 2

Ahora que los fotogramas están más próximos, el Stitching es capaz de


crear la escena (Figura 54).

Figura 54 Stitching-arriba 2

Ahora, la escena sale de nuevo deformada, y en la localización de los


fotogramas que la conforman (figura 55), el programa no es capaz de
detectar correctamente el segundo fotograma, proporcionando resultados
erróneos.

73
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 55 Localización-arriba 2

El siguiente experimento se similar al anterior, ya que en vez de jugar con


una imagen superior, se utiliza una inferior (siendo el desplazamiento
relativo entre ambos fotogramas lo que marque el resultado), las imágenes
empleadas en esta prueba, son las de la figura 56.

74
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 56 Imágenes base-abajo

Esta vez la escena conformada, se aproxima a la realidad, tal y como se


muestra en la figura 57.

Figura 57 Stitching-abajo

Sin embargo ahora el programa no es capaz de detectar correctamente


ningún fotograma base, (figura 58), esto es debido a la poca relación que
guardan los puntos de interés localizados.

75
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 58 Localización-abajo

En la siguiente prueba, se analiza el caso del desplazamiento lateral de dos


imágenes, siendo éstas las de la figura 59.

76
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 59 Imágenes base-derecha

El Stitching devuelve esta vez una escena no uniforme, tal y como aparece
en la figura 60, sin embargo, se corresponde bastante bien con la realidad.

Figura 60 Stitching-derecha

A la hora de localizar los fotogramas que conforman la panorámica, el


programa resulta bastante preciso, obteniendo un buen resultado, tal y
como se aprecia en la figura 61.

77
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 61 Localización-derecha

Para terminar, en el último experimento, se proceden a unir dos imágenes


con desplazamiento lateral entre ellas (figura 62).

Figura 62 Imágenes base-izquierda

78
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Al igual que en el experimento anterior, se obtiene una escena bastante


próxima a la realidad (figura 63).

Figura 63 Stitching-izquierda

De igual forma, se obtienen unas localizaciones muy precisas de los


fotogramas base, como se muestra en la figura 64.

79
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 64 Localización-izquierda

Adicionalmente, se han recogido los tiempos de proceso de los


experimentos (Tabla 2), siendo el tiempo de creación el tiempo que tarda
en crear la escena y el tiempo total, el que tarda en crearla y localizar los
fotogramas base; los tiempos son el valor medio estimado de varias
mediciones.

80
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Escena Tiempo Creación(s) Tiempo Total(s)

Ligero desplazamiento (figuras 48,


12.3 19.5
49, 50)

Avance (figura 51) x x

Centro-Arriba (figura 52) x x

Centro-Arriba 2 (figuras 53, 54, 55) 17.2 32.7

Centro-Abajo(figuras 56, 57, 58) 12.4 23.1

Centro-Derecha(figuras 59, 60, 61) 13.2 23.8

Centro-Izquierda(figuras 62, 63, 64) 12.2 23.3

Tabla 2 Tiempo Stitching

Para concluir, se observa que la herramienta Stitching no es del todo


fiable, ya que requiere que el área que comparten las dos imágenes base
sea bastante grande, y aun así, puede producir errores en la escena en
situaciones con imágenes cuya área compartida sea demasiado grande
(como en las figuras 50 y 51), esto es un problema, ya que en caso de que
se tengan que procesar imágenes como éstas, el programa fallará,
terminando la compilación.

Otro de los problemas que genera, es el largo tiempo de procesamiento


que tarda en realizar las tareas (tanto la generación de la escena, como la
búsqueda de los fotogramas base en la misma), que unido al tiempo que
tarda el programa en procesar los datos extraídos por el sensor Kinect,
resultaría en una tasa de FPS (Frames Per Second) de 0.04 (1/30s), algo
inviable para una aplicación a tiempo real.

81
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

3.2.3 STITCHING EN ESCENAS LUMINOSAS

A la hora de recrear una escena, puede haber momentos en los que el


sensor reciba deslumbramientos (que según el apartado 3.1.1, podría fallar
al percibir la profundidad), por lo tanto se requiere conocer como
afectarán dichas condiciones a la creación de la escena.

Para ello se han tomado dos fotogramas (figura 65), que difieren en la
luminosidad y se intentará formar una escena con ellos.

Figura 65 Stitching-luz

El intento de formar una escena con las imágenes variando la


luminosidad, devuelve un error, esto es debido a que la herramienta
Stitching reconoce las imágenes como imágenes distintas.

Esto indica que es necesario hacer un experimento con imágenes no


estáticas, es decir, que contengan elementos en movimiento, como se verá
en el apartado siguiente.

3.2.4 STITCHING EN ESCENAS NO ESTÁTICAS

Ya que en algunos momentos durante la navegación, puede pasar que el


quad se encuentre con objetos móviles (animales por ejemplo), o por
ejemplo deslumbramientos momentáneos (apartado 3.2.3), se requiere

82
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

saber cómo actuará la herramienta de Stitching a la hora de recrear la


escena cuando elementos presentes desaparezcan.

Para ello, se han tomado dos imágenes en las que un objeto es omitido (la
lámpara) tal y como se muestra en la figura 66.

Figura 66 Imágenes base-imágenes no estáticas

Con estas imágenes, se recrea la escena, mostrada en la figura 67, en la


cual se puede apreciar la inclusión del objeto omitido, incluso en las zonas
comunes a ambos fotogramas base.

Figura 67 Stitching-imágenes no estáticas

83
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Tras recrear con éxito la escena, se continúa el proceso y se buscan los


fotogramas base en la panorámica, con el resultado mostrado en la figura
68.

Figura 68 Localización-imágenes no estáticas

Teniendo en cuenta los resultados de este experimento y el anterior


(apartado 3.2.3) se concluye en que el programa puede trabajar en las
condiciones de un entorno no estático, es decir, que contenga objetos
móviles, sin embargo, tienen que ser objetos secundarios en la escena, que
no definan completamente los fotogramas.

84
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

3.3 EXPERIMENTOS Y RESULTADOS EN EL ESPACIO


TRIDIMENSIONAL

En esta última parte se llevaran a cabo los experimentos necesarios para


garantizar el buen funcionamiento del display tridimensional empleando
la herramienta de OpenGL, además se mostrarán los resultados obtenidos
de la representación espacial de la escena.

3.3.1 ANÁLISIS DE LAS HERRAMIENTAS DISPONIBLES EN EL ESPACIO

TRIDIMENSIONAL

En este apartado se analizarán las distintas implementaciones realizadas


para una representación óptima del mapeado tridimensional.

A la hora de introducir los datos en la matriz global Mat_Omega


(apartado 2.3.6), se requiere introducir las diferencias espaciales entre los
fotogramas, es decir los giros y las traslaciones (estas fueron calculadas en
el apartado 2.3.7).

Para ello, se van a ir comprobando las distintas modificaciones, una por


una, para escenas simples, es decir, planos de un solo color, fácilmente
distinguibles unos de otros, para poder apreciar las diferencias.
Empezando con la traslación espacial, se selecciona una traslación de (350,
200, 300) en coordenadas XYZ, y el resultado que se obtiene, se puede
apreciar en la figura 69, en la que el plano blanco actúa de fotograma base,
mientras que el rojo, simula al nuevo fotograma, al que se le aplica la
traslación. Se ha añadido también la localización inicial del sensor Kinect
(en el origen de coordenadas, marcado por la estrella) y también los
sentidos positivos de los ejes de coordenadas.

85
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 69 Traslación y ejes

Ahora vamos a comprobar el giro sobre el eje X, tal y como muestra la


figura 70, el plano rojo, aparece girado 45 grados respecto al fotograma
base (el plano blanco).

Figura 70 Rotación eje X

Mientras que en el giro sobre el eje Y (figura 71), se aprecia que el plano
rojo aparece girado 45 grados también respecto el plano blanco, el eje de

86
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

giro, es el eje central del plano rojo, que en este caso, coincide con el centro
del plano blanco.

Figura 71 Rotación eje Y

Se comprueba el correcto funcionamiento de las diferencias entre


fotogramas al ser introducidos en la matriz global.

Uno de los errores de esta herramienta es la superposición de superficies


en la representación, esto puede causar problemas a la hora de visualizar
la escena.

Además, tal y como fue mencionado en el apartado 2.4.2, el usuario


necesita poder cambiar la escala, para momentos en los que la escena sea
tan grande que no se pueda apreciar en el display, o por el lado contrario,
que se necesite más detalle para observarla, tal y como se muestra en la
comparativa de la figura 73.

87
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 72 Normal vs grande

Por otra parte, a la hora de tener escenas muy grandes, es necesario una
visión general de las mismas (figura 72), para ello, se aplica el reescalado
inverso, además en caso de no ser suficiente, el reescalado es acumulativo,
es decir, al activar el comando que disminuye la escala, se puede volver a
activar para disminuir aun más la escala.

Figura 73 Normal vs pequeño vs más pequeño

Como conclusión, se puede apreciar que el reescalado funciona


perfectamente, sin embargo, estaría bien que para desarrollos futuros,
fueran introducidos más comandos que permitiesen una visión más
interactiva de la escena.

88
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Finalmente es necesario comprobar cuál es el límite de puntos que pueden


ser representados para ello, por medio de figuras simples, se va a ir
llenando el espacio, hasta que éste no sea capaz de representar la rotación.

En la figura 74, se han ido añadiendo figuras una tras otra hasta llegar al
límite.

Figura 74 Imagen límite

El límite de fotogramas que se pueden representar, esta acotado por el


procesador del ordenador, y por el tamaño que se le quiera dar a la matriz
global, en el caso de este proyecto (con un procesador Intel® Core™ i3
CPU M330 @2.13GHz) el límite donde la fluidez se empieza a resentir se
ha encontrado en 9 fotogramas.

3.3.2 REPRESENTACIÓN DE UN FOTOGRAMA

El objetivo de este experimento es lograr la representación tridimensional


de un único fotograma.

Para ello, se han recogido los datos de dicho fotograma (color y


profundidad) mediante el sensor Kinect, que tras ser almacenados en la
matriz global, se procede a representarla.

89
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Las figuras 75 y 76 muestran algunas de las capturas de la representación


tridimensional obtenida.

Figura 75 Representación tridimensional-Resultado 1

Figura 76 representación tridimensional-Resultado 2

90
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

La valoración de la representación es positiva, sin embargo, se observan


ciertos errores, que son precisos de eliminar para continuar, tales como los
puntos correspondientes a la imagen residual (puntos con valor de
profundidad nulo, detectados en el apartado 2.4.2); este problema se
puede resolver fácilmente añadiendo una condición en la función de
representación, que impide añadir valores con profundidad igual a cero.

El otro problema es la falta de uniformidad en las superficies, que habría


que arreglar para desarrollos futuros en los que se desee detectar los
objetos y las superficies y reconocerlos, avisando al usuario o al vehículo
de la existencia de los mismos, la distancia a la que se encuentran y su
forma.

3.3.3 RECREACIÓN DE LA ESCENA TRIDIMENSIONAL

En este apartado se llevara a cabo la representación de una serie de


escenas tridimensionales, el objetivo es demostrar que se ha logrado
recrear la escena con éxito.
Este es el paso que culmina todos los anteriores, la recreación de la escena
por medio de OpenCV fue para posicionar los distintos fotogramas
adecuadamente en el espacio, y aquí van a ser representados, se han
realizado grabaciones de cada representación, referidas en el pie de las
imágenes.

En esta primera escena (figura 77), el mapeado está formado por la unión
de tres fotogramas, cabe resaltar, que hay zonas en las que se superponen
los fotogramas (por ejemplo solo se ve la mitad del televisor), esto es un
problema de la herramienta de representación, que en caso de
superposición, representa el más cercano al observador.

91
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 77 Escena formada con tres fotogramas [22]

En la siguiente escena, también formada con tres fotogramas, no logra la


precisión suficiente, ya que el primer y el tercer fotograma acaban casi
unidos, bloqueando el segundo (que aparece resaltado con un círculo
amarillo en la figura 78).

92
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 78 Segunda escena formada por tres fotogramas [23]

En el último mapeado tridimensional (figura 79), se juntan dos fotogramas


únicamente, estos poseen un área compartida superior, permitiendo así
apreciar algunos de los errores de cálculo del proceso (figura 80),
marcados en rojo.

93
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 79 Escena formada por dos fotogramas [24]

Se aprecia que hay zonas donde se superponen las imágenes y resulta


difícil distinguir los objetos, esto es debido a la superposición de puntos
desde la perspectiva del observador del display, como se explica al
principio de este apartado.

94
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 80 Escena formada por dos fotogramas, vista perpendicular

La figura 81 muestra el mapeado visto desde atrás de la pared física,


donde ahora sí se pueden apreciar los objetos que en las anteriores figuras
habían salido cortados.

95
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Resultados/Experimentos

Figura 81 escena formada por dos fotogramas, vista posterior

Como conclusión, la representación se ha llevado a cabo adecuadamente


[25], los puntos residuales (nombrados en el apartado 3.3.2) han sido
eliminados y se puede distinguir la escena con cierta claridad, sin
embargo, los cálculos realizados a la hora de reconstruir la escena, no son
demasiado precisos, y además el proceso de reconstrucción no es nada
fiable, ya que la unión de ciertos fotogramas acaban en errores que
terminan el proceso (apartado 3.2.2).

Con respecto al experimento 3.3.1 la fluidez cuando existen zonas que se


superponen, se ve resentida a partir de 3 fotogramas, en los que el display
ha de seleccionar que puntos son visibles y cuáles no.

96
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Conclusiones

Capítulo 4 CONCLUSIONES

Se ha desarrollado un programa basado en el sensor Kinect, que intenta


responder a la necesidad de la navegación autónoma de un vehículo, el
programa analiza el entorno en tiempo real, permitiendo la generación de
órdenes de navegación únicamente a partir de la información
proporcionada por el sensor Kinect.

Los objetivos principales del proyecto se han cubierto mayormente; la


recreación del entorno se ha completado con relativo éxito, aunque debido
a ciertos problemas expuestos a continuación (y mostrados en el Capitulo
3 de experimentos y resultados), no se ha podido continuar al siguiente
paso, distinción de obstáculos.

En primer lugar se han extraído con éxito los datos proporcionados por el
sensor Kinect, tanto de color como de profundidad, y esos datos han sido
invertidos para coincidir con la imagen real.

Empleando la herramienta OpenCV, se ha construido la escena con éxito,


posicionando los fotogramas en el espacio hasta conformar el mapeado
tridimensional de la escena, detectando las variaciones relativas entre los
fotogramas: la translación en las tres coordenadas y también los giros
respecto los ejes X e Y.

Además se han almacenando los valores de la nube de puntos en la


matriz: Mat_Omega, para ser posteriormente analizados y representados
con OpenGL, se han solucionado los problemas de visualización
tridimensional aplicando la rotación de la escena y el reescalado.

A partir de esta representación, en un futuro se crearan las órdenes que


necesite el vehículo seleccionado para la navegación autónoma.

97
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Conclusiones

Sin embargo, también han surgido ciertos problemas que impiden un


desarrollo adecuado del proyecto, siendo el mayor de ellos la poca
velocidad del proceso, que dificulta enormemente que pueda ser aplicado
en tiempo real (una unión de dos frames cada 30 segundos, en el mejor de
los casos).

Esta lentitud de proceso, aumenta los fallos en la construcción de la escena


en aspectos como la fiabilidad de los puntos de interés en los fotogramas
consecutivos, produciendo irregularidades en la escena, o una terminación
del programa en el peor de los casos; este problema se agrava debido a la
falta de uniformidad del programa base a la hora de escanear imágenes
del entorno, y a la imposibilidad de introducir un temporizador (real o
controlado por el propio usuario) que de un ritmo interno mas
estructurado al programa.

Por otra parte la viabilidad del Kinect (versión 1.8) como sensor no es del
todo adecuada, debido a la alta posibilidad de deslumbramiento en
exteriores, que “cegarían” la cámara y podría transmitir errores (dan los
valores erróneos de cero milímetros de distancia en las áreas
deslumbradas, inhibiendo su capacidad para detectar obstáculos próximos
en esas zonas, ver apartados 3.1.1 y 3.1.2)

En cualquier caso, los medios para llegar a los objetivos propuestos


funcionan correctamente, solo que estos medios no resultan ser del todo
óptimos.

En conclusión, los objetivos conseguidos: el flujo de datos proporcionado


por el Kinect, la representación tridimensional del entorno y la recreación
de la escena; funcionan adecuadamente por separado, sin embargo en
conjunto, no son adecuados para responder a la necesidad pedida, y
requieren otro planteamiento, otra selección de herramientas y nuevas
versiones de hardware.

98
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Futuros desarrollos

Capítulo 5 FUTUROS DESARROLLOS

Se ha logrado recrear el mapeado tridimensional del entorno a partir de


los datos proporcionados por el sensor Kinect 360, objetivo indispensable
para guiar al vehículo a través del entorno, sin embargo ciertos problemas
impiden que la presente solución sea completamente viable.

Dada la lentitud del procesamiento de datos, la construcción de la escena


no es lo suficientemente rápida para aplicarse en tiempo real.

Las herramientas empleadas para la recreación de la escena (Stitching de


OpenCV) no son del todo eficientes, y presentan cierta posibilidad de
error a la hora de crear la escena (error que impide continuar con el
programa), por lo que un uso continuado supondría un cierre inevitable
del programa (apartado 3.2.2).

Además, el sensor Kinect 360 que se usa en este proyecto, no es apto para
condiciones en el exterior (apartado 3.1.1) ya que en situaciones de alta
luminosidad no funciona correctamente.

Por lo tanto en futuros desarrollos, sería necesario arreglar los problemas


que impiden el óptimo funcionamiento de este futuro control visual.

Para mejorar la velocidad de proceso, un buen comienzo seria cambiar el


ordenador por otro más potente (es un Toshiba con un procesador Intel(R)
Core(TM) i3 CPU 2.13GHz), con mayor velocidad de procesamiento; de
esta forma, el programa podría ser optimizado y llegar a ser una
aplicación real, en el caso de lograr una tasa de FPS (Frames Per Second)
aceptable.

Sería recomendable que el programa guardase una cierta jerarquía,


agregando timers o esperando inputs del usuario, para optimizar el
procesamiento de la escena; sin embargo, el programa no admite los

99
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Futuros desarrollos

inputs más comunes del usuario como getchar() o waitKey(); otra forma
seria ajustando el bucle de OpenGL y haciendo que este regule el
programa, pero es poco recomendable (apartado 2.4.1)

Ciertos fallos en la recreación de la escena mediante Stitching deben ser


arreglados, tales como la detección previa de la compatibilidad de las
imágenes que se van a juntar, evitando errores en el programa (aunque
esto demorase el proceso).

En cualquier caso, quizás las soluciones ofrecidas por estas librerías no


sean las más adecuadas, existen varias opciones para implementar el
sistema, una de las opciones más razonables y que fuertemente se
recomienda en futuros desarrollos es la de PCL, por estar orientada al
trabajo con nubes de puntos, y contar con varios tipos de filtrado para los
mismos. [26]

Esta opción no fue considerada en su momento por el desconocimiento de


la misma (únicamente sirve para trabajar con nubes de puntos) y el grado
de avance que existía en aquel momento con la solución escogida, sin
embargo, esta librería, se podría decir que engloba las funciones
requeridas de las librerías que se usan (OpenCV y OpenGL).

Una vez se han resuelto los problemas existentes, el paso siguiente es la


detección de obstáculos y el reconocimiento de objetos.

Para el reconocimiento de obstáculos, es necesaria la aplicación de filtros,


ya sea manualmente (seleccionando un rango de valores de profundidad)
o filtros ya programados que eliminen los valores residuales (apartado
2.4.2 figura 33)o que sean capaces de reconstruir las superfices a partir de
los datos imperfectos del sensor; en cualquier caso hay que reconstruir la
nube de puntos en figuras compactas, para ello detectando las superficies
(vectores normales) y después reconocer los objetos, en otras palabras, se
busca transformar la escena tridimensional actual en un conjunto de
cubos, superficies. [27]

100
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Futuros desarrollos

Una vez categorizados los objetos de la escena en formas reconocibles, se


obtendría algo similar a esto:

Figura 82 Distinción de objetos en el mapeado tridimensional

Partiendo de este mapeado mas estructurado, se informaría al vehículo de


la forma de los obstáculos y la distancia a la que se encuentran, esto es
reconociendo los obstáculos y pudiendo distinguirlos entre sí.

101
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

102
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Bibliografía

BIBLIOGRAFÍA

[1] Coches. Net, Los fabricantes avanzan en la conducción automatizada


http://www.coches.net/noticias/coches-sin-conductor
[2] Universidad Carlos III, Un nuevo modelo para la navegación autónoma de
vehículos
http://portal.uc3m.es/portal/page/portal/actualidad_cientifica/noticias/navegacion
_autonoma_vehiculos
[3] Universidad Carlos III, Sistema de apoyo a la navegación de un robot móvil en
invernaderos
http://www.ual.es/personal/rgonzalez/papers/279.pdf
[4] Kinect for Windows SDK
https://msdn.microsoft.com/en-us/library/hh855347.aspx
[5] Kinect for Windows Human Interface Guidelines v 1.8.0
https://msdn.microsoft.com/en-us/library/jj663791.aspx

[6] Explicación visión estereoscópica


http://www.adpsystems.net/Pdf/Visi%C3%B3n%20%20estereosc%C3%B3pica.pdf

[7] Blog Panasonic, Explicación de la visión


http://blog.panasonic.es/tecnologia/tecnologia-3d-a-fondo/

[8] Seattle Pi E3 2009


http://blog.seattlepi.com/digitaljoystick/2009/06/01/e3-2009-microsoft-at-e3-
several-metric-tons-of-press-releaseapalloza/
[9] Kinect for Windows SDK beta launches, wants PC users to get a move on
http://www.engadget.com/2011/06/16/microsoft-launches-kinect-for-windows-sdk-beta-
wants-pc-users-t/

[10] Wikipedia Kinect Microsoft

http://es.wikipedia.org/wiki/Kinect
[11] Microsoft Download Center Kinect for Windows SDK v 1.8
https://www.microsoft.com/en-us/download/details.aspx?id=40278

103
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Bibliografía

[12] Wikipedia, OpenCV


https://en.wikipedia.org/wiki/OpenCV
[13] InformatikZentrale RGB Farbmodell
http://www.informatikzentrale.de/rgb-farbmodell.html
[14] OpenCV Docs Mat The basic Image Container
http://docs.opencv.org/doc/tutorials/core/mat_the_basic_image_container/mat_th
e_basic_image_container.html#matthebasicimagecontainer

[15] Wikipedia RGBA


https://en.wikipedia.org/wiki/RGBA_color_space
[16] OpenCV Docs Features 2D Homography
http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_hom
ography.html#feature-homography
[17] OpenCV Docs Common Interfaces of Feature Detectors
http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_d
etectors.html
[18] Nvidia GameWorks
https://developer.nvidia.com/opengl
[19] Wikipedia OpenGL
https://es.wikipedia.org/wiki/OpenGL
[20] Software GLUT Hack
http://www.sjbaker.org/steve/software/glut_hack.html
[21] Vídeo de la escena, disponible en Youtube
https://youtu.be/eR4S4tpCaIE
[22] Vídeo de la escena, disponible en Youtube
https://youtu.be/HtoT2piXwHA

[23] Vídeo de la escena, disponible en Youtube


https://youtu.be/TM1jzjGJ7K0
[24] Vídeo de la escena, disponible en Youtube
https://youtu.be/gs4oMp2ewV4
[25] Lista de reproducción de los mapeados tridimensionales, Youtube

104
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Bibliografía

https://www.youtube.com/watch?v=V-SSGvK6s-
A&list=PLITBzsKx59J3E5b9FjKyEqoPBxli_1gjI
[26] Point Cloud Library
http://pointclouds.org/about/
[27] Wikibooks OpenGL
https://en.wikibooks.org/wiki/OpenGL_Programming
[28] OpenCV Download

http://opencv.org/downloads.html
[29] OpenGL Download
https://www.opengl.org/wiki/Getting_Started

105
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Bibliografía

106
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Bibliografía

Parte II ESTUDIO

ECONÓMICO

107
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

108
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Estudio económico

Capítulo 1 ESTUDIO ECONÓMICO

La mayoría de sistemas de navegación autónoma emplean cámaras o


sensores para analizar los alrededores y ser capaces de detectar obstáculos
(recordar que para obtener una visión estereoscópica se requieren al
menos dos cámaras), con el sensor Kinect, se tienen las cámaras necesarias
para ello, además de ciertos sensores adicionales (como detector de audio),
esto puede ser de utilidad para futuros proyectos.

Con el Kinect, se tiene una mayor fiabilidad en los datos, ya que ha sido
programado y testeado; cosa que no ocurre en otros sistemas, como si se
implementase con cámaras normales para después calcular los valores de
profundidad y color (la escena); esto hace que el precio del desarrollo
disminuya enormemente, ya que los datos proporcionados por los
sensores no requieren ser calculados a partir de la diferencia de las
imágenes proporcionadas por las cámaras (que son más baratas) además
el hecho de incluir el sensor Kinect, implica un coste menor, ya que este
está orientado a mas campos que al de navegación autónoma, lo que le
proporciona mayor número de clientes y disminuye su precio.

Una de las principales características a tener en cuenta, es el rango de


detección de obstáculos, que en el Kinect, este es de 4 metros, teniendo
gran precisión, aunque poca velocidad de refresco, esto lo hace apto para
vehículos lentos y que recorran terrenos muy accidentados o con multitud
de obstáculos, no siendo viable para vehículos rápidos por recorridos más
simples (como coches en una autopista).

El coste inicial de desarrollo es de 12823.7€. El coste del material necesario


para construir modelos (para una flota de vehículos, por ejemplo) seria de
aproximadamente 3500€, que se podría reducir a 100€ si se busca un

109
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Estudio económico

compilador libre que funcione con ambas librerías y se logra omitir la


presencia del ordenador en el proceso.

El coste de la mano de obra para testear cada una de las unidades, no es


muy elevado (en torno a 20€ como máximo, por si surgen complicaciones),
ya que el programa es único, y no requiere calibración.

Suponiendo que no haya problemas de distribución del producto por que


el sensor Kinect pertenezca a Microsoft, el coste del producto para la
empresa seria de 120€ aproximadamente. A falta de un estudio de
mercado, se estima que la demanda potencial del producto a lo largo de su
producción será de 150 unidades (en España). Siendo así, a cada unidad
habrá que repercutirle 12823.7/150€ (85.5€) para cubrir los costes de
desarrollo, ascendiendo el precio a 235.5€.

Considerando un beneficio empresarial del 20%, el precio de venta queda


en 385€, y al sumar el IVA (21%), el precio final de venta al público queda
en 341.9€.
A la vista de las demás alternativas del mercado (orientado a los clientes
que necesitan un sensor de precisión donde la velocidad de proceso sea
algo secundario) este precio es bastante competitivo.

Una cosa a tener en cuenta es el relativo poco mercado que existe, ya que
si hubiera más demanda, hacer un sistema de navegación con cámaras
normales, aunque poseyera un desarrollo del prototipo mucho más
costoso, el coste de construcción por unidad es más barato (los
componentes son más baratos), lo que rebajaría mucho su precio (cubriría
más fácilmente los costes de desarrollo).

Por lo que utilizar un sensor Kinect para la navegación autónoma es una


buena idea para abrir nuevos mercados, que más adelante se encaminaran
al uso de cámaras normales, más económicas, aunque de mayor coste de
desarrollo.

110
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Estudio económico

Parte III PRESUPUESTO

111
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

112
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Mediciones

Capítulo 1 MEDICIONES

En este capítulo se recogen las unidades de los equipos y componentes


empleados, además de las horas imputables al proyecto, clasificadas según
la tarea en cuestión.

1.1 COMPONENTES DE HARDWARE Y HERRAMIENTAS

En esta tabla aparecen los componentes de hardware y las herramientas


empleadas para llevar a cabo el proyecto.

Equipo y hardware Cantidad Horas Horas de uso al año

Ordenador Toshiba
1 300 1000
Satellite i3

Kinect 360 1 280 280

Cable USB Kinect 1 280 280

Tabla 3Medición de Hardware

113
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Mediciones

1.2 COMPONENTES DE SOFTWARE

En la siguiente tabla se muestran los precios de los distintos programas


empleados en la elaboración del dispositivo de visión

Elemento Cantidad Horas Horas de uso al año

Microsoft Visual
1 300 380
Studio Ultimate 2013

Kinect SDK 1 280 280

Librería OpenCV 1 100 100

Librería OpenGL 1 70 70

Microsoft Word 1 50 700

Tabla 4 Medición de Software

1.3 MANO DE OBRA DIRECTA

Por último, en esta tabla aparecen las distintas actividades con su


correspondiente tiempo aplicado a cada una

Actividad Horas

Programación 65

Documentación 85

Pruebas y testeo 70

Solución de errores 90

Tabla 5 Medición de mano de obra

114
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Precios unitarios

Capítulo 2 PRECIOS UNITARIOS

En este capítulo, se calculan los costes de cada elemento por separado, en


función del precio unitario de cada uno

2.1 COMPONENTES DE HARDWARE Y HERRAMIENTAS

Equipo y hardware Precio[€/ud]

Ordenador Toshiba Satellite i3 800

Kinect 360 70

Cable USB Kinect 15

Tabla 6 Precio de hardware

2.2 COMPONENTES DE SOFTWARE

Elemento Precio[€/ud]

Microsoft Visual Studio


3328
Ultimate 2013

Kinect SDK Gratuito(con el Kinect)

Librería OpenCV Gratuito

Librería OpenGL Versión Libre

Microsoft Word 119

Tabla 7 Precio de software

115
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Precios unitarios

2.3 MANO DE OBRA DIRECTA

Actividad Precio[€/ud]

Programación 25

Documentación 30

Pruebas y testeo 30

Solución de errores 40

Tabla 8 Precio de mano de obra

116
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Sumas parciales

Capítulo 3 SUMAS PARCIALES

En los siguientes apartados se indica el precio unitario de cada elemento


utilizado en el proyecto, así como el precio de la hora de la mano de obra
directa

3.1 COMPONENTES DE HARDWARE Y HERRAMIENTAS

Horas Horas
Equipo y Amortización
Cantidad de de uso Precio[€/ud] Coste total(€)
hardware anual
proyecto al año

Ordenador
Toshiba 1 300 1000 800 25% 200
Satellite i3

Kinect 360 1 280 280 70 15% 49

Cable USB
1 280 280 15 10% 13.5
Kinect

Total 262.5

Tabla 9 Suma de hardware

117
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Sumas parciales

3.2 COMPONENTES DE SOFTWARE

Horas
Horas de Amortización
Elemento Cantidad de uso Precio[€/ud] Coste total
proyecto Anual
al año

Microsoft Visual
Studio Ultimate 1 300 500 3328 20% 2662.4
2013

Kinect SDK 1 280 280 Gratuito 20% 0

Librería OpenCV 1 100 100 Gratuito 20% 0

Librería OpenGL 1 70 70 Versión Libre 20% 0

Microsoft Word 1 50 700 119 20% 23.8

Total 2686.2

Tabla 10 Suma de software

3.3 MANO DE OBRA DIRECTA

Actividad Horas Precio[€/ud] Coste total(€)

Programación 65 25 1625

Documentación 85 30 2550

Pruebas y testeo 70 30 2100

Solución de errores 90 40 3600

Total 9875

Tabla 11Suma de mano de obra

118
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Presupuesto general

Capítulo 4 PRESUPUESTO GENERAL

Sumando la contribución de todos los elementos anteriores, se concluye


que el coste del proyecto, impuestos incluidos, asciende a:

Concepto Coste(€)

Componentes de Hardware y herramientas 262.5

Componentes de Software 2686.2

Mano de obra directa 9875

Total 12823.7

Tabla 12 Presupuesto general

119
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Presupuesto general

120
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Presupuesto general

Parte IV CÓDIGO FUENTE

121
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

122
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

Capítulo 1 CÓDIGO FUENTE

Se adjunta a continuación el archivo NuiImageBuffer.cpp.

/////Verificar que se tienen las librerias instaladas!!!!!


#define GLUT_DISABLE_ATEXIT_HACK
#include <strsafe.h>

#include "resource.h"
#include <stdio.h>

#include < opencv2\stitching\stitcher.hpp > ////uno nuevo


#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include "opencv2/core/core.hpp"

#include "opencv2/flann/miniflann.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/photo/photo.hpp"
#include "opencv2/video/video.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/ml/ml.hpp"

#include "opencv2/contrib/contrib.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/imgproc/imgproc_c.h"

using namespace cv;


using namespace std;

#include "opencv2/nonfree/nonfree.hpp"

#include <vector>
#include "stdafx.h"
#include <cmath>
#include "NuiImageBuffer.h"
#include "Utility.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <glut.h> ///dio problemas tiene que estar por debajo de stdlib

//////

123
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

long int cont = 0;


int frame_complete = 0;
int LUT_depth[307200]; //640*480
int LUT_index[307200];

int variableauxiliarDep = 0;
int variableauxiliarRGB = 0;

int LUT_depth_matrixPAR[640][480];
int LUT_depth_matrixIMPAR[640][480];
int LUT_depth_matrix2[640][480];
int LUT_R_matrixPAR[640][480];
int LUT_G_matrixPAR[640][480];
int LUT_B_matrixPAR[640][480];
int LUT_R_matrixIMPAR[640][480];
int LUT_G_matrixIMPAR[640][480];
int LUT_B_matrixIMPAR[640][480];
int LUT_R_matrix[640][480];
int LUT_G_matrix[640][480];
int LUT_B_matrix[640][480];
int LUT_R_matrix2[640][480];
int LUT_G_matrix2[640][480];
int LUT_B_matrix2[640][480];
//string Sto_bitmap;
int colors[921600];
int Height = 639;
int Width = 479;
int T_timer = 0;
int GO = 10;
int mezcla = 0;
int n_image = 0;
int n_image2 = 0;
int cuenta1,cuenta2,cuenta3 = 0;

vector<KeyPoint> queryKeypoints_B, trainKeypoints_B;


char title[] = "3D Shapes";
//GLfloat anglePyramid = 0.0f; // Rotational angle for pyramid [NEW]
GLfloat angleCube = 0.0f; // Rotational angle for cube [NEW]
int refreshMills = 15; // refresh interval in milliseconds [NEW]
int width = 640;
int height = 480;
int depth_M[640][480];
int Inicio_SCAN = 0;
float reescalado = 1;
Mat LUT_RGB(480, 640, CV_8UC3, Scalar(0, 0, 0));
Mat LUT_1(480, 640, CV_8UC3, Scalar(0, 0, 0));
Mat LUT_2(480, 640, CV_8UC3, Scalar(0, 0, 0));
Mat Stitch(480, 640, CV_8UC3, Scalar(0, 0, 0));

int LUT_1RGB[640][480][3];
int LUT_2RGB[640][480][3];

float vecX_Base[] = { 0, 0, 0, 0 };
float vecY_Base[] = { 0, 0, 0, 0 };
float vecX_New[] = { 0, 0, 0, 0 };

124
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

float vecY_New[] = { 0, 0, 0, 0 };
float X_Base, Y_Base, X_New, Y_New = 0;
float vectorXY_desp[50][3];///50 por ejemplo, hay que cambiarlo 0 es X 1
es Y 2 es Z
float vec[3][10];
float centros[50][3]; ///0 es X, 1 es Y, 2 es Z

int numero_puntos = 1536000;


float Mat_Omega[3072000][7]; /// numero,X,Y,Z, R,G,B
int giro,rot, Z_prof = 0;
int numero = 0;
///////////

#define BYTES_PER_PIXEL_RGB 4
#define BYTES_PER_PIXEL_INFRARED 2
#define BYTES_PER_PIXEL_BAYER 1
#define BYTES_PER_PIXEL_DEPTH sizeof(NUI_DEPTH_IMAGE_PIXEL)

#define COLOR_INDEX_BLUE 0
#define COLOR_INDEX_GREEN 1
#define COLOR_INDEX_RED 2
#define COLOR_INDEX_ALPHA 3

#define MIN_DEPTH 400


#define MAX_DEPTH 16383
#define UNKNOWN_DEPTH 0
#define UNKNOWN_DEPTH_COLOR 0x003F3F07
#define TOO_NEAR_COLOR 0x001F7FFF
#define TOO_FAR_COLOR 0x007F0F3F
#define NEAREST_COLOR 0x00FFFFFF

// intensity shift table to generate different render colors for different


tracked players
const BYTE NuiImageBuffer::m_intensityShiftR[] = {0, 2, 0, 2, 0, 0, 2};
const BYTE NuiImageBuffer::m_intensityShiftG[] = {0, 2, 2, 0, 2, 0, 0};
const BYTE NuiImageBuffer::m_intensityShiftB[] = {0, 0, 2, 2, 0, 2, 0};

/// <summary>
/// Constructor
/// </summary>
NuiImageBuffer::NuiImageBuffer()
: m_nearMode(false)
, m_depthTreatment(CLAMP_UNRELIABLE_DEPTHS)
, m_nSizeInBytes(0)
, m_width(0)
, m_height(0)
, m_srcWidth(0)
, m_srcHeight(0)
, m_pBuffer(nullptr)
{
////aqui inicializo la matriz en la que podre los vectores
Mat_Omega[numero_puntos][7]; /// numero,X,Y,Z, R,G,B
for (int p = 0; p < numero_puntos; p++) {
Mat_Omega[p][0]=p;

125
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

Mat_Omega[p][3]=0; ///si Z es 0, no sera representado

InitDepthColorTable();
}

/// <summary>
/// Destructor
/// </summary>
NuiImageBuffer::~NuiImageBuffer()
{
SafeDelete(m_pBuffer);
}

/// <summary>
/// Set image size according to image resolution
/// </summary>
/// <param name="resolution">Image resolution</param>
void NuiImageBuffer::SetImageSize(NUI_IMAGE_RESOLUTION resolution)
{
GetImageSize(resolution, m_srcWidth, m_srcHeight);
}

/// <summary>
/// Calculate image width and height according to image resolution
enumeration value.
/// If resolution enumeration is invalid, width and height will be set to
zero.
/// </summary>
/// <param name="resolution">Enumeration value which indicates the image
resolution format</param>
/// <param name="width">Calculated image width</param>
/// <param name="height">Calculated image height</param>
void NuiImageBuffer::GetImageSize(NUI_IMAGE_RESOLUTION resolution, DWORD&
width, DWORD& height)
{
NuiImageResolutionToSize(resolution, width, height);
}

/// <summary>
/// Get width of image.
/// </sumamry>
/// <returns>Width of image.</returns>
DWORD NuiImageBuffer::GetWidth() const
{
return m_width;
}

/// <summary>
/// Get height of image.
/// </sumamry>
/// <returns>Width of height.</returns>
DWORD NuiImageBuffer::GetHeight() const
{
return m_height;
}

126
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

/// <suumary>
/// Get size of buffer.
/// <summary>
/// <returns>Size of buffer.</returns>
DWORD NuiImageBuffer::GetBufferSize() const
{
return m_nSizeInBytes;
}

/// <summary>
/// Return allocated buffer.
/// </summary>
/// <returns>
/// The pointer to the allocated buffer
/// Return value could be nullptr if the buffer is not allocated
/// </returns>
BYTE* NuiImageBuffer::GetBuffer() const
{
return m_pBuffer;
}

/// <summary>
/// Allocate a buffer of size and return it
/// </summary>
/// <param name="size">Size of buffer to allocate</param>
/// <returns>The pointer to the allocated buffer. If size hasn't changed,
the previously allocated buffer is returned</returns>
BYTE* NuiImageBuffer::ResetBuffer(UINT size)
{
if (!m_pBuffer || m_nSizeInBytes != size)
{
SafeDeleteArray(m_pBuffer);

if (0 != size)
{
m_pBuffer = new BYTE[size];
}
m_nSizeInBytes = size;
}
printf("\n\nalphaBuffer \n\n");
return m_pBuffer;
}

/// <summary>
/// Clear buffer
/// </summary>
void NuiImageBuffer::Clear()
{
m_width = 0;
m_height = 0;
ResetBuffer(0);
}

/// <summary>
/// Initialize the depth-color mapping table.
/// </summary>

127
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

void NuiImageBuffer::InitDepthColorTable()
{

// Get the min and max reliable depth


USHORT minReliableDepth = (m_nearMode ?
NUI_IMAGE_DEPTH_MINIMUM_NEAR_MODE : NUI_IMAGE_DEPTH_MINIMUM) >>
NUI_IMAGE_PLAYER_INDEX_SHIFT;
USHORT maxReliableDepth = (m_nearMode ?
NUI_IMAGE_DEPTH_MAXIMUM_NEAR_MODE : NUI_IMAGE_DEPTH_MAXIMUM) >>
NUI_IMAGE_PLAYER_INDEX_SHIFT;

ZeroMemory(m_depthColorTable, sizeof(m_depthColorTable));

// Set color for unknown depth


m_depthColorTable[0][UNKNOWN_DEPTH] = UNKNOWN_DEPTH_COLOR;

switch (m_depthTreatment)
{
case CLAMP_UNRELIABLE_DEPTHS:
// Fill in the "near" portion of the table with solid color
for (int depth = UNKNOWN_DEPTH + 1; depth < minReliableDepth;
depth++)
{
m_depthColorTable[0][depth] = TOO_NEAR_COLOR;
}

// Fill in the "far" portion of the table with solid color


for (int depth = maxReliableDepth + 1; depth <= USHRT_MAX; depth++)
{
m_depthColorTable[0][depth] = TOO_FAR_COLOR;
}
break;

case TINT_UNRELIABLE_DEPTHS:
{
// Fill in the "near" portion of the table with a tinted
gradient
for (int depth = UNKNOWN_DEPTH + 1; depth < minReliableDepth;
depth++)
{
BYTE intensity = GetIntensity(depth);
BYTE r = intensity >> 3;
BYTE g = intensity >> 1;
BYTE b = intensity;
SetColor(&m_depthColorTable[0][depth], r, g, b);

// Fill in the "far" portion of the table with a tinted


gradient
for (int depth = maxReliableDepth + 1; depth <= USHRT_MAX;
depth++)
{
BYTE intensity = GetIntensity(depth);
BYTE r = intensity;
BYTE g = intensity >> 3;
BYTE b = intensity >> 1;

128
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

SetColor(&m_depthColorTable[0][depth], r, g, b);
}
}
break;

case DISPLAY_ALL_DEPTHS:
minReliableDepth = MIN_DEPTH;
maxReliableDepth = MAX_DEPTH;

for (int depth = UNKNOWN_DEPTH + 1; depth < minReliableDepth;


depth++)
{
m_depthColorTable[0][depth] = NEAREST_COLOR;
}
break;

default:
break;
}

for (USHORT depth = minReliableDepth; depth <= maxReliableDepth;


depth++)
{
BYTE intensity = GetIntensity(depth);

for (int index = 0; index <= MAX_PLAYER_INDEX; index++)


{
BYTE r = intensity >> m_intensityShiftR[index];
BYTE g = intensity >> m_intensityShiftG[index];
BYTE b = intensity >> m_intensityShiftB[index];
SetColor(&m_depthColorTable[index][depth], r, g, b);
}
}
}

/// <summary>
/// Set color value
/// </summary>
/// <param name="pColor">The pointer to the variable to be set with
color</param>
/// <param name="red">Red component of the color</param>
/// <param name="green">Green component of the color</parma>
/// <param name="blue">Blue component of the color</param>
/// <param name="alpha">Alpha component of the color</param>
void NuiImageBuffer::SetColor(UINT* pColor, BYTE red, BYTE green, BYTE
blue, BYTE alpha)
{
if (!pColor)
return;

BYTE* c = (BYTE*)pColor;
c[COLOR_INDEX_RED] = red;
c[COLOR_INDEX_GREEN] = green;
c[COLOR_INDEX_BLUE] = blue;
c[COLOR_INDEX_ALPHA] = alpha;
}

129
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

/// <summary>
/// Calculate intensity of a certain depth
/// </summary>
/// <param name="depth">A certain depth</param>
/// <returns>Intensity calculated from a certain depth</returns>
BYTE NuiImageBuffer::GetIntensity(int depth)
{
// Validate arguments
if (depth < MIN_DEPTH || depth > MAX_DEPTH)
{
return UCHAR_MAX;
}

// Use a logarithmic scale that shows more detail for nearer depths.
// The constants in this formula were chosen such that values between
// MIN_DEPTH and MAX_DEPTH will map to the full range of possible
// byte values.
const float depthRangeScale = 500.0f;
const int intensityRangeScale = 74;
return (BYTE)(~(BYTE)min(
UCHAR_MAX,
log((double)(depth - MIN_DEPTH) / depthRangeScale + 1) *
intensityRangeScale));
}

/// <summary>
///Stacks an image in the Mat format
/// </summary>
void Mat_Image(Mat pImage,int unoo2)
{
for (int rw = 0; rw <479; rw++){
for (int cl = 0; cl < 639; cl++){
Mat paso_punto(1, 1, CV_8UC3, Scalar(LUT_B_matrix[639-
cl][rw], LUT_G_matrix[639-cl][rw], LUT_R_matrix[639-cl][rw]));
paso_punto.copyTo(pImage.row(rw).col(cl));//para que
funcione
if (unoo2==1){
LUT_1RGB[cl][rw][0] = LUT_R_matrix[cl][rw];
LUT_1RGB[cl][rw][1] = LUT_G_matrix[cl][rw];
LUT_1RGB[cl][rw][2] = LUT_B_matrix[cl][rw];
}
else{
LUT_2RGB[cl][rw][0] = LUT_R_matrix[cl][rw];
LUT_2RGB[cl][rw][1] = LUT_G_matrix[cl][rw];
LUT_2RGB[cl][rw][2] = LUT_B_matrix[cl][rw];
}

}
}

void initGL() { //////OPENGL


//printf("alpha \n");

130
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

// OpenGL setup
glClearColor(0, 0, 0, 1);// Set background color to black and opaque
glClearDepth(1); // Set background depth to farthest
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// aparece en
display

/////////
// Global variables:
GLuint vboId; // Vertex buffer ID
GLuint cboId; // Color buffer ID

glViewport(0, 0, width, height);


glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, width / (GLdouble)height, 0.1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 0, 0, 0, 1, 0, 1, 0);
}

void display() { ////OPENGL


///matrix creation

//int D = depth_M[314][239];

///std::cout << D;
///La primera coorodenada els la del eje de coordenadas (horizontal)
la 2 es ordenadas (altura) y la ultima es profundidad
int D = 800;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color
and depth buffers
glMatrixMode(GL_MODELVIEW); // To operate on model-view matrix

glLoadIdentity();

glTranslatef(0, 0, -1 * D); //lo muevo a dicho punto como centro, va


a girar respecto ahi

glRotatef(angleCube, 0, 1, 0);
glPointSize(1);// le he puesto mucho tamaño

D = 500;//ajustar esto LUT_depth_matrixPAR[314][239];


glBegin(GL_POINTS);

for (int i = 0; i < numero;i++){


if (Mat_Omega[i][3] != 0){
glColor3f(Mat_Omega[i][4] / 255.f, Mat_Omega[i][5] /
255.f, Mat_Omega[i][6] / 255.f);

131
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

glVertex3f(Mat_Omega[i][1] / 3 / reescalado,
Mat_Omega[i][2] / 3 / reescalado, Mat_Omega[i][3] / 3 / reescalado);
}
}

int Dii = sqrt(50);


int Diii = sqrt(51);
int Di = sqrt(51);
int Dv = sqrt(66);
int Div = sqrt(49);

int w = 640 / 3; //parece que no entra tan grande


int h = 480 / 3;
/*
// I
glColor3f(1, 0, 1); // Purple
glVertex3f(-w / 2, h / 2, w);// D - 7);

// II
glColor3f(1, 0, 0); // Red
glVertex3f(w / 2, h / 2, w);
*/
// III
glColor3f(0, 255, 255); // blue
glVertex3f(w / 2, -h / 2, -w);

// IV
glColor3f(0, 1, 0); // Green
glVertex3f(-w / 2, -h / 2, -w);

// V
glColor3f(255, 51, 0); // White
glVertex3f(0, 0, D - D);

glEnd(); // End of drawing


/*
glBegin(GL_QUADS);

glColor3f(255, 255, 255); // White


glVertex3f(w / 2, h / 2, -w);
glVertex3f(-w / 2, h / 2, -w);
glVertex3f(-w / 2, h / 2, w);
glVertex3f(w / 2, h / 2, w);

glEnd();

glLineWidth(4);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINES);
for (int i = 0; i < cuenta2; i++){

132
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

glVertex3f(centros[cuenta2][0], centros[cuenta2][0],
centros[cuenta2][0]);
glVertex3f(30+5*i, 5*i, 30);
}

glEnd();

*/

glutSwapBuffers();
angleCube -= 0.2;

void timer(int value) {


glutPostRedisplay();
glutTimerFunc(refreshMills, timer, 0);

void reshape(GLsizei width, GLsizei height) {

if (height == 0) height = 1;
GLfloat aspect = (GLfloat)width / (GLfloat)height;

glViewport(0, 0, width, height);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); // reset

gluPerspective(45.0f, aspect, 0.1f, 100.0f);


}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'p':
case 'P':
reescalado++;
break;

case 'o':
case 'O':
reescalado = 1;
break;

case 'i':
case 'I':
reescalado = reescalado/2;
break;

case 27: // escape


exit(0);

133
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

break;
}
}

void OpenGL_3D(int argc){

glutInitDisplayMode(GLUT_DOUBLE);
glutInitWindowSize(1280, 960);
glutInitWindowPosition(50, 50);

gluPerspective(45, width / (GLdouble)height, 0.1, 1000);

glutCreateWindow(title);

glutDisplayFunc(display);
glutReshapeFunc(reshape);
initGL();

glutTimerFunc(0, timer, 0);


glutKeyboardFunc(keyboard);
glutMainLoop();

void StichMix(Mat image1, Mat image2){


vector< Mat > vImg;
vImg.push_back(image1);
vImg.push_back(image2);//si añado mas, se pueden juntar mas

Stitcher stitcher = Stitcher::createDefault();

Stitcher::Status status = stitcher.stitch(vImg, Stitch);

//imshow("Stitching Result", result);


// int nRows = result.rows;
// int nCols = result.cols;

// printf("Found %d Cols.\n", nCols);

}
/////
void fcn_Square(Mat queryImg_N, Mat trainImg_N, int BaseorNew){

SiftFeatureDetector detector(400);
vector<KeyPoint> queryKeypoints_N, trainKeypoints_N;
detector.detect(queryImg_N, queryKeypoints_N);
detector.detect(trainImg_N, trainKeypoints_N);

134
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

SiftDescriptorExtractor extractor;

Mat queryDescriptors_N, trainDescriptors_N;

extractor.compute(queryImg_N, queryKeypoints_N, queryDescriptors_N);


extractor.compute(trainImg_N, trainKeypoints_N, trainDescriptors_N);

Size size = queryDescriptors_N.size();

size = trainDescriptors_N.size();

BFMatcher matcher(NORM_L2);

vector<DMatch> matches_N;
matcher.match(queryDescriptors_N, trainDescriptors_N, matches_N);
printf("Found %d matches.\n", matches_N.size());

//namedWindow("matches", 1);
Mat img_matches_N;
drawMatches(queryImg_N, queryKeypoints_N, trainImg_N,
trainKeypoints_N, matches_N, img_matches_N);

// imshow("matches", trainImg);

//////
vector< DMatch > good_matches;
double min_dist = 100;
for (int i = 0; i < queryDescriptors_N.rows; i++)
{
if (matches_N[i].distance < 3 * min_dist)
{
good_matches.push_back(matches_N[i]);
}
}
//Localiza
vector<Point2f> obj_N;
vector<Point2f> scene_N;

for (int i = 0; i < good_matches.size(); i++)


{
//obtiene keypoints

obj_N.push_back(queryKeypoints_N[good_matches[i].queryIdx].pt);

scene_N.push_back(trainKeypoints_N[good_matches[i].trainIdx].pt);
}

Mat H = findHomography(obj_N, scene_N, CV_RANSAC);

135
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

//obtiene esqunas
vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0, 0); obj_corners[1] =
cvPoint(queryImg_N.cols, 0);
obj_corners[2] = cvPoint(queryImg_N.cols, queryImg_N.rows);
obj_corners[3] = cvPoint(0, queryImg_N.rows);
vector<Point2f> scene_corners(4);

perspectiveTransform(obj_corners, scene_corners, H);

//dibujar lineas
line(img_matches_N, scene_corners[0] + Point2f(queryImg_N.cols, 0),
scene_corners[1] + Point2f(queryImg_N.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches_N, scene_corners[1] + Point2f(queryImg_N.cols, 0),
scene_corners[2] + Point2f(queryImg_N.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches_N, scene_corners[2] + Point2f(queryImg_N.cols, 0),
scene_corners[3] + Point2f(queryImg_N.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches_N, scene_corners[3] + Point2f(queryImg_N.cols, 0),
scene_corners[0] + Point2f(queryImg_N.cols, 0), Scalar(0, 255, 0), 4);

int X_coordinate0 = scene_corners[0].x;


int Y_coordinate0 = scene_corners[0].y;
int X_coordinate1 = scene_corners[1].x;
int Y_coordinate1 = scene_corners[1].y;
int X_coordinate2 = scene_corners[2].x;
int Y_coordinate2 = scene_corners[2].y;
int X_coordinate3 = scene_corners[3].x;
int Y_coordinate3 = scene_corners[3].y;

if (BaseorNew==1){
vecX_New[0] = X_coordinate0;
vecY_New[0] = Y_coordinate0;
vecX_New[1] = X_coordinate1;
vecY_New[1] = Y_coordinate1;
vecX_New[2] = X_coordinate2;
vecY_New[2] = Y_coordinate2;
vecX_New[3] = X_coordinate3;
vecY_New[3] = Y_coordinate3;
//OutputDebugStringA("gammaaaAAAA \n\n\n\n");
}else{
vecX_Base[0] = X_coordinate0;
vecY_Base[0] = Y_coordinate0;
vecX_Base[1] = X_coordinate1;
vecY_Base[1] = Y_coordinate1;
vecX_Base[2] = X_coordinate2;
vecY_Base[2] = Y_coordinate2;
vecX_Base[3] = X_coordinate3;
vecY_Base[3] = Y_coordinate3;
}

136
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

//namedWindow("MyWindow", 1);// CV_WINDOW_AUTOSIZE); //create a


window with the name "MyWindow"
//imshow("MyWindow", queryImg); //display the image which is stored
in the 'img' in the "MyWindow" window
//imshow("matches_N", img_matches_N);
// imshow("matches22_N", trainImg_N);
}
void intersect_central(float vecX[], float vecY[], float select){
long float alfaB_up = (vecY[0] - vecY[2]);///(29- 410) / (108 - 495);
long float alfaB_dw = (vecX[0] - vecX[2]);//(vecY_Base[0] -
vecY_Base[2]) / (vecX_Base[0] - vecX_Base[2]);
long float alfaB = alfaB_up / alfaB_dw;
long float betaB = vecY[0] - alfaB*vecX[0];

///////// ecuacion de los otros puntos


long float gamaB_up = (vecY[1] - vecY[3]);
long float gamaB_dw = (vecX[1] - vecX[3]);
long float gamaB = gamaB_up / gamaB_dw;
long float sigmB = vecY[1] - gamaB*vecX[1];

/// juto los dos


long float x_up = -(betaB - sigmB);
long float x_dw = alfaB - gamaB;
long float x_central = x_up / x_dw;
long float y_central = alfaB*x_central + betaB;

if (select == 0){
///es base

X_Base = 0;
Y_Base = 0;
X_Base = x_central;
Y_Base = y_central;

}
else{
X_New = 0;
Y_New = 0;
X_New = x_central;
Y_New = y_central;
}

/// <summary>
/// Copy color frame image to image buffer
/// </summary>
/// <param name="pImage">The pointer to the frame image to copy</param>
/// <param name="size">Size in bytes to copy</param>
void NuiImageBuffer::CopyRGB(const BYTE* pImage, UINT size){
//OutputDebugStringA("\nprueba RGB\n");
// Check source buffer size
//OutputDebugStringA("\n alpha \n");
if (size != m_srcWidth * m_srcHeight * BYTES_PER_PIXEL_RGB){

137
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

return;
}
// Set image size to source image size
m_width = m_srcWidth;
m_height = m_srcHeight;

// Allocate buffer for image


UINT* pBuffer = (UINT*)ResetBuffer(m_width * m_height *
BYTES_PER_PIXEL_RGB);

//////aatatata
int p = 0;
int dpt = 0;
int p2 = 0;

// loop over each row and column of the color


for (LONG y = 0; y < m_height; ++y){
for (LONG x = 0; x < m_width; ++x){
if (n_image == 1){/// porque se actualiza despues, va
cambiado
LUT_B_matrixIMPAR[x][y] = m_pBuffer[p];
LUT_B_matrix[x][y] = m_pBuffer[p];
p++;
LUT_G_matrixIMPAR[x][y] = m_pBuffer[p];
LUT_G_matrix[x][y] = m_pBuffer[p];
p++;
LUT_R_matrixIMPAR[x][y] = m_pBuffer[p];
LUT_R_matrix[x][y] = m_pBuffer[p];
p++;
p++;
}
else{
//// creacion de matriz
LUT_B_matrixPAR[x][y] = m_pBuffer[p];
LUT_B_matrix[x][y] = m_pBuffer[p];
p++;
LUT_G_matrixPAR[x][y] = m_pBuffer[p];
LUT_G_matrix[x][y] = m_pBuffer[p];
p++;
LUT_R_matrixPAR[x][y] = m_pBuffer[p];
LUT_R_matrix[x][y] = m_pBuffer[p];
p++;
p++;
}

// Mat paso_punto(1, 1, CV_8UC3,


Scalar(RGB_array[p], RGB_array[p+1], RGB_array[p+2]));
// paso_punto.copyTo(LUT_RGB.row(639-x).col(y));
}
}

///// Copy source image to buffer


memcpy_s(m_pBuffer, m_nSizeInBytes, pImage, size);

138
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

/*
char sz15[255];
sprintf_s(sz15, " R: %d ", LUT_R_matrix[300][240]); //
m_depthColorTable[300][240]);
OutputDebugStringA(sz15);
sprintf_s(sz15, " G: %d ", LUT_G_matrix[300][240]); //
m_depthColorTable[300][240]);
OutputDebugStringA(sz15);
sprintf_s(sz15, " B: %d ", LUT_B_matrix[300][240]); //
m_depthColorTable[300][240]);
OutputDebugStringA(sz15);
*/
///////

/////////////
char sz152[255];
variableauxiliarRGB = variableauxiliarRGB + 10;
sprintf_s(sz152, " RGB=VarAuxDepth: %d ", variableauxiliarDep); //
m_depthColorTable[300][240]);
OutputDebugStringA(sz152);
sprintf_s(sz152, " ((RGB: %d)) \n", variableauxiliarRGB); //
m_depthColorTable[300][240]);
OutputDebugStringA(sz152);

/// <summary>
/// Copy raw bayer data and convert to RGB image
/// </summary>
/// <param name="pImage">The pointer to the frame image to copy</param>
/// <param name="size">Size in bytes to copy</param>
void NuiImageBuffer::CopyBayer(const BYTE* pImage, UINT size)
{
// Check source buffer size
if (size != m_srcWidth * m_srcHeight * BYTES_PER_PIXEL_BAYER)
{
return;
}

// Check if source image size can mod by 2


if (0 != m_srcWidth % 2 || 0 != m_srcHeight % 2)
{
return;
}

// Converted image size is equal to source image size


m_width = m_srcWidth;
m_height = m_srcHeight;

// Allocate buffer for image


UINT* pBuffer = (UINT*)ResetBuffer(m_width * m_height *
BYTES_PER_PIXEL_RGB);
///OutputDebugStringA("\nprueba Bayer\nBayer\n Bayer\n QUE SI, BAYER\n");
// Run through pixels
for (DWORD y = 0; y < m_srcHeight; y += 2)

139
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

{
for (DWORD x = 0; x < m_srcWidth; x += 2)
{
int firstRowOffset = (y * m_srcWidth) + x;
int secondRowOffset = firstRowOffset + m_srcWidth;
// _____
// Get bayer colors from source image // | | |
BYTE r = pImage[firstRowOffset + 1]; // |g1|r |
BYTE g1 = pImage[firstRowOffset]; // |--|--|
BYTE g2 = pImage[secondRowOffset + 1]; // |b |g2|
BYTE b = pImage[secondRowOffset]; // |__|__|

// Set color to buffered pixel


SetColor(pBuffer + firstRowOffset, r, g1, b);
SetColor(pBuffer + firstRowOffset + 1, r, g1, b);
SetColor(pBuffer + secondRowOffset, r, g2, b);
SetColor(pBuffer + secondRowOffset + 1, r, g2, b);
}
}
}

/// <summary>
/// Copy and convert infrared frame image to image buffer
/// </summary>
/// <param name="pImage">The pointer to the frame image to copy</param>
/// <param name="size">Size in bytes to copy</param>
void NuiImageBuffer::CopyInfrared(const BYTE* pImage, UINT size)
{
// Check source buffer size
if (size != m_srcWidth * m_srcHeight * BYTES_PER_PIXEL_INFRARED)
{
return;
}
//OutputDebugStringA("\nprueba Infarred\n");
// Converted image size is equal to source image size
m_width = m_srcWidth;
m_height = m_srcHeight;

// Allocate buffer for image


UINT* pBuffer = (UINT*)ResetBuffer(m_width * m_height *
BYTES_PER_PIXEL_RGB);

// Initialize pixel pointers


USHORT* pPixelRun = (USHORT*)pImage;
USHORT* pPixelEnd = pPixelRun + size / BYTES_PER_PIXEL_INFRARED;

// Run through pixels


while (pPixelRun < pPixelEnd)
{
// Convert pixel from 16-bit to 8-bit intensity
BYTE intensity = (*pPixelRun) >> 8;

// Set pixel color with R, G and B components all equal to intensity


SetColor(pBuffer, intensity, intensity, intensity);

140
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

// Move to next pixel


++pPixelRun;
++pBuffer;
}
}

int inter_recta(int r1, int r2, int w_X, int w_Y){


int rtr = 0;
if (w_Y >= vecY_Base[r2]){ ///la de abajo

if (w_Y <= vecY_Base[r1]){ ///la de arriba


///recta
float C_X = 0;
float alpha1 = 0;

if (vecX_Base[r1] != vecX_Base[r2]){
alpha1 = (vecY_Base[r1] - vecY_Base[r2]) /
(vecX_Base[r1] - vecX_Base[r2]);
}
char szb[255];
sprintf_s(szb, "\n alpha: %f ", alpha1);
//OutputDebugStringA(szb);
float Beta1 = vecY_Base[r1] - alpha1*vecX_Base[r1];
sprintf_s(szb, "\n betab: %f ", Beta1);
//OutputDebugStringA(szb);

if (alpha1!=0){
C_X = (w_Y - Beta1) / alpha1;
}
else{
C_X = vecX_Base[r1];
}

sprintf_s(szb, "\n CX: %f ", C_X);


//OutputDebugStringA(szb);
if (w_X <= C_X){
rtr = 1;
///intersecciona
}
}
}
if (w_Y <= vecY_Base[r2]){ ///la de abajo

if (w_Y >= vecY_Base[r1]){ ///la de arriba


///recta
float C_X = 0;
float alpha1 = 0;

if (vecX_Base[r1] != vecX_Base[r2]){

alpha1 = (vecY_Base[r1] - vecY_Base[r2]) /


(vecX_Base[r1] - vecX_Base[r2]);
}
char szb[255];

sprintf_s(szb, "\n X2: %f ", vecX_Base[r1]);


//OutputDebugStringA(szb);

141
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

sprintf_s(szb, "\n X3: %f ", vecX_Base[r2]);


//OutputDebugStringA(szb);
sprintf_s(szb, "\n alphaDIF: %f ", alpha1);
//OutputDebugStringA(szb);
float Beta1 = vecY_Base[r1] - alpha1*vecX_Base[r1];
sprintf_s(szb, "\n betaDIF: %f ", Beta1);
//OutputDebugStringA(szb);
if (alpha1 != 0){
C_X = (w_Y - Beta1) / alpha1;
}
else{
C_X = vecX_Base[r1];
}

if (w_X <= C_X){


rtr = 1;
///intersecciona
}
}
}
return rtr;
}
int inter_rectaDos(int r1, int r2, int w_X, int w_Y){
int rtr = 0;
if (w_Y >= vecY_New[r2]){ ///la de abajo

if (w_Y <= vecY_New[r1]){ ///la de arriba


///recta
float C_X = 0;
float alpha1 = 0;

if (vecX_New[r1] != vecX_New[r2]){
alpha1 = (vecY_New[r1] - vecY_New[r2]) /
(vecX_New[r1] - vecX_New[r2]);
}

float Beta1 = vecY_New[r1] - alpha1*vecX_New[r1];

if (alpha1 != 0){
C_X = (w_Y - Beta1) / alpha1;
}
else{
C_X = vecX_Base[r1];
}

if (w_X <= C_X){


rtr = 1;
///intersecciona
}
}
}
if (w_Y <= vecY_New[r2]){ ///la de abajo

if (w_Y >= vecY_New[r1]){ ///la de arriba


///recta
float C_X = 0;
float alpha1 = 0;

142
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

if (vecX_New[r1] != vecX_New[r2]){

alpha1 = (vecY_New[r1] - vecY_New[r2]) /


(vecX_New[r1] - vecX_New[r2]);
}

float Beta1 = vecY_New[r1] - alpha1*vecX_New[r1];

if (alpha1 != 0){
C_X = (w_Y - Beta1) / alpha1;
}
else{
C_X = vecX_New[r1];
}

if (w_X <= C_X){


rtr = 1;
///intersecciona
}
}
}
return rtr;
}
int intersec_Punto(float w_X1, float w_Y1){
int rr = 0;

/// wx, primera recta con 0-3


int primera = inter_recta(0,3,w_X1,w_Y1);///primero la de arriba,
despues abajo, y las coordenadas del punto

//OutputDebugStringA("priemro escanado\n");
/// segunda 1-2
int segunda = inter_recta(1, 2, w_X1, w_Y1);
//OutputDebugStringA("segundo escanado\n");
///tercera 01
int tercera = inter_recta(0, 1, w_X1, w_Y1);
//OutputDebugStringA("tercero escanado\n");
// ///cuarta 32
int cuarta = inter_recta(3, 2, w_X1, w_Y1);
// char sza[255];
// sprintf_s(sza, "\n awi p1: %d ,p2: %d,p3: %d,p4: %d \n ",
primera,segunda, tercera,cuarta);
// OutputDebugStringA(sza);
if (primera+segunda+tercera+cuarta==1){
rr = 1;
}
return rr;
//// si dentro o si fuera

}
int intersec_PuntoDos(float w_X1, float w_Y1){
int rr = 0;

/// wx, primera recta con 0-3


int primera = inter_rectaDos(0, 3, w_X1, w_Y1);///primero la de
arriba, despues abajo, y las coordenadas del punto

143
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

/// segunda 1-2


int segunda = inter_rectaDos(1, 2, w_X1, w_Y1);

///tercera 01
int tercera = inter_rectaDos(0, 1, w_X1, w_Y1);

// ///cuarta 32
int cuarta = inter_rectaDos(3, 2, w_X1, w_Y1);

if (primera + segunda + tercera + cuarta == 1){


rr = 1;
}
return rr;

}
void Cuatro_Puntos(int x_1, int x_2, int x_3, int x_4 ){
///////////////// tengo las 4 aristas en vecX_Base, vecY_Base y
vecX_New , vecY_New
///esta el priemr punto dentro?

int punto_1 = intersec_Punto(vecX_New[0],vecY_New[0]);


///esta el segundo?
int punto_2 = intersec_Punto(vecX_New[1], vecY_New[1]);
/// y el tercero
int punto_3 = intersec_Punto(vecX_New[2], vecY_New[2]);
///y el 4?
int punto_4 = intersec_Punto(vecX_New[3], vecY_New[3]);
///balance
if (punto_1==1){
x_1 = 1;
}else{
x_1 = 0;
}
if (punto_2 == 1){
x_2 = 1;
}else{
x_2 = 0;
}
if (punto_3 == 1){
x_3 = 1;
}else{
x_3 = 0;
}
if (punto_4 == 1){
x_4 = 1;
}else{
x_4 = 0;
}

/////////////////
////se continua con los demas puntos
}
void Cuatro_PuntosDos(int x_1, int x_2, int x_3, int x_4){
///////////////// tengo las 4 aristas en vecX_Base, vecY_Base y
vecX_New , vecY_New

144
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

int punto_1 = intersec_PuntoDos(vecX_Base[0], vecY_Base[0]);


///esta el segundo?
int punto_2 = intersec_PuntoDos(vecX_Base[1], vecY_Base[1]);
/// y el tercero
int punto_3 = intersec_PuntoDos(vecX_New[2], vecY_Base[2]);
///y el 4?
int punto_4 = intersec_PuntoDos(vecX_Base[3], vecY_Base[3]);
///balance
if (punto_1 == 1){
x_1 = 1;
}
else{
x_1 = 0;
}
if (punto_2 == 1){
x_2 = 1;
}else{
x_2 = 0;
}
if (punto_3 == 1){
x_3 = 1;
}else{
x_3 = 0;
}
if (punto_4 == 1){
x_4 = 1;
}else{
x_4 = 0;
}

/////////////////
////se continua con los demas puntos
}
////obtener giro, rotacion y diferencia de profunidad
void Cambio_Imagenes(float giroY,float giroX, int Z){

///////////////// tengo las 4 aristas en vecX_Base, vecY_Base y


vecX_New , vecY_New
////los puntos centrales X_Base Y_Base X_New Y_New
////int giro, int giro 2, int Z_prof
int Cuatro[4];
int CuatroDos[4];
///obtener los 4 puntos

Cuatro_Puntos(Cuatro[0], Cuatro[1], Cuatro[2], Cuatro[3]); //Busca


puntos exixtentes en el fotograma nuevo
Cuatro_PuntosDos(CuatroDos[0], CuatroDos[1],
CuatroDos[2],CuatroDos[3]);//busca en el fotograma Base
///ahora ya se cuales son los puntos comunes
//obtener giros y prof
int punto_FotNew[2];
int punto_FotBase[2];///como generlamente solo suele haber un punto,
cojo el primero de cada
int Prof_New_Base[2];///priemro New, despues Base

for (int i = 0; i < 3; i++){

145
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

if (CuatroDos[i] == 1){
punto_FotBase[0] = vecX_Base[i];
punto_FotBase[1] = vecY_Base[i];
}
if (CuatroDos[i]==1){
punto_FotNew[0] = vecX_New[i];
punto_FotNew[1] = vecY_New[i];
}
}
///localizacion punto
//punto base
if (n_image==1){
int x = punto_FotNew[0] - X_Base;///calculo las diferencias
int y = punto_FotNew[1] - Y_Base;
Prof_New_Base[0] = LUT_depth_matrixPAR[x][y];///tengo la
profundidad
int x2 = punto_FotBase[0] - X_New;///calculo las diferencias
int y2 = punto_FotBase[1] - Y_New;
Prof_New_Base[1] = LUT_depth_matrixPAR[x2][y2];///tengo la
profundidad
}
else{
int x = punto_FotNew[0] - X_Base;///calculo las diferencias
int y = punto_FotNew[1] - Y_Base;
Prof_New_Base[0] = LUT_depth_matrixIMPAR[x][y];
int x2 = punto_FotBase[0] - X_New;///calculo las diferencias
int y2 = punto_FotBase[1] - Y_New;
Prof_New_Base[1] = LUT_depth_matrixIMPAR[x2][y2];///tengo la
profundidad
}
giroY = atan((Prof_New_Base[0] - Prof_New_Base[0]) / (X_Base -
X_New));///dan muchos problemas
giroX = atan((Prof_New_Base[0] - Prof_New_Base[0]) / (Y_Base -
Y_New));///dan muchos problemas
Z = Prof_New_Base[1] - Prof_New_Base[0];

/// <summary>
/// Copy and convert depth frame image to image buffer
/// </summary>
/// <param name="pImage">The pointer to the frame image to copy</param>
/// <param name="size">Size in bytes to copy</param>
/// <param name="nearMode">Depth stream range mode</param>
/// <param name="treatment">Depth treatment mode</param>
void NuiImageBuffer::CopyDepth(const BYTE* pImage, UINT size, BOOL
nearMode, DEPTH_TREATMENT treatment)
{
frame_complete = 0;
// Check source buffer size
if (size != m_srcWidth * m_srcHeight * BYTES_PER_PIXEL_DEPTH)
{
return;
}

146
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

// Check if range mode and depth treatment have been changed. Re-
initlialize depth-color table with changed parameters
if (m_nearMode != (FALSE != nearMode) || m_depthTreatment != treatment)
{
m_nearMode = (FALSE != nearMode);
m_depthTreatment = treatment;

InitDepthColorTable();
}

// Converted image size is equal to source image size


m_width = m_srcWidth;
m_height = m_srcHeight;

// Allocate buffer for color image. If required buffer size hasn't


changed, the previously allocated buffer is returned
UINT* rgbrun = (UINT*)ResetBuffer(m_width * m_height *
BYTES_PER_PIXEL_RGB);

// Initialize pixel pointers to start and end of image buffer


NUI_DEPTH_IMAGE_PIXEL* pPixelRun = (NUI_DEPTH_IMAGE_PIXEL*)pImage;
NUI_DEPTH_IMAGE_PIXEL* pPixelEnd = pPixelRun + m_srcWidth;//
*m_srcHeight;

////relleno la matriz
int p = 0;
int l;
int inv_d[640];
int inv_I[640];
for (int k = 0; k <= 479; k++){
l = 0;
for (l = 0; l <= 639; l++){
USHORT depth = pPixelRun->depth; /// este es el valor
USHORT index = pPixelRun->playerIndex;
//int depth = pBufferRun->depth; //saca la profundidad
del sitio
inv_d[l] = depth;
inv_I[l]=index;
pPixelRun++;
}
for (int h = 0; h <= 639; h++){
LUT_depth[frame_complete] = inv_d[639 - h];
LUT_index[frame_complete] = inv_I[639 - h];

++rgbrun;

*rgbrun =
m_depthColorTable[LUT_index[frame_complete]][LUT_depth[frame_complete]];
//LUT_depth_matrix[h][k] = LUT_depth[p];
if (n_image == 1){ ///porque se actualiza despues, va
cambiado
LUT_depth_matrixIMPAR[h][k] = LUT_depth[p] * 255
/ 1250;
}else{

147
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

LUT_depth_matrixPAR[h][k] = LUT_depth[p] * 255 /


1250;
}
if (n_image2 == 1){
LUT_depth_matrix2[h][k] = LUT_depth[p] * 255 /
1250;
}

p++;
frame_complete++;
}
}
variableauxiliarDep = variableauxiliarDep + 25;
///

////
char sz15[255];
sprintf_s(sz15, "(( Depth: %d ))", variableauxiliarDep); //
m_depthColorTable[300][240]);
//OutputDebugStringA(sz15);

sprintf_s(sz15, " Depth=VarAuxRGB: %d \n", variableauxiliarRGB); //


m_depthColorTable[300][240]);
//OutputDebugStringA(sz15);
/////////////////////

/////////////////////////////////////////////////////////////////////
//////////////////////
////toca sacar imagenes
/////////////////////////////////////////////////////////////////////
//////////////////////

if (Inicio_SCAN == 0){
if (T_timer >= GO){ ///cuando el contador llega al momento
fijado de inicio (GO es el numero de bucles)

/* Son las matrices que voy a usar, fuera, porque


si no se reinician
Mat LUT_RGB(480, 640, CV_8UC3, Scalar(0, 0, 0));
Mat LUT_1(480, 640, CV_8UC3, Scalar(0, 0, 0));
Mat LUT_2(480, 640, CV_8UC3, Scalar(0, 0, 0));

//namedWindow("MyWindow", CV_WINDOW_AUTOSIZE); //create


a window with the name "MyWindow"
//imshow("MyWindow", LUT_1); //display the image which
is stored in the 'img' in the "MyWindow" window
//OutputDebugStringA("\n SCAN: ON\n");
*/

n_image++;/// su valor inical es 0

if (n_image == 1){
OutputDebugStringA("PAR \n");

148
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

////PAR

////Imagen Base
if (cuenta1 == 0){
OutputDebugStringA("\n Primer fotograma,
el BASE \n");
Mat_Image(LUT_1,1); /// va a la funcion
dada, que carga la imagen
cuenta1 = 1; /// para no volver a pasar
por aqui
namedWindow("L1 first",
CV_WINDOW_AUTOSIZE);
imshow("L1 first", LUT_1);
///////////
///copio la primera imagen al vector
requerido

int vueltas = 0;

for ( int k = 0; k < 480; k++){

for (int l = 0; l <= 640; l++,


numero++){
Mat_Omega[numero][0] =
numero;

Mat_Omega[numero][1] = -l +
640 / 2;///x
Mat_Omega[numero][2] = -k +
480 / 2;///y
Mat_Omega[numero][3] =
LUT_depth_matrixPAR[l][k];///z
Mat_Omega[numero][4] =
LUT_1RGB[640 - l][k][0];// LUT_R_matrixPAR[640 - l][k];///R
Mat_Omega[numero][5] =
LUT_1RGB[640 - l][k][1];//LUT_G_matrixPAR[640 - l][k];///G
Mat_Omega[numero][6] =
LUT_1RGB[640 - l][k][2];// LUT_B_matrixPAR[640 - l][k];///B No puedo
poner PAR, porque se escaneo antes de eso

}
vueltas++;
}
numero=numero - 480;///307200
centros[0][1] = 0;
centros[0][0] = 0;
centros[0][2] =
LUT_depth_matrixPAR[320][240];
//aqui se carga L1, pero no se autoriza
OpenGL_3D(0); ///para saltar, se quita

}else{
//////////
//cargo L1 y autorizo
Mat_Image(LUT_1,1);
mezcla = 1;
}

149
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

}
if (n_image == 2){
n_image = 0;
OutputDebugStringA("IMPAR \n");
////IMPAR

///Cargare L2
Mat_Image(LUT_2,2);
mezcla = 1;
}

///////////////////////////////////////////////
//////////////////////////////////////////////
if (mezcla == 1){
////juntar L1 y L2, en Pares, la Base es L2, en
impares, L1 (el inicial no salta), a Stitch
/*
vecX_Base[] = { 0, 0, 0, 0 };
vecY_Base[] = { 0, 0, 0, 0 };
vecX_New[] = { 0, 0, 0, 0 };
vecY_New[] = { 0, 0, 0, 0 };
*/
//// detectar si son la misma

/////////////////////////////////////////////////////////////////////
////////
////es necesario un evento que diga que si son
la misma o han avanzado
/////////////////////si no son la misma,
comeinzo el proceso normal,

StichMix(LUT_1, LUT_2);

OutputDebugStringA("Stitch -> Complete \n");

if (cuenta2 == 0){
namedWindow("L2 first",
CV_WINDOW_AUTOSIZE); //create a window with the name "MyWindow"
imshow("L2 first", LUT_2); //display the
image which is stored in the 'img' in the "MyWindow" window

namedWindow("MyWindow1",
CV_WINDOW_AUTOSIZE); //create a window with the name "MyWindow"
imshow("MyWindow1", Stitch); //display the
image which is stored in the 'img' in the "MyWindow" window

}
if (cuenta2 == 1){
//namedWindow("MyWindow3",
CV_WINDOW_AUTOSIZE); //create a window with the name "MyWindow"
//imshow("MyWindow3", Stitch); //display
the image which is stored in the 'img' in the "MyWindow" window
//OpenGL_3D(0);

150
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

}
if (cuenta2 == 2){
//namedWindow("MyWindow2",
CV_WINDOW_AUTOSIZE); //create a window with the name "MyWindow"
//imshow("MyWindow2", Stitch); //display
the image which is stored in the 'img' in the "MyWindow" window
//namedWindow("L1 2", CV_WINDOW_AUTOSIZE);
//create a window with the name "MyWindow"
//imshow("L1 2", LUT_1); //display the
image which is stored in the 'img' in the "MyWindow" window
}

OutputDebugStringA("JUNTAR \n");
if (n_image == 1){ //BASE L2
//es PAR
////////
/// hago los recortes
Mat Centro_Origen(LUT_2, Rect(140, 40,
400, 400)); ////chequear si los recortes son apropiados
Mat Centro_Nueva(LUT_1, Rect(140, 40, 400,
400));

///////
//// los paso a escala de grises
//cvtColor(Centro_Nueva, LUT_1,
CV_RGB2GRAY);
//cvtColor(Centro_Origen, LUT_2,
CV_RGB2GRAY);
////////

fcn_Square(Centro_Origen, Stitch, 0);


///nuevo es 1
///
OutputDebugStringA("test 12 PAR\n");
OutputDebugStringA("Base Complete \n");
fcn_Square(Centro_Nueva, Stitch,1);
OutputDebugStringA("New Complete \n");

}else{
///es IMPAR
////////
/// hago los recortes
Mat Centro_Origen(LUT_1, Rect(140, 40,
400, 400)); ////chequear si los recortes son apropiados
Mat Centro_Nueva(LUT_2, Rect(140, 40,
400, 400));
///////
//// los paso a escala de grises
//cvtColor(Centro_Nueva, LUT_2,
CV_RGB2GRAY);

151
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

//cvtColor(Centro_Origen, LUT_1,
CV_RGB2GRAY);
////////

///

fcn_Square(Centro_Origen, Stitch, 0);


///
OutputDebugStringA("test 12 IMPAR\n");
OutputDebugStringA("Base Complete \n");
fcn_Square(Centro_Nueva, Stitch, 1);
OutputDebugStringA("New Complete \n");

////ahora saco los valores del punto central


char sz152[255];

/////
sprintf_s(sz152, "0_Found Base X: %f and Y: %f
/// \n", vecX_Base[0], vecY_Base[0]);
OutputDebugStringA(sz152);
sprintf_s(sz152, "1_Found Base X: %f and Y: %f
/// \n", vecX_Base[1], vecY_Base[1]);
OutputDebugStringA(sz152);
sprintf_s(sz152, "2_Found Base X: %f and Y: %f
/// \n", vecX_Base[2], vecY_Base[2]);
OutputDebugStringA(sz152);
sprintf_s(sz152, "3_Found Base X: %f and Y: %f
/// \n", vecX_Base[3], vecY_Base[3]);
OutputDebugStringA(sz152);

/////////////////////
///aqui saco los valores del punto central

intersect_central(vecX_Base, vecY_Base, 0);/// 0


para Base

intersect_central(vecX_New, vecY_New, 1);

sprintf_s(sz152, "\n Centro x Base: %f Centro y


Base: %f\n ", X_Base, Y_Base);
OutputDebugStringA(sz152);
sprintf_s(sz152, "\n Centro x New: %f Centro y
New: %f \n ", X_New,Y_New);
OutputDebugStringA(sz152);

///// las transformaciones van aqui


///////////////// tengo las 4 aristas en
vecX_Base, vecY_Base y vecX_New , vecY_New
////los puntos centrales X_Base Y_Base X_New
Y_New
/////

float giro = 0;///sobre el eje vertical

152
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

float giro2 = 0;///sobre el eje horizontal

int Z_prof = 0;////POSITIVO ES ALEJARLO DEL


SENSOR

Cambio_Imagenes(giro,giro2, Z_prof);////cuidado
con las operaciones trigonometricas, da muchos errores

float variacion = X_New - X_Base;

centros[cuenta2 + 1][0] = centros[cuenta2][0] +


X_New - X_Base;
centros[cuenta2 + 1][1] = centros[cuenta2][1] +
Y_New - Y_Base;
centros[cuenta2 + 1][2] = centros[cuenta2][2] +
Z_prof;

///////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
///

if (n_image == 1){
////PAR, añado LUT_1
char sz152[255];

int vueltas = 0;

for (int k = 0; k < 480; k++){

for (int l = 0; l <= 640; l++,


numero++){

Mat_Omega[numero][0] =
numero;
Mat_Omega[numero][1] = -l +
640 / 2 + X_New - X_Base + centros[cuenta2][0] - (-l + 640 / 2)*(1 -
cos(giro));///x
Mat_Omega[numero][2] = -k +
480 / 2 + Y_New - Y_Base + centros[cuenta2][1] - (-k + 480 / 2)*(1-
cos(giro2));///y

Mat_Omega[numero][3] =
centros[cuenta2][2] + Z_prof - (-l + 640 / 2)*sin(giro) - (-k + 480 /
2)*sin(giro2)+ LUT_depth_matrixPAR[l][k];///z
if
(LUT_depth_matrixPAR[l][k]==0){
Mat_Omega[numero][3]
= 0;
}

153
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

Mat_Omega[numero][4] =
LUT_1RGB[640 - l][k][0];// LUT_R_matrixPAR[640 - l][k];///R
Mat_Omega[numero][5] =
LUT_1RGB[640 - l][k][1];//LUT_G_matrixPAR[640 - l][k];///G
Mat_Omega[numero][6] =
LUT_1RGB[640 - l][k][2];// LUT_B_matrixPAR[640 - l][k];///B No puedo
poner PAR, porque se escaneo antes de eso
}
vueltas++;
}
numero = numero - 480;///307200
OpenGL_3D(0);///poner como comentario para
saltar
}else{
///IMPAR, añado LUT_2

int vueltas = 0;

for (int k = 0; k < 480; k++){

for (int l = 0; l <= 640; l++,


numero++){

Mat_Omega[numero][0] =
numero;

Mat_Omega[numero][1] = -l +
640 / 2 + X_New - X_Base + centros[cuenta2][0] - (-l + 640 / 2)*(1 -
cos(giro));///x
Mat_Omega[numero][2] = -k +
480 / 2 + Y_New - Y_Base + centros[cuenta2][1] - (-k + 480 / 2)*(1 -
cos(giro2));///y
Mat_Omega[numero][3] =
centros[cuenta2][2] + Z_prof - (-l + 640 / 2)*sin(giro) - (-k + 480 /
2)*sin(giro2) +LUT_depth_matrixPAR[l][k];///z
if
(LUT_depth_matrixPAR[l][k] == 0){
Mat_Omega[numero][3]
= 0;
}
Mat_Omega[numero][4] =
LUT_2RGB[640 - l][k][0];// LUT_R_matrixPAR[640 - l][k];///R
Mat_Omega[numero][5] =
LUT_2RGB[640 - l][k][1];//LUT_G_matrixPAR[640 - l][k];///G
Mat_Omega[numero][6] =
LUT_2RGB[640 - l][k][2];// LUT_B_matrixPAR[640 - l][k];///B No puedo
poner PAR, porque se escaneo antes de eso

}
vueltas++;
}
numero = numero - 480;///307200

154
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

OpenGL_3D(0);///poner como comentario para


saltar
}

cuenta2++;//indica el numero de mezcla por el


que voy
if (cuenta2 == 2){
OpenGL_3D(0);
}

// destroyWindow("MyWindow");
}

if(T_timer < GO + 5){

T_timer++;
}

////////////////////////////////

//char sz15[255];
//sprintf_s(sz15, " pequeña: %d ", LUT_depth_matrix[320][240]); //
m_depthColorTable[300][240]);
//OutputDebugStringA(sz15);
}

155
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

156
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Código fuente

Parte V MANUAL DEL

USUARIO

157
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

158
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Instalación de librerías

Capítulo 1 INSTALACIÓN DE LIBRERÍAS

En este capítulo se explican los pasos a seguir para instalar las librerías
necesarias para que el programa funcione correctamente.

El compilador usado en este proyecto es Microsoft Visual Studio Ultimate


2013, y la arquitectura del sistema es de 64 bits, y las instrucciones dadas
son para estas características

1.1 INSTALACIÓN DE OPENCV

El primer paso es descargar la librería de OpenCV [28], requerida para


formar la panorámica y localizar los fotogramas base.

Una vez descargada se preparan las variables de entorno, para ello, se


accede a Mi PC, y se después a Propiedades, aquí, se selecciona
Configuración Avanzada del Sistema, tal y como muestra la figura 83.

Figura 83, Configuración Avanzada del Sistema

Tras esto, se selecciona la opción de Variables de Entorno, (figura 84)

159
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Instalación de librerías

Figura 84 variables de entorno


Y entonces se crea una nueva variable, llamada OPENCV_DIR (el círculo
verde en la figura 85), a la que hay que añadir la localización de los
archivos descargados, después de esto, se edita la variable ya existente,
Path (círculo rojo), y se le añade al final %OPENCV_DIR%\x64\vc13\bin,
donde el 64 representa a la arquitectura del sistema (64 bits) y vc13
representa el tipo de compilador usado.

160
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Instalación de librerías

Figura 85 Editando las variables de entorno

El paso siguiente, ya en el compilador, requiere ir a la ventana de


Propiedades, a la que se accede haciendo clic izquierdo en el nombre del
proyecto, en la parte del Explorador de Soluciones, tal y como se muestra
en la figura 85.

161
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Instalación de librerías

Figura 86 Propiedades

El siguiente paso es seleccionar Todas las Configuraciones, C/C++ y


General (figura 87) y es necesario añadir en $(OPENCV_DIR)\include en
la pestaña de Directorios de Inclusión Adicionales, tal y como se muestra
en la figura 87

Figura 87 C/C++ General

162
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Instalación de librerías

El paso siguiente es añadir %OPENCV_DIR%\x64\vc13\bin en el


apartado de Vinculador, General, en Directorios de Bibliotecas
Adicionales, como aparece en la figura 88

Figura 88 Directorios de Bibliotecas Adicionales

Por último se añadirá en dependencias adicionales (Vinculador->Entrada-


>Dependencias Adicionales) los nombres de todos los archivos de las
librerías (.lib) descargadas (presentes en la carpeta lib de OpenCV), tras
aceptar los cambios, la librería OpenCV está instalada.

1.2 INSTALACION DE OPENGL

La librería OpenGL es la encargada de realizar la representación


tridimensional de la escena.

Tras descargar los archivos de OpenGL en la pagina correspondiente [29],


se procede a abrir el compilador, en la Pestaña de Propiedades, vista en el
anterior apartado (figura 86), y en la opción de C/C++ y General, como
aparece en la figura 89, se hace clic en Editar

163
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Instalación de librerías

Figura 89 C/C++ Editar

Aquí deberemos añadir el directorio de la carpeta llamada include, de los


archivos descargados. Tras esto, en Vinculador, General, en Directorios de
Bibliotecas Adicionales, añadiremos el directorio de la carpeta lib de los
archivos de OpenGL

Figura 90 Vinculador General

Finalmente, de igual forma que en apartado anterior, es necesario añadir


todos los nombres de todas las librerías, que se pueden encontrar en la
carpeta lib.

164
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Funcionamiento del programa

Capítulo 2 FUNCIONAMIENTO DEL

PROGRAMA

En este capítulo se detalla el funcionamiento básico del programa


desarrollado.

Una vez se ha conectado el sensor Kinect, y se ha detectado su presencia


en el equipo, se puede proceder a compilar el programa, iniciando la
depuración, como muestra la figura 91

Figura 91 Visual Studio Compilar

La señal que marca el inicio del programa es la aparición de la ventana


menú de Kinect Explorer D2D (apartado 2.2.2) (figura 92)

165
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Funcionamiento del programa

Figura 92 Kinect Explorer D2D

Tras unos instantes, se puede observar como el frame rate en la esquina


superior derecha decae hasta valores muy pequeños (entre 0 y 3), esto
indica que el programa está procesando la información, de datos normales
o formando una panorámica, que como se comentó en el apartado 3.2.2,
esto ralentiza demasiado el proceso para que pueda funcionar en tiempo
real.

A partir de la aparición de la ventana-menú (figura 92) ya se puede


empezar a mover el sensor Kinect, sin embargo, hay que tener cuidado, ya
que debido al largo tiempo que puede estar procesando el programa, no es
posible conocer con exactitud cuando se escanea cada imagen, con lo que
se podrían escanear dos fotogramas que la herramienta de Stitching no
sería capaz de unir, resultado en un error de programa.

Tras un cierto tiempo, suponiendo que el Stitching no haya fallado en la


reconstrucción de las escenas, el programa llegará a la función llamada
OpenGL_3D y mostrará la ventana con la representación 3D tal y como
muestra la figura 93.

166
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL

Funcionamiento del programa

Figura 93 Representación 3D

El programa está configurado para que solo represente 3 panorámicas,


esto es debido a que tras ciertos experimentos (apartado 3.3.3) se considera
el limite debido a la superposición de puntos, que empeoran visibilidad de
la escena, tal y como fue comentado en el apartado 3.3.3.

Es importante saber, que debido a los problemas explicados


anteriormente, al tratar de representar las 3 escenas, es muy probable que
el programa falle, por los motivos anteriormente mencionados; una forma
de ir adaptando las representaciones es ir activando antes o después la
función de OpenGL_3D, siempre que se hayan almacenado previamente
valores en la matriz global.

167

You might also like