LASPY: LIDAR PARA PYTHON

¿Qué es laspy?

Laspy es una librería de Python que nos permite trabajar con archivos LiDAR, leyéndolos, modificándolos y creando nuevos archivos.

Esta librería funciona con versiones de Python 3.6 o superiores. En la web que recoge la mayoría de los paquetes y librerías de Python, podemos encontrar mas información sobre laspy y algunos ejemplos.

Preparando un entorno de trabajo

Vamos a ver algunos ejemplos sobre esta librería. Para realizar este ejercicio por tu cuenta solo necesitarás:

  • Una instalación de Python 3.6 o superior
  • Un entorno de trabajo de Python o «environment» donde instalaremos laspy
  • Datos LiDAR

En este caso, vamos a usar la versión de Python 3.7.8 que puedes descargar desde la página oficial de Python.

Lo primero que vamos a hacer es crear nuestro «Python Environment» así, podemos inslatar la librería de laspy y evitar posibles conflictos entre librerías.

Una vez tenemos nuestro entorno de trabajo listo, es hora de activarlo. Para ello ejecuta el siguiente comando que básicamente activa nuestro «environment»:

env_laspy\Scripts\activate

Activando el espacio de trabajo nos permitirá instalar las librerías que queramos en él. Instala el paquete de «laspy», por defecto se instalará la versión mas reciente. Si no tenías «numpy» instalado en tu PC este también se instalará.

Ahora ya tenemos todo listo. Es el momento de crear un script de Python y leer el primer archivo LiDAR.

Leer un archivo LiDAR con LASPY

Para la realización de este ejemplo, vamos a usar Pycharm, pero podrías utilizar cualquier otra IDE para trabajar con Python, incluso el bloc de notas. Para descargar la versión gratuita de Pycharm pincha aquí.

Abre un proyecto de Pycharm en la carpeta donde tienes tu «environment» de Python, de este modo, Pycharm encontrar automáticamente el intérprete de Python que necesita. De forma alternativa, puedes manualmente establecer el intérprete tu mismo desde «settings»:

Configurar interprete en pycharm

Ahora, crea un archivo de python desde la ventana de proyectos y llamalo «test_laspy»:

Crear un archivo en pycharm

En primer lugar, vamos a comenzar importando laspy y numpy. Usaremos ambas librerías para nuestro propósito:

import laspy as lp
import numpy as np

El siguiente paso será añadir nuestros datos de entrada, es decir, la nube de puntos que usaremos como test:

input_path = "C:\Javi\Movidas\laspy\PNOA_1.las"

Ahora ya tenemos definida la variable con el archivo de entrada. Vamos a leer el archivo LiDAR y obtener el número de puntos que hay según la información de cabecera («header information»)

with lp.open(input_path) as fh:
print('Numero de puntos en la cabecera:', fh.header.point_count)

Con la función «print», obtendremos en pantalla el número de puntos o retornos que contiene nuestro archivo LiDAR, para la nube de puntos que estoy usando del PNOA, he obtenido algo más de 3 millones de puntos: 3.221.429.

Ahora, en lugar de leer el número de retornos desde la información de cabecera, vamos a leer el número total de puntos que tiene nuestro LiDAR. Esto es una práctica habitual y puede ayudarnos a identificar archivos corruptos cuando hay discrepancias entre ambos valores. Para ello, ejecuta el siguiente código:

with lp.open(input_path) as fh:
print('Numero de puntos en la cabecera:', fh.header.point_count)
las = fh.read()
print('Points from data:', len(las.points))

Ahora tienes dos funciones «print» y ambas te deberían dar el mismo resultado en tus datos, que en este caso es 3221429. Uno de los valores se consigue usando «point_count» y el otro con la función «len()».

Filtrar una nube de puntos por clase y retorno

Cuando tenemos nubes de puntos clasificadas, es interesante conocer formas de filtrar el LiDAR para obtener información sobre cuantos puntos tenemos en cada clase, así como la distribución del número de retornos. En cualquier nube de puntos clasificada, deberíamos esperar que el suelo tuviera valores muy altos para el primer (y único retorno). Vamos a ver si esto se cumple en nuestra nube de puntos:

with lp.open(input_path) as fh:
    las = fh.read()
    ground_pts = las.classification == 2
    bins, counts = np.unique(las.return_number[ground_pts], return_counts=True)
    print('Ground Point Return Number distribution:')
    for r,c in zip(bins,counts):
        print('{}:{}'.format(r, c))

Como resultado obtenemos:

Trabajar con numpy arrays para obtener informacion de la nube de puntos

En este último paso vamos a crear un «numpy array» con los valores en Z de nuestra nube de puntos y vamos a calcular los valores máximos, mínimos y medios de dicha nube de puntos. Para ello, utiliza el siguiente código:

import laspy as lp
import numpy as np


input_path = "C:\Javi\Movidas\laspy\PNOA_1.las"

point_cloud = lp.read(input_path)

pointsZ = np.vstack((point_cloud.z)).transpose()

print('\nAltitud maxima:', np.max(pointsZ))

print('\nAlitud media:', np.mean(pointsZ))

print('\nAltitud minima:', np.min(pointsZ))

Paso por paso, importamos las librerías de laspy y numpy, después leemos con laspy nuestra nube de puntos. A continuación usamos «vstak» para convertir los datos en Z de nuestra nube de puntos en un «numpy array».

El último paso consiste en usar las funciones max, mean y min para leer los valores máximos, mínimos y medios en Z. También podrías obtener información sobre quartiles, desviación estándar, mediana etc.

Ahora que sabemos los valores mínimos y máximo de alturas, ¿no sería interesante conocer la distribución de los mismos?

Podemos conseguir esto creando un histograma con 5 grupos iguales (bins), así averiguaremos como se distribuyen los datos desde 4 metros hasta 963 metros de altura. Usaremos nuevamente numpy para conseguir nuestro objetivo:

input_path = "C:\Javi\Movidas\laspy\PNOA_1.las"

point_cloud = lp.read(input_path)

pointsZ = np.vstack((point_cloud.z)).transpose()

print('\nAltitud maxima:', np.max(pointsZ))

print('\nAlitud media:', np.mean(pointsZ))

print('\nAltitud minima:', np.min(pointsZ))


histo = (np.histogram(pointsZ, bins=[4, 200, 400, 600, 800, 963]))

La función histograma de numpy, crea la distribución de puntos acorde con el tamaño de bin que nosotros deseemos.

Si nos fijamos en los resultados, vemos que la inmensa mayoría de nuestros valores se encuentran entre 4 y 200 metros. Lo cual ya nos indica que valores superiores a 200 metros serán probablemente «outliers» o valores atípicos.

ConclusiÓn

Como hemos podido comprobar, las librerías de laspy en combinación con numpy, nos dan mucha versatilidad para obtener información importante sobre nubes de puntos lidar. En posteriores posts veremos como crear nuevas nubes de puntos, filtrar por RGB, eliminar valores atípicos, etc.

El código que hemos usado quedaría del siguiente modo:

import laspy as lp
import numpy as np

## open file
input_path = "C:\Javi\Movidas\laspy\PNOA_1.las"
point_cloud = lp.read(input_path) # read file
pointsZ = np.vstack((point_cloud.z)).transpose() # convert Z values into np array
print('\nAltitud maxima:', np.max(pointsZ)) # print some metrics
print('\nAlitud media:', np.mean(pointsZ))
print('\nAltitud minima:', np.min(pointsZ))

histo = (np.histogram(pointsZ, bins=[4, 200, 400, 600, 800, 963])) ## find out Z distribution

print('\nHistograma: ', histo)

with lp.open(input_path) as fh:

las = fh.read()
print('Points from data:', len(las.points)) ## read number of points from file




with lp.open(input_path) as fh:
las = fh.read()
ground_pts = las.classification == 2
bins, counts = np.unique(las.return_number[ground_pts], return_counts=True)

for r,c in zip(bins,counts):
print('{}:{}'.format(r, c)) ## find out ground point distribution

LiDAR PNOA

Como instalar el nuevo QGIS 3.18 con la funcionalidad de visualizar LiDAR

Durante el mes de Febrero, se ha lanzado una nueva versión de QGIS (3.18) con múltiples mejoras y extras, entre ellas la posibilidad de cargar nubes de puntos en formato LAZ o LAS directamente arrastrándolas a tu ventana de QGIS.

El programa utiliza librerías de entwine pdal combinadas con el software de QGIS para exprimir al máximo nuestros datos LiDAR. Por ahora se trata de una primera versión con escasa funcionalidad, pero es fácil imaginar su potencial unido a QGIS. El simple hecho de poder combinar vectores, rasters y nubes de puntos en la ventana de QGIS ya resulta de gran utilidad.

Sin embargo, parece que esta opción aun no está disponible para Windows cuando descargamos el instalador de QGIS directamente desde su página oficial. No obstante existe una solución temporal para esto que ha sido facilitada por Lutra Consulting, empresa que organizó el crowdfounding para incluir esta funcionalidad en QGIS, junto con North Road y Hobu.

Instalación

Para poder disfrutar por ahora de esta nueva funcionalidad, es necesario descargar el nuevo instalador de OSGEO4W que por ahora se encuentra en prueba. Pero ojo, si ya tienes OSGEO4W o QGIS instalado en tu ordenador y no deseas sobreescribir o modificar la instalación, entonces te recomiendo que a la hora de instalarlo, lo hagas en una ruta diferente.

Sigue los pasos para realizar la instalación. Durante el proceso no sólo podrás seleccionar la ruta de instalación si no que también podrás crear un acceso directo en el escritorio. La instalación puede tardar unos minutos y como con cualquier otro porgrama, es recomendable reiniciar el ordenador una vez finalizada.

Probando datos

Una vez hemos instalado QGIS 3.18, es el momento de ejecutar el programa. Para ello, dirígete a la ruta donde lo has instalado y busca la carpeta bin. Desde ella, busca el archivo ejecutable llamado «qgis-bin.exe» y haz doble clic en él. De esta manera te aseguras de ejecutar la versión que acabas de instalar y no otra versión que ya exista en tu PC.

Ahora simplemente arrastra una nube de puntos en formato LAS o LAZ a tu ventana de QGIS. Para este ejemplo, he descargado el bloque «PNOA_2016_MAD_426-4481_ORT-CLA-RGB.laz» a través del centro de descargas del CNIG.

Las nubes de puntos que descargamos del PNOA estan coloreadas usando ortofotos, por este motivo al cargarla se verá como en la siguiente captura de pantalla, coloreda por sus atributos RGB:

Bloque LiDAR visualizado en QGIS por RGB

Si lo deseas, puedes cargar también en QGIS una ortofoto que puedes conseguir del mismo buscador del CNIG y usarla como mapa base.

En QGIS, la nube de puntos se carga como otra capa cualquiera, es decir, como una capa vectorial o ráster. Por tanto, el sistema de coordenadas de referencia o su simbología se pueden modificar.

Para cambiar la simbología de la nube de puntos, haz doble clic en la capa LiDAR y busca la pestaña de simbología. Tendrás 4 opciones:

  • Extensión: Serían los límites del bloque
  • Atributos: Esta opción te permite mostrar la nube de puntos en base a sus campos escalares (intensidad, número de retorno, coordenadas, etc.
  • RGB: Si existe, es posible mostrar la nube de puntos por los colores con los que haya sido atribuída.
  • Clasificación: Generalmente, esta clasificación será responde a los estándares de la «American Society of Photogrametry and Remote Sensing«

En este ejemplo he optado por colorear la nube de puntos en base a uno de sus atributos, en concreto la coordenada Z. Para ello simplemente selecciona «Attribute by Ramp» en las opciones de simbología y ha continuación, selecciona la opción de la coordenada Z. De forma automática se crea una rampa de colores en base al rango por alturas (en este caso alturas sobre el nivel del mar).

Nube de puntos superpuesta sobre Ortofoto. El LiDAR se muestra clasificado por alturas

Por el momento, no hay algoritmos nativos disponibles en QGIS 3.18 para modificar la nube de puntos o crear productos a partir de ella. Pero teniendo en cuenta que usa la librería de PDAL, es muy posible que próximas versiones incorporen distintas funcionalidades para generar, por ejemplo, modelos digitales del terreno a partir del LiDAR.