Uploaded by Geografia Recursos Virtuais

Mesclagem, recorte e reprojeção de raster | Analytics Vidhya

advertisement
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
1 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Esta é sua última história gratuita somente para membros neste mês.
Faça upgrade para acesso ilimitado.
Python para geociências: fusão raster, recorte
e reprojeção com rasterio
Aprenda a executar a reprojeção raster, recorte e mesclagem usando o pacote
rasterio para Python
Maurício Cordeiro
Seguir
3 de abril · 10 min de leitura
Introduction
Welcome back for the 5th part of this series. On the previous Python for Geosciences
post (here), we learned how to work with bit masks provided by satellite imagery,
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
2 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
specifically for the case of the Landsat 8. It is very handful to mask undesired pixels or
to select specific targets of interest. However, the pixel classification list of Level 2A
processors is not always the same, or they are not reliable enough, and sometimes we
need to use a mask provided by a different source/provider.
Last week, for example, I had prepare some water masks from the Global Water
Surface Dataset [1], available to download here, to superpose with data from 5
different Sentinel 2 tiles. The Global Water Surface Dataset is provided by the
European Commission and "… maps the location and temporal distribution of water
surfaces at the global scale over the past 3.6 decades, and provides statistics on their
extent and change to support better informed water-management decisionmaking.". It is a very handful database for global water-related research. As I had only
5 sites to analyze, I decided to do all the pre-processing manually using QGIS. By preprocessing, I mean manually reprojecting, clipping and merging whenever necessary.
However, all of this could be automated by using a package that we have already seen,
the rasterio. With that in mind, I decided to write about it. Let’s go.
Step 1- Understanding the problem
First step is to understand the problem we are facing. Why should we care about these
things if we already know how to open images and manipulate them as Arrays in
Python?
In the previous posts we used the MNDWI index to create a water masks for our
raster image of the Amazon region. Now, suppose we want to compare our results
with a map of occurrence of water, like the one provided by the Global Water Surface.
Let’s start by downloading the reference maps from https://global-surfacewater.appspot.com/download. The data is available in tiles divided by 10 x 10 degrees
of latitude and longitude. The area we are interested is divided in two different tiles,
70W 0N and 60W 0N. We can download them manually by clicking in the
corresponding tile and selecting the occurrence link that appears just bellow (Figure
1). The two tiles we need are marked in orange.
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
3 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Figure 1: Global Water Surface Dataset grid. Source: https://global-surface-water.appspot.com/download
Assim que tivermos baixado os dados, podemos abrir esses dois blocos usando
rasterio . Além disso, também carregaremos nossa imagem usando
load_landsat_image , definido nos posts anteriores, mas com uma modificação
muito simples. Em vez de retornar apenas o dicionário de imagens com as bandas
como matrizes, também retornaremos um dicionário com os conjuntos de dados (eles
serão importantes na próxima seção).
No final, usamos o
subplots
função de matplotlib para exibir as imagens
carregadas recentemente.
1
from rasterio.warp import reproject
2
3
water1_reproj, water1_reproj_trans = reproject(source=rasterio.band(water1_ds, 1),
4
dst_crs=image_ds['B2'].profile['crs'],
5
dst_resolution=(30, 30)
6
)
7
8
water2_reproj, water2_reproj_trans = reproject(source=rasterio.band(water2_ds, 1),
9
10
11
pfg_05_02.py hosted with ❤ by GitHub
dst_crs=image_ds['B2'].profile['crs'],
dst_resolution=(30, 30)
)
view raw
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
4 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Saída de código.
A primeira coisa que você deve ter notado é que os arrays têm tamanhos diferentes.
Podemos imprimir as formas para verificar:
imprimir (rgb.shape, water1_array.shape, water2_array.shape)
resultado:
(7761, 7601, 3) (40000, 40000) (40000, 40000)
Então, como podemos sobrepor e comparar essas matrizes? Primeiro, precisamos
entender por que eles parecem tão diferentes.
Etapa 2 - Sistemas de referência de coordenadas
Quando carregamos uma imagem raster de satélite em um array Python, é apenas
isso, um array. Não temos informações sobre a localização desses pixels na Terra.
Para isso, duas coisas são necessárias:
• Um sistema (lógica) para mapear localizações terrestres em coordenadas (Sistema
de Referência de Coordenadas); e
• Algo que nos diga onde neste sistema de coordenadas está nosso array
(GeoTransformation).
A dará aqui uma breve introdução aos CRSs para entender como manipular
corretamente nossa imagem raster, mas existem outros bons recursos online se você
quiser se aprofundar neste assunto.
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
5 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Tipos de sistemas de referência de coordenadas
Os sistemas de referência de coordenadas, ou sistemas de referência espacial,
descrevem como podemos mapear a superfície da Terra em coordenadas. Existem
dois tipos principais:
• Sistemas de Coordenadas Geográficas: no GCS, o modelo matemático tenta
combinar a posição na Terra aproximando a Terra de um elipsóide (qual
dependerá do Datum que estamos usando). As coordenadas são então medidas
em graus (latitude e longitude). Os GCS são os melhores para análise global
(Figura 2-a), no entanto, as distâncias (e áreas) são distorcidas. Por exemplo, um
grau de longitude ao redor do equador tem uma distância diferente de um grau de
longitude próximo aos pólos;
• Sistemas de Coordenadas Projetadas: o PCS representa a superfície da Terra (ou
uma parte dela) em um sistema de coordenadas bidimensional plano (por
exemplo, um pedaço de papel plano ou tela de computador). É necessário usar
uma projeção de mapa, para transformar a Terra de sua forma esférica (3D) para
uma forma plana (2D). Existem três tipos principais de projeções cartográficas
que podem ser visualizadas na Figura 2-b (cilíndrica, plana e cônica). Eles foram
concebidos para diferentes objetivos: preservar ângulos, preservar áreas, etc.
Figura 2: (a) Exemplo de Sistema de Coordenadas Geográficas, fonte: ESRI; (b) exemplos de projeções de
mapas, fonte: UCGIScience ( https://gistbok.ucgis.org/bok-topics/map-projections )
Embora nossos arrays carregados recentemente não tenham nenhuma informação
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
6 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
geográfica, vamos acessar o conjunto de dados carregado por rasterio . O atributo
profile é um dicionário, e se o imprimirmos (abaixo), podemos ver que uma das
chaves é "crs" (em negrito ). Observe que as máscaras de ocorrência de água têm
= CRS.from_epsg(4326)
e a imagem da paisagem tem
CRS
CRS = CRS.from_epsg(32620) .
imprimir ('Imagem: \ n', imagem_ds ['B2']. perfil)
print ('Máscara de água 1: \ n', water1_ds.profile)
print ('Máscara de água 2: \ n', water2_ds.profile)
Resultado:
Imagem:
{'driver': 'GTiff', 'dtype': 'uint16', 'nodata': 0,0, 'largura':
7601, 'altura': 7761, 'contagem': 1, 'crs': CRS.from_epsg (32620 ) ,
'transformar': afim (30,0, 0,0, 658185,0,
0.0, -30.0, -203985.0), 'blockxsize': 256, 'blockysize': 256,
'tiled': True, 'compress': 'deflate', 'interleave': 'band'}
Máscara de água 1:
{'driver': 'GTiff', 'dtype': 'uint8', 'nodata': Nenhum, 'largura':
40000, 'altura': 40000, 'contagem': 1, 'crs': CRS.from_epsg (4326 )
, 'transformar': afim (0,00025, 0,0, -70,0,
0.0, -0.00025, 0.0), 'blockxsize': 256, 'blockysize': 256, 'tiled':
True, 'compress': 'lzw', 'intercalar': 'band'}
Máscara de água 2:
{'driver': 'GTiff', 'dtype': 'uint8', 'nodata': Nenhum, 'largura':
40000, 'altura': 40000, 'contagem': 1, 'crs': CRS.from_epsg (4326 )
, 'transformar': afim (0,00025, 0,0, -60,0,
0.0, -0.00025, 0.0), 'blockxsize': 256, 'blockysize': 256, 'tiled':
True, 'compress': 'lzw', 'intercalar': 'band'}
Observe que temos apenas um código, chamado EPSG. EPSG é um registro público de
sistemas de coordenadas e cada um recebe um número exclusivo (o código EPSG).
Nota: EPSG significa European Petroleum Survey Group e é uma organização que
mantém um banco de dados de parâmetros geodésicos com padrão códigos , os
códigos EPSG (http://epsg.org) .
Se pesquisarmos na base de dados ESPG (ou google), por esses códigos EPSG,
podemos ter a descrição correta de cada CRS que temos.
• EPSG 4326: WGS 84 Geographic
• EPSG 32620: Zona UTM projetada 20N
GeoTransformação
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
7 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Agora que sabemos quais são os CRSs de nossas imagens, ainda precisamos entender
como podemos mapear os índices de array (linhas e colunas) para as coordenadas
geográficas de nosso CRS. O método mais comum é considerar nosso array como uma
grade regular com espaçamento uniforme (cada célula tem o mesmo tamanho). Nesse
caso, basta saber a localização correta de uma célula (canto superior esquerdo) e as
dimensões da célula (largura e altura) nas unidades CRS (graus para o CRS geográfico
e metros para o UTM, por exemplo). O mapeamento do índice da matriz (linha,
coluna) em coordenadas CRSs é feito pela GeoTransformation. Esta transformação
também é armazenada no perfil do conjunto de dados e se a aplicarmos a qualquer
posição do conjunto de dados, receberemos sua coordenada CRS correspondente.
Vamos tentar aplicar a transformação de qualquer banda (B2, por exemplo) à
primeira célula superior esquerda (0, 0) e à célula inferior direita (largura, altura).
Para aplicá-lo, podemos usar AffineMatrix * (coluna, linha) e os resultados serão (x, y)
nas unidades CRSs. Então, podemos comparar o resultado com as extensões do
conjunto de dados e confirmar se eles correspondem perfeitamente.
1
# top left cell
2
first_cell = (0, 0)
3
# bottom right cell
4
last_cell = (image_ds['B2'].profile['width'], image_ds['B2'].profile['height'])
5
6
print(image_ds['B2'].profile['transform'] * first_cell)
7
print(image_ds['B2'].profile['transform'] * last_cell)
8
9
print(image_ds['B2'].bounds)
pfg_05_03.py hosted with ❤ by GitHub
view raw
(658185.0, -203985.0)
(886215.0, -436815.0)
BoundingBox (left = 658185.0, bottom = -436815.0, right = 886215.0,
top = -203985.0)
Etapa 3 - Reprojetando
Agora que sabemos como funciona um CRS, é fácil entender por que não podemos
simplesmente comparar os pixels de nossos arrays. Portanto, a primeira coisa que
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
8 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
temos que fazer é converter os arrays para o mesmo CRS. À medida que vai querer
sobrepor a máscara de água em nossa imagem Amazon, estamos indo para converter
as máscaras de água a partir EPSG 4326 para EPSG 32620. Para realizar a reprojeção
usaremos o Reproject função definida no warp módulo do RasterIO . Passaremos
como argumentos, a fonte como um objeto de banda rasterio (essa é a razão da
rasterio.band aplicada ao conjunto de dados), o CRS desejado e a resolução de
destino.
1
from rasterio.warp import reproject
2
3
water1_reproj, water1_reproj_trans = reproject(source=rasterio.band(water1_ds, 1),
4
dst_crs=image_ds['B2'].profile['crs'],
5
dst_resolution=(30, 30)
6
)
7
8
water2_reproj, water2_reproj_trans = reproject(source=rasterio.band(water2_ds, 1),
9
10
11
dst_crs=image_ds['B2'].profile['crs'],
dst_resolution=(30, 30)
)
pfg_05_02.py hosted with ❤ by GitHub
view raw
Step 4- Merging
Para tornar as coisas um pouco mais difíceis aqui, nossa imagem do Landsat 8 está
dividida em dois blocos de máscara de água diferentes, portanto, não podemos
simplesmente cortar a parte que desejamos. Primeiro, mesclaremos as duas máscaras
de água em uma. Isso será feito usando o merge função de rasterio.merge módulo.
Nota: A função de mesclagem requer dois conjuntos de dados rasterio, no entanto,
temos os arrays reprojetados (e as transformações) em seu lugar. Nesse caso, temos
que gravar nossos resultados reprojetados em novos conjuntos de dados. Em vez de
gravar novos conjuntos de dados no arquivo, usaremos a
rasterio.io.MemoryFile classe para manter tudo na memória.
Vamos definir uma create_dataset função que receberá o array, o CRS e a
transformação para retornar um na memória rasterio conjunto de dados . Depois de
termos nossos conjuntos de dados, seremos capazes de chamar a função de
mesclagem. No final, exibiremos a máscara de água mesclada.
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
9 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
1
from rasterio.io import MemoryFile
2
from rasterio.merge import merge
3
4
def create_dataset(data, crs, transform):
5
# Receives a 2D array, a transform and a crs to create a rasterio dataset
6
memfile = MemoryFile()
7
dataset = memfile.open(driver='GTiff', height=data.shape[0], width=data.shape[1], count
8
9
transform=transform, dtype=data.dtype)
dataset.write(data, 1)
10
11
return dataset
12
13
water1_reproj_ds = create_dataset(water1_reproj[0], image_ds['B2'].profile['crs'], water1_reproj_tra
14
water2_reproj_ds = create_dataset(water2_reproj[0], image_ds['B2'].profile['crs'], water2_reproj_tra
15
16
merged, transf = merge([water1_reproj_ds, water2_reproj_ds])
17
18
plt.figure(figsize=(12,6))
19
plt.imshow(merged[0])
pfg_05_04.py hosted with ❤ by GitHub
view raw
Saída de código.
A fusão parece ter funcionado bem, mas a questão é: Onde fica a nossa Área de
Interesse (região de Manaus) aqui?
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
10 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Etapa 5 - Corte
Agora que temos um grande mapa de ocorrência de água mesclado no mesmo CRS da
imagem do Landsat 8, é hora de recortá-lo usando as extensões de nossa Área de
Interesse. Portanto, a primeira coisa a fazer agora é obter as extensões da imagem
Landsat. Vimos na Etapa 2 que podemos usar o método bounds para obter as
extensões de um conjunto de dados. No entanto, o método de cultivo de rasterio
recebe um GeoJSON como entrada para fazer o cultivo.
Podemos extrair o GeoJSON de nossa imagem landsat fazendo isso usando a
rasterio.features.shapes função , que nos retornará um GeoJSON das formas que
ele identifica em um determinado conjunto de dados. Como queremos a imagem
inteira, podemos passar apenas um array vazio com o mesmo formato da imagem
Landsat. O truque aqui é que as funções de formas retornam um “gerador”, que nos
permite iterar os vários resultados. Não entraremos em detalhes de rendimento e
geradores aqui, mas como esperamos apenas uma saída (o polígono com a imagem
inteira), usaremos a incorporada do python próxima função , assim:
próximo (formas (np.zeros_like (img ['B2']), transformar = imagem_ds
['B2']. perfil ['transformar']))
Resultados:
({'tipo': 'Polígono',
'coordenadas': [[(658185.0, -203985.0),
(658185.0, -436815.0),
(886215.0, -436815.0),
(886215.0, -203985.0),
(658185.0, -203985.0)]]},
0.0)
Como antes, a corte função de requer um conjunto de dados como argumento, então
vamos criar o
merged_ds
antecipadamente. Em seguida, recortaremos as extensões
que acabamos de recuperar e exibiremos os resultados.
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
11 de 16
1
from rasterio.features import shapes
2
from rasterio.mask import mask
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
3
4
# get the extents of the Landsat image as a geometry
5
extents, _ = next(shapes(np.zeros_like(img['B2']), transform=image_ds['B2'].profile['transform'
6
7
# create a dataset of the merged water mask
8
merged_ds = create_dataset(merged[0], image_ds['B2'].profile['crs'], transf)
9
10
# creop the water mask to the Landsat extents
11
cropped, crop_transf = mask(merged_ds, [extents], crop=True)
12
13
plt.figure(figsize=(10, 10))
14
plt.imshow(cropped[0])
pfg_05_05.py hosted with ❤ by GitHub
view raw
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
12 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Saída de código.
Etapa 6 - Superpondo as camadas
Em novo, podemos usar a plot_masked_rgb função definida na parte 4 para
sobrepor a máscara com toda a imagem Landsat. Um pequeno ajuste é necessário no
cropped
forma, como a do rasterio máscara função de retornou pixel adicional que
pode ser descartado. Como a máscara de ocorrência de água da Água de Superfície
Global é fornecida em uma escala de 0-100 (100 significa 100% de ocorrência de água
ao longo do tempo) e esperamos uma máscara VERDADEIRO / FALSO, podemos
usar o operando lógico maior do que para obter os pixels com mais de 80% de água:
mask = cropped[0]>80 .
Além disso, iremos ignorar os pixels que não têm valor na
imagem Landsat, através do comando
mask = np.where(img[‘B2’] == 0, 0, mask) e
traçar nossa suposta imagem, como de costume.
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
13 de 16
1
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
def plot_masked_rgb(red, green, blue, mask, color_mask=(1, 0, 0), transparency=0.5, brightness
2
3
# to improve our visualization, we will increase the brightness of our values
4
max_value = np.max([red.max(), green.max(), blue.max()])
5
red = red / max_value * brightness
6
green = green / max_value * brightness
7
blue = blue / max_value * brightness
8
9
red = np.where(mask==True, red*transparency+color_mask[0]*(1-transparency), red)
10
green = np.where(mask==True, green*transparency+color_mask[1]*(1-transparency), green
11
blue = np.where(mask==True, blue*transparency+color_mask[2]*(1-transparency), blue)
12
13
rgb = np.stack([red, green, blue], axis=2)
14
15
return rgb
16
17
mask = cropped[0]>80
18
shape = img['B2'].shape
19
mask = mask[:shape[0], :shape[1]]
20
21
mask = np.where(img['B2'] == 0, 0, mask)
22
23
masked_rgb = plot_masked_rgb(red=img['B4'],
24
green=img['B3'],
25
blue=img['B2'],
26
mask=mask,
27
color_mask=(0, 0, 1),
28
brightness=3
29
)
30
31
plt.figure(figsize=(15, 15))
32
plt.imshow(masked_rgb)
pfg_05_06.py hosted with ❤ by GitHub
view raw
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
14 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Saída de código.
Caderno
Como sempre, aqui está o bloco de notas com todo o código necessário para executar
esses exemplos.
Sign up for Analytics Vidhya News Bytes
By Analytics Vidhya
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
15 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
Latest news from Analytics Vidhya on our Hackathons and some of our best articles! Take a look.
Get this newsletter
Python Programming
About Write
Geoscience
Emails will be sent to geografianoturnolaranjeiras@gmail.com.
Not you?
Remote Sensing
Satellite Imagery
Tutorial
Help Legal
Get the Medium app
pfg_05_nb01.ipynb hosted with ❤ by GitHub
view raw
Conclusão
Hoje, apresentamos uma visão geral de alguns conceitos importantes sobre dados
geoespaciais, como Sistemas de Referência de Coordenadas e GeoTransforms e como mover de
um sistema para outro usando o rasterio pacote . As tarefas de reprojetar, recortar e mesclar
geralmente são necessárias quando precisamos comparar dados salvos em diferentes sistemas
de projeção. Eles podem ser feitos usando software GIS como QGIS ou ArcGIS da ESRI, mas
com Python é possível escrever uma cadeia para automatizar essas etapas.
Hope you have enjoyed, stay tuned and see you next story!
Previous Posts
Link for the previous posts of Python for Geosciences series:
07/10/2021, 08:55
Mesclagem, recorte e reprojeção de raster | Analytics Vidhya
16 de 16
https://medium.com/analytics-vidhya/python-for-geosciences-raster-mer...
• Part 1- Working with Satellite Images
• Part 2- Satellite Image Analysis
• Part 3- Spectral Analysis
• Part 4- Raster bit masks explained
• Part 6- Scatter plots and PDF Reports
References:
[1] Pekel, J.-F.; Cottam, A.; Gorelick, N.; Belward, A. S. High-Resolution Mapping of Global
Surface Water and Its Long-Term Changes. Nature 2016, 540 (7633), 418–422.
https://doi.org/10.1038/nature20584.
07/10/2021, 08:55
Download