Archivo del Autor: joseangelmt

Cambios en el sistema de cámaras

Debido a la incorporación del modelo de corrección de distorsiones en cámaras calibradas con Pix4D, PhotoScan y con OpenCV, hemos realizado una serie de cambios en el concepto de cámara en Digi3D.NET.

Los cambios realizados son internos y hemos mantenido compatibilidad hacia atrás, de manera que las cámaras creadas a día de hoy se seguirán comportando de la misma manera.

Un restituidor digital como Digi3D.NET básicamente muestra imágenes centrando un determinado pixel de estas imágenes en el centro de la ventana fotogramétrica. Cuando mueves el dispositivo de entrada (manivelas, topomouse, ratón, etc.) se incrementan o decrementan valores a las Coordenadas Terreno y el sensor correspondiente se encarga de transformar dichas Coordenadas Terreno a Coordenadas Pixel en las que se tendrá que centrar cada imagen mostrada en la Ventana Fotogramétrica, de modo que la responsabilidad de transformar de Coordenadas Terreno a Coordenadas Pixel recae en los sensores (que en Digi3D.NET están implementados como extensiones).

Cada sensor (ADS, Satelital, Cámaras Cónicas, etc.) pasa por una serie de cálculos (específicos del modelo matemático del sensor) para cumplir esa misión: Transformar de Coordenadas Terreno a Coordenadas Pixel.

Los cambios que hemos introducido aquí se aplican al Sensor Cónico (el de cámaras pinhole), el resto de sensores no se han tocado.

Veamos cómo se comportaba hasta hoy este sensor para transformar de Coordenadas Terreno a Coordenadas Pixel:

Cámaras antiguo

La Orientación Exterior tenía como parámetros de entrada Coordenadas Terreno (Xt, Yt, Zt) y como salida proporcionaba Coordenadas Foto (Xfo, Yfo). Para conseguir esto, la Orientación Exterior tenía que conocer con qué cámara estamos trabajando, pues en el cálculo para obtener Coordenadas Foto interviene la Focal de la cámara. Esto como verás más adelante lo hemos cambiado: ahora la Orientación Exterior es agnóstica en lo referente a la cámara con la que se está trabajando y por lo tanto no tiene conocimiento de que existe una cámara.

La misión de la Cámara era transformar las Coordenadas Foto en Coordenadas Fiducial  (Xfi, Yfi) corrigiendo las distorsiones de la lente si era necesario.

La misión de la Orientación Interna era transformar de Coordenadas Fiducial a Coordenadas Pixel (Xp, Yp).

Las correcciones de distorsión se realizaban en  el paso de Coordenadas Foto a Coordenadas Fiducial únicamente. Además, puedes ver que teníamos que tener si o si una orientación interna.

Resulta que las distorsiones en Pix4D, PhotoScan y las calibraciones obtenidas mediante cualquier programa que utilice la librería de visión artificial OpenCV no corrigen las distorsiones en el sistema foto, sino que se corrigen en el Sistema Cámara Proyectado. Además, no es necesaria una orientación interna pues el modelo matemático para estas cámaras transforma directamente a coordenadas pixel.

Veamos cómo se comporta el sensor cónico de Digi3D.NET para transformar de Coordenadas Terreno a Coordenadas Pixel una vez realizados los cambios que presentamos hoy:

Cámaras nuevo global

Ahora la orientación exterior no devuelve Coordenadas Foto (Xfo, Yfo), sino que devuelve Coordenadas en el Sistema Cámara (Xcam, Ycam, Zcam). La misión de las Cámaras ahora es convertir esas Coordenadas en el Sistema Cámara a Coordenadas Pixel (Xp, Yp).

Estudiemos ahora cómo transforma la cámara de Coordenadas en el Sistema Cámara a Coordenadas Pixel:

Cámaras nuevo detallado.PNG

Lo primero que hacemos es convertir de Coordenadas en el Sistema Cámara a Coordenadas Proyectadas en el Sistema Cámara (dividiendo tanto la componente X como la Y por la Z).

Luego transformamos de Coordenadas Proyectadas en el Sistema Cámara a Coordenadas Foto. Las implementaciones de Pix4D, PhotoScan y OpenCV corrigen las distorsiones en este paso. En esta fase se tiene en cuenta la focal (o mejor dicho, las focales de la cámara, porque ahora se pueden introducir dos focales si es necesario (si la cámara está calibrada en píxeles y el sensor es barato, es posible que el ancho del pixel no coincida con el alto del pixel, por lo tanto obtenemos dos focales distintas).

Continuamos transformando de Foto a Fiducial. Es en esta fase donde Digi3D.NET calculaba las distorsiones. Las cámaras Pix4D, PhotoScan y OpenCV básicamente suman aquí las coordenadas del punto principal.

Y por último se transforman las Coordenadas Fiducial a Coordenadas Pixel. Si la cámara es analógica, aquí es donde se tiene en cuenta la orientación interna, y si no, pues básicamente se multiplican las Coordenadas Fiducial por el tamaño del pixel y se les suma la coordenada del pixel central de la imagen (que es el 0,0 en el sistema fiducial).

Digi3D.NET ahora carga de forma nativa archivos de Pix4D (en breve de PhotoScan y de OpenCV si es que existe algún formato estandarizado para OpenCV, lo tengo que estudiar), de modo que no tienes que hacer nada más que cargar el archivo de cámara correspondiente y Digi3D.NET se encarga de todo, tal y como puedes ver en la entrada del blog Carga nativa de archivos de calibración de cámaras de Pix4D, sin embargo, hemos modificado también los archivos de cámara de Digi3D.NET para que puedas crear un archivo de cámara en formato Digi3D.NET y que funcione igual que el de Pix4D por ejemplo.

Veamos a continuación cómo han quedado esos parámetros:

Variable Valor Valor por defecto Descripción
Focal
  • Si la focal tiene las mismas dimensiones en X y en Y, un único valor con el valor de la focal.
  • Si la focal tiene distintas dimensiones en X y en Y, dos valores: uno para la focal en X y otro para la focal en Y.
N/A Focal calibrada de la cámara. Las unidades de este valor definen las unidades del resto de valores en el archivo de cámara, lo que quiere indicar que si ponemos este valor en milímetros, las unidades del resto de variables deberán estar en milímetros. De puede introducir aquí un valor en cualquier unidad, con la condición de que el resto de variables utilicen la misma unidad.
TipoCorreccion
  • CamaraAFoto
  • FotoAFiducial
FotoAFiducial Indica en que paso se va a realizar la corrección de distorsiones de la cámara. Por defecto este valor es CamaraAFoto para mantener compatibilidad hacia atrás.
TipoDistorsionTangencial
  • No.
    Si no se quiere aplicar distorsión tangencial.
  • Brown.
    Si se quiere aplicar la siguiente fórmula:∆x = P1*(r2 + 2*x2)+2*P2*x*y
    ∆y = 2*P1*x*y + P2*
    (r2 + 2*y2)
  • OpenCV.
    Si se quiere aplicar la siguiente fórmula:∆x = 2*P1*x*y + P2*(r2 + 2*x2)

    ∆y = 2*P2*x*y + P1*(r2 + 2*y2)
  • Si no se especifica esta variable ni las variables P1 y P2, el valor por defecto es No.
  • Si no se especifica esta variable y en el archivo de cámara aparecen valores para las variables P1 y P2, por compatibilidad hacia atrás el valor por defecto es Brown.
Indica el tipo de corrección tangencial a aplicar. Estas distorsiones aparecen por una mala alineación entre la lente y el sensor.
TipoDesortogonalidad
  • No.
    Si no se desea aplicar desortogonalidad.
  • Fraser.
    Si se desea aplicar desortogonalidad en el eje de la X mediante la fórmula:∆x = B1*x + B2*y
  • Si no se especifica
  • esta variable ni las variables B1 y B2, el valor por defecto es No.
  • Si no se especifica esta variable pero si se especifican las variables B1 y B2, el valor por defecto es Fraser
Indica el tipo de desortogonalidad (por una mala fabricación del sensor CCD en el que puede que los píxeles no tengan el mismo ancho que alto o que la matriz de píxeles no esté perfectamente alineada.

Te muestro a continuación el código fuente de la función que calcula la corrección por distorsión para que quede claro cómo se calculan las distorsiones en Digi3D.NET (está programado en C++, pero aunque no entiendas de programación creo que haces un mínimo esfuerzo por entenderlo lo vas a ver claro):

CódigoCalculaCorreccionDistorsion

De esta manera puedes ver cómo intervienen todos los parámetros del archivo de cámara.

Vemos ahora un caso práctico: Vamos a crear un archivo de cámara en formato Digi3D.NET que simule el siguiente archivo de cámara de Pix4D:

Pix4D camera calibration file 0
#Focal Length mm assuming a sensor width of 23.64864599999999938973x15.76576400000000077739mm
F 25.21219253120580461314
#Principal Point mm
Px 11.78574296804639587322
Py 7.57715224585386515344
#Symmetrical Lens Distortion Coeffs
K1 0.00086121816472929343
K2 0.02791840536682562574
K3 -0.03806069473095977096
#Tangential Lens Distortion Coeffs
T1 -0.00621590311996760014
T2 -0.00051873958437360630

Puedes comprobar que aparece (como comentario) el tamaño del sensor en milímetros. No aparece por ningún sitio el tamaño del pixel, ni el tamaño de las imágenes.

Si te fijas en el archivo de calibración se indica que el ancho del sensor es mayor que el alto del sensor, lo que significa que la cámara se ha calibrado en horizontal y las fotos obtenidas con esta cámara deberían ir siempre en horizontal (desactivar la opción de rotado automático), y así habría que cargarlas en Digi3D.NET.

Esta cámara en particular crea imágenes de 6000×4000 píxeles, de modo que el tamaño de píxel en horizontal y en vertical se puede deducir fácilmente dividiendo el ancho del sensor por el número de píxeles en horizontal por un lado y el alto del sensor por el número de píxeles en vertical de la imagen dando los siguientes resultados

23.648646 / 6000 = 0.003941441
15.765764 / 4000 = 0.003941441

Por lo tanto el tamaño de píxel en horizontal es igual que en vertical. Comencemos a crear nuestro archivo de cámara:

[Camara]
TamanoPixel=0.003941441

La focal se indica claramente que va en milímetros también, así que la copiamos tal cual

[Camara]
TamanoPixel=0.003941441
Focal=25.21219253120580461314

Continuamos con el punto principal. El punto principal en Pix4D se da con respecto a la esquina superior izquierda de la imagen, y no con respecto al centro fiducial como estamos acostumbrados, de modo que tenemos que hacer una simple resta (coordenadas que aparecen en el archivo de Pix4D menos coordenadas del centro fiducial de la cámara) para transformar ese punto principal a un punto principal con respecto al centro fiducial que es como lo requiere Digi3D.NET. Los ejes X e Y crecen de forma distinta, por lo tanto verás que en la Y la operación se hace al revés.

PuntoPrincipalXConRecpectoAlCentroFiducial = PuntoPrincipalXConRecpectoEsquinaSuperiorIzquierda - CentroFiducialX

PuntoPrincipalYConRecpectoAlCentroFiducial = CentroFiducialY - PuntoPrincipalYConRecpectoEsquinaSuperiorIzquierdaY

Y el centro fiducial es muy sencillo: o dividimos entre dos el ancho y alto del sensor por un lado, o dividimos entre dos el tamaño de la imagen (el resultado nos dará en píxeles obviamente) y multiplicamos el valor por el tamaño de pixel calculado anteriormente. Voy a utilizar una fórmula para la X y otra para la Y, así las tienes las dos:

CentroFiducialX = 23.64864599999999938973 / 2 = 11.824323
CentroFiducialY = 4000 / 2 * 0.003941441 = 7.882882

Perfecto, ahora a restar y tenemos las coordenadas del punto principal con respecto al centro fiducial:

PuntoPrincipalXConRecpectoAlCentroFiducial  = 11.78574296804639587322 - 11.824323 = -0.038580032
PuntoPrincipalYConRecpectoAlCentroFiducial  = 7.882882 - 7.57715224585386515344 = 0.3057297541462

Continuamos pues con nuestro archivo de cámara:

[Camara]
TamanoPixel=0.003941441
Focal=25.21219253120580461314
PuntoPrincipal=-0.038580032 0.3057297541462

Si estudiamos las fórmulas utilizadas por Pix4D  comprobaremos que éste realiza la corrección de distorsión en el paso de Coordenadas Cámara Proyectadas a Coordenadas Focal, y que además el polinomio utilizado para las distorsiones radiales es K1_R2_K2_R4, además se utiliza como tipo de distorsión tangencial el método de OpenCV y que no se tiene en cuenta la desortogonalidad, de modo que el archivo de cámara queda de la siguiente manera:

[Camara]
TamanoPixel=0.003941441
Focal=25.21219253120580461314
PuntoPrincipal=-0.038580032 0.3057297541462
TipoCorreccion=CamaraAFoto
Pol=K1_R2_K2_R4
TipoDistorsionTangencial=OpenCV
TipoDesortogonalidad=No
K1=0.00086121816472929343
K2=0.02791840536682562574
K3=-0.03806069473095977096
P1=-0.00621590311996760014
P2=-0.00051873958437360630

Y a continuación tienes un vídeo en el que se demuestra que con este archivo de cámara los resultados son idénticos que con la cámara nativa de Pix4D.

Carga nativa de archivos de calibración de cámaras de Pix4D

Acabamos de implementar la primera novedad de la versión Beta 2016 de Digi3D.NET: Carga nativa de archivos de calibración de cámaras de Pix4D.

Si procesas un proyecto con Pix4D, éste crea un archivo de calibración de cámara cuyo nombre sigue el siguiente patrón: nombre_del_proyecto_pix4d_calibrated_internal_camera_parameters.cam. y dentro del archivo aparecen los parámetros de calibración de cámara.

Digi3D.NET ahora carga de forma nativa estos archivos e implementa el modelo matemático para corregir distorsiones con los parámetros especificados en el archivo. De esta manera puedes trabajar con cámaras no métricas utilizando el modelo preciso de corrección de distorsiones de Pix4D.

Puedes ver un vídeo mostrando esta característica en acción:

Nuevos desencadenadores en tiempo real

Comenzamos una semana que vamos a dedicar a añadir nuevos controles de calidad en tiempo real.

Os presentamos dos nuevos desencadendores que nos van a permitir detectar en el momento de digitalizar las siguientes condiciones:

  1. Detectar si un punto se ha digitalizado cerca de otro punto. Puedes utilizar esto para detectar por ejemplo una farola cerca de otra farola, una farmacia cerca de otra farmacia, etc.
  2. Detectar si una geometría está en el interior de otra geometría como por ejemplo un edificio dentro de una masa de árboles.

Los desencadenadores en Digi3D.NET permiten que se ejecuten una serie de acciones si se cumple el desencadenador, como por ejemplo mostrar mensajes de error, convertir la entidad en otra entidad, o simplemente eliminarla.

Puedes ver estos dos nuevos desencadenadores en acción en el siguiente vídeo:

Ejecutar órdenes al pulsar el botón de Dato

Acabamos a añadir una novedad en Digi3D.NET, que nos permite indicar en la tabla de códigos un conjunto de órdenes a ejecutar al pulsar el botón de DATO si Digi3D.NET está en modo preparado y el código activo es el código en el que hemos añadido ese conjunto de órdenes.

De modo que ahora disponemos de dos conjuntos de órdenes que podemos indicar opcionalmente a cada código:

  • Órdenes a ejecutar cuando se selecciona el código.
  • Órdenes a ejecutar cuando el programa está en modo preparado y pulsamos el botón de Dato.

Puedes ver esta nueva funcionalidad en acción en el siguiente vídeo:

Nueva orden SELECCIONA_TODO_EN_CURSOR

Presentamos una nueva orden (del conjunto de órdenes de selecciones) que nos va a permitir seleccionar de forma automática todas las entidades que están en el ámbito del cursor.

Esta orden se activa únicamente cuando estamos ejecutando una orden que está solicitando que seleccionemos varias entidades, como por ejemplo la orden MOD_MULTIPLE.

En el siguiente vídeo puedes comprobar cómo modificar la geometría de las seamlines generadas mediante MDTopX.

Nueva orden GENERAR_TOPOLOGIAS_SIN_ISLAS

Acabamos de añadir a Digi3D.NET una nueva orden que nos va a permitir generar topologías por inundación sin tener en cuenta la relación entre polígono y huecos.

De esta manera, al pasar el cursor sobre un polígono, si este tiene huecos, estos no se marcarán, de modo que la orden que ejecutemos (como añadir código por recinto) únicamente tendrá en cuenta las caras externas del polígono.

Puedes seleccionar esta nueva orden en el menú Inundación/Generar inundaciones (sin huecos).

Comprueba esta nueva funcionalidad en el siguiente vídeo:

Nuevas condiciones para los desencadenadores de Digi3D.NET para el control de calidad de la cartografía

Acabamos de añadir varias condiciones nuevas al listado de condiciones que pueden desencadenar una serie de acciones en el momento de almacenar una entidad.

Las condiciones nuevas son:

  • Se acaba de digitalizar una línea.
  • Se acaba de digitalizar un punto.
  • Se acaba de digitalizar un texto.
  • Se acaba de digitalizar un polígono.
  • Se acaba de digitalizar un complejo.

Que se añaden al conjunto de condiciones de las que disponíamos hasta ahora:

  • Es una línea cerrada o un polígono y su área es inferior a un valor.
  • Es una línea y su perímetro en el plano es inferior a un determinado valor.
  • Es una línea y su perímetro 3D es inferior a un determinado valor.

De esta manera, podemos por ejemplo mostrar un mensaje de error al usuario si almacena un punto en un código pensado para almacenar líneas, etc.

Puedes ver esta nueva funcionalidad en el siguiente vídeo: