Lesson 1 of 2
Em andamento

Extração de Dados de um Serviço WMS Remotamente

Ricardo 16 de Setembro, 2024

1 – Introdução ao WMS

Neste tutorial, podes aprender a como extrair dados de um serviço WMS remotamente usando Python. O Web Map Service (WMS) é um protocolo padrão para a solicitação e entrega de mapas em formatos de imagem a partir de servidores remotos. Vamos explorar como extrair dados específicos de um serviço WMS e exibir as informações desejadas.

Comecemos por considerar a página onde se pode aceder ao modelo batimétrico do canhão da Nazaré, aqui.

A figura acima é a imagem que descreve o modelo batimétrico e abaixo a imagem com as camadas de background

podendo ser observadas e analisadas na página do hidrográfico+. O que se pode observar, com cores mais claras são profundidades mais elevadas e a vermelho os locais de menor profundidade. No entanto, uma coisa é visualizar, a outra é ter acesso aos valores um a um. Muitas das vezes só precisamos de recolher informação numa área/ponto específico, e é isso que aqui vamos mostrar.

 

2 – Importar as bibliotecas necessárias

Para começar, será melhor explicar as bibliotecas que podem ser usadas.

import requests                      # Para fazer requisições HTTP
import urllib.parse                  # Para fazer a análise de URLs
import pyproj                        # Para transformações de coordenadas
import matplotlib.pyplot as plt      # Para plotar gráficos
import matplotlib.image as mpimg     # Para ler e exibir imagens
  • requests: É uma biblioteca popular para fazer requisições HTTP. Vamos usá-la para enviar uma requisição HTTP para obter informações do serviço WMS.
  • urllib.parse: É uma biblioteca usada para analisar e manipular URLs. No serviço WMS e iremos extrair os parâmetros de consulta.
  • pyproj: É uma biblioteca para realizar transformações de coordenadas entre diferentes sistemas de referência espacial (SRS). Pois as coordenadas habituais podem não ser as mesmas do serviço.
  • matplotlib.pyplot: É uma biblioteca de visualização amplamente utilizada em Python.
  • matplotlib.image: É uma biblioteca utilizada para ler e exibir imagens, como aquela que pode ser descarregada do canhão da Nazaré.

Estas bibliotecas permitirão a extração de uma profundidade num local específico.

 

3 – Extrair informações do WMS

No código abaixo, a definição da URL do serviço WMS usado como exemplo está representada pela variável `url`. Aqui está a parte relevante do código que define essa URL:

# URL do WMS
url = r'https://webgeo1.hidrografico.pt/geoserver/mbat25m/wms?service=WMS&version=1.1.0&request=GetMap&layers=mbat25m%3ACanhaoNazare&bbox=-86412.5%2C-10012.5%2C-80587.5%2C-6487.5&width=768&height=464&srs=EPSG%3A3763&format=application%2Fopenlayers3#'

# Analisar a URL
parsed_url = urllib.parse.urlparse(url)

# Obter os parâmetros de consulta
query_params = urllib.parse.parse_qs(parsed_url.query)

Aqui está uma breve explicação da estrutura da URL e dos seus parâmetros:

  • `https://webgeo1.hidrografico.pt/geoserver/mbat25m/wms`: É a parte fixa da URL que indica o endereço do servidor WMS. Iremos utilizá-la outra vez mais há frente.
  • `service=WMS`: Especifica o serviço como WMS (Web Map Service).
  • `version=1.1.0`: Indica a versão do serviço WMS utilizada.
  • `request=GetMap`: Especifica o tipo de solicitação para obter o mapa.
  • `layers=mbat25m%3ACanhaoNazare`: Especifica a camada do mapa que serão exibidas. No exemplo, a camada é `mbat25m:CanhaoNazare`, que evidentemente diz respeito ao modelo batimétrico que pretendemos.
  • `bbox=-86412.5%2C-10012.5%2C-80587.5%2C-6487.5`: Define a extensão espacial do mapa (bounding box) através das coordenadas do retângulo delimitador (bbox). Iremos defini-las como `west_lon=-86412.5`, `south_lat=-10012.5`, `east_lon=-80587.5` e `north_lat=-6487.5`.
  • `width=768&height=464`: Especifica a largura e a altura do mapa em pixels, ou seja, da imagem PNG.
  • `srs=EPSG%3A3763`: Define o sistema de referência espacial (SRS) usado para o mapa. No exemplo, o SRS é `EPSG:3763`. Esta é uma das informações mais importantes pois especifica o tipo de projeção/coordenadas usadas no bbox.
  • `format=application%2Fopenlayers3`: Define o formato do mapa retornado. No exemplo, o formato é `application/openlayers3`.

Estas informações serão úteis para o processo de requisição do valor pretendido.

 

4 – Conversão de coordenadas

Como queremos, neste exemplo, ilustrar esse pedido,  podemos escolher uma localização e observar a profundidade da zona do canhão.

 

Neste local, a aplicação mostra-nos que naquele local o valor de profundidade é aproximadamente -44.53 m.

 

Ora, para a sua extração, podemos proceder da seguinte forma:

Primeiro converter as coordenadas para coordenadas decimais:

# Escolher latitude e longitude
latitude_given = "39° 35' 43\" N"
longitude_given = "9° 4' 48\" W"

def convert_coord(coord):
    degrees, minutes, seconds, direction = coord.split(" ")
    degrees = float(degrees[:-1])
    minutes = float(minutes[:-1])
    seconds = float(seconds[:-1])
    decimal_degrees = degrees + minutes / 60 + seconds / 3600
    if direction in ["S", "W"]:
        decimal_degrees = -decimal_degrees
    return decimal_degrees

# Converter coordenadas de graus, minutos e segundos para graus decimais
latitude_decimal = convert_coord(latitude_given)
longitude_decimal = convert_coord(longitude_given)

Foi necessário, proceder à transformação das coordenadas observadas para coordenadas decimais, neste caso, mas num projeto diferente as coordenadas podem já estar nesse formato.

Posteriormente, converter  as coordenadas que estavam no formato 'EPSG:4326' para o sistema adotado pelo WMS, neste caso,  já tínhamos visto que era 'EPSG:3763'. Dado que vamos aceder à informação contida numa imagem, temos de mudar a escala para coincidir com o pixel correspondente à localização na imagem.

# Extrair parâmetros
image_width = query_params['width'][0]
image_height = query_params['height'][0]
west_lon, south_lat, east_lon, north_lat = map(float, query_params['bbox'][0].split(','))
srs = query_params['srs'][0]

# Criar o transformer para converter entre sistemas de coordenadas
transformer = pyproj.Transformer.from_crs('EPSG:4326', srs, always_xy=True)
lon_range = east_lon - west_lon
lat_range = north_lat - south_lat

# Transformar as coordenadas para o sistema de coordenadas do mapa
transformed_coords = transformer.transform(longitude_decimal, latitude_decimal)
x = int((transformed_coords[0] - west_lon) / lon_range * float(image_width))-1 #Subtrair 1 dado que temos uma deslocação
y = int(image_height) - int((transformed_coords[1] - south_lat) / lat_range * float(image_height))-1 #Subtrair 1 dado que temos uma deslocação

Estes valores de x e de y são as posições dos pixels que correspondem às nossas coordenadas iniciais. Ou seja, no comprimento y e na altura x, estará a cor associada ao valor pretendido.

 

5 – Solicitação de informações

Agora que temos as coordenadas, podemos usá-las para solicitar o ‘envio’ da profundidade desejada. Definindo o url do WMS e o seus parâmetros e requerer o valor que está associado ao 'GRAY_INDEX'.

# URL do WMS
url_wms = 'https://webgeo1.hidrografico.pt/geoserver/mbat25m/wms'

# Parâmetros para a solicitação GetFeatureInfo
params = {
    'service': 'WMS',
    'version': '1.1.0',
    'request': 'GetFeatureInfo',
    'layers': 'mbat25m:CanhaoNazare',
    'query_layers': 'mbat25m:CanhaoNazare',
    'bbox': '-86412.5,-10012.5,-80587.5,-6487.5',
    'width': '768',
    'height': '464',
    'srs': 'EPSG:3763',
    'format': 'image/png',
    'info_format': 'application/json',
    'x': str(x),
    'y': str(y)
}

# Enviar a solicitação HTTP para obter as informações do modelo
response = requests.get(url_wms, params=params)

if response.status_code == 200:
    data = response.json()
    features = data.get('features')
    if features:
        gray_index = features[0]['properties'].get('GRAY_INDEX')
        if gray_index:
            print('Índice de Cinza:', gray_index)
        else:
            print('Índice de Cinza não encontrado.')
    else:
        print('Nenhuma característica encontrada na resposta.')
else:
    print('Falha ao recuperar as informações do modelo. Código de status:', response.status_code)

Gray Index: -44.52616500854492

Deste modo, podemos confirmar que os valores são iguais ao do sistema implementado.

Podemos até visualizar a localização do valor de x e de y, na imagem guardada no PC.

# Visualizar as coordenadas na imagem
img = mpimg.imread('mbat25m-CanhaoNazare.png')
plt.imshow(img)
plt.scatter(x, y, color='red', marker='x')
plt.show()

 

6 – Conclusão

Em conclusão, neste tutorial, explicamos como extrair informações de um serviço WMS usando Python. Utilizamos as bibliotecas requests, urllib.parse, pyproj, para realizar as tarefas necessárias.

Começamos por analisar a URL do serviço WMS e extrar os parâmetros relevantes usando a biblioteca urllib.parse. De seguida, realizamos a conversão das coordenadas para o sistema de coordenadas do mapa usando a biblioteca pyproj. Através dessas etapas, obtivemos as coordenadas de pixel correspondentes às coordenadas geográficas de interesse.

Usamos a biblioteca requests para fazer a solicitação HTTP e especificamos os parâmetros necessários, incluindo as coordenadas de pixel obtidas anteriormente. Depois, analisamos a resposta e extraímos o valor do atributo GRAY_INDEX, que representa a profundidade desejada.

Esse processo permitiu a extração de informações específicas de um serviço WMS de uma forma programática, possibilitando a obtenção de dados relevantes para análise e visualização.

Espero que este tutorial tenha sido útil e fornecido uma compreensão básica de como extrair dados de um serviço WMS usando Python.