Extração de Dados de um Serviço WMS Remotamente
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.