top of page
  • jalesbussinguer

Automatizando o processamento de imagens de radar com Python

Construindo um script para o processamento de imagens Sentinel-1 com o snappy


Este estudo tem origem no meu projeto final de graduação do curso de Engenharia Ambiental na Universidade de Brasília, desenvolvido em 2019. Em resumo, nesse projeto eu precisava processar imagens da constelação Sentinel-1 (ESA), radar de abertura sintética (SAR), para extrair extensões de rios que serviriam para calibrar um modelo hidráulico de rios amazônicos.


Esse foi o meu primeiro contato com o processamento de imagens de radar. Na época, tive que aprender do zero toda a teoria de aquisição de imagens SAR para entender quais os tipos de processamentos necessários para corrigir as imagens brutas além de aprender a utilizar um software totalmente novo para mim.


Foram meses de pesquisas e experimentos até chegar a um roteiro de processamento viável capaz de retornar o resultado que eu precisava pro meu projeto. Contudo, esse roteiro não era nada prático. Devido à minha inexperiência no assunto, perdia muito tempo fazendo todos os processamentos manualmente, um por um, no SNAP (SeNtinel Application Program). Além disso, ocorriam muitos erros, o que tornava o processo ainda mais demorado e estressante.


Em meados de maio de 2020 decidi intensificar os estudos de programação em Python, onde um dos objetivos era aprender a automatizar processos por meio de scripts, tendo esse problema como principal motivação. Neste artigo vou apresentar um pouco do que consegui de lá pra cá.

 

Dados


Para este projeto, utilizei uma imagem do satélite Sentinel-1A do dia 20/12/2018. A cena compreende a região da confluência dos rios Negro e Solimões, nas proximidades do município de Manaus (AM), área de estudo do meu projeto final de graduação.


A imagem foi adquirida em formato .zip por meio da Copernicus Open Acces Hub, plataforma da ESA para a distribuição gratuita das imagens do Sentinel-1 e outros sistemas sensores.

Imagem bruta adquirida

A cena possui as seguintes especificações técnicas:

  • Id: S1A_IW_GRDH_1SDV_20181220T093910_20181220T093935_025107_02C588_9290;

  • Data: 20/12/2018;

  • Tipo de produto: Level 1 - GRD;

  • Modo de aquisição: IW;

  • Número de órbita: 25107;

  • Polarizações (canais): VH, VV;

  • Pixels: 10 x 10 m

Informações adicionais sobre a missão Sentinel-1 podem ser encontradas aqui.


A imagem bruta possui quatro bandas no total: Amplitude_VV, Intensity_VV, Amplitude_VH e Intensity_VH. As bandas "amplitude" contém dados de amplitude e fase do sinal captado pelo sensor e as bandas "intensity" contém a intensidade do sinal.


Nesse projeto, utilizei a banda Intensity_VH, que caracteriza a intensidade do sinal que foi despolarizado, ou seja, foi emitido pelo sensor na polaridade vertical (V) e captado na polaridade horizontal (H). Ao utilizar essa banda, estou considerando os efeitos de despolarização do sinal causada pela interação das microondas com os diversos objetos que compõem a cena.


Para ilustrar essa decisão, tomo como exemplo os corpos hídricos e as florestas. No primeiro caso, os rios funcionam como uma espécie de espelho devido à sua superfície pouco rugosa. Sendo assim, o sinal incidente sobre essa superfície é retroespalhado de forma especular na direção oposta ao sensor e sofre pouca despolarização. Dessa forma, os corpos hídricos são percebidos na cena em cores mais escuras.


No caso das florestas, por serem alvos volumétricos devido à estrutura das árvores e suas folhas, o sinal é retroespalhado diversas vezes de maneira difusa e parte do sinal é despolarizado. Sendo assim, percebemos as florestas em tons mais claros nessa banda.


A imagem bruta, quando carregada, se apresenta "invertida". Tal efeito ocorre devido ao modo como as imagens são adquiridas por um satélite em órbita descendente. Além disso, a imagem bruta apresenta um histograma que dificulta sua aplicação direta para estudos de mapeamento, necessitando de correções. Tais procedimentos serão tratados a seguir.

Para mais detalhes sobre a teoria de imageamento SAR, ver o capítulo 10, seção 10.5 do livro "Introduction to Microwave Remote Sensing" (Woodhouse, 2006).

 

Roteiro de processamento


O intuito de estabelecer um roteiro de processamento para imagens de radar é aprimorar as características geométricas e radiométricas das imagens para uma melhor diferenciação entre as feições que compõem a cena.


Para o meu projeto, eu precisava de uma imagem em que fosse capaz de separar os corpos hídricos das outras feições sem precisar de uma classificação. Dessa forma, fui buscar na literatura alguns trabalhos que tinham objetivos parecidos e que demonstrassem o objetivo de cada processamento. Os dois principais trabalhos em que me baseei foram Liu (2016) e Huang et al. (2017). Além disso, utilizei também a documentação do próprio SNAP como referência para entender os parâmetros de cada processamento.


O SNAP basicamente funciona como uma coleção de ferramentas executáveis e APIs (Application Programming Interfaces) desenvolvidas para o processamento de dados de sensoriamento remoto. Dentro da estrutura do software, cada ferramenta é chamada de operador e pode ser ser utilizada dentro de uma estrutura de processamento sequencial.


Após muita leitura e experimentos, cheguei ao roteiro de processamento abaixo. Este foi construído seguindo uma lógica sequencial apresentada a seguir:

Após a leitura do arquivo, é feita a atualização do arquivo de órbita (Apply Orbit File). Esse processamento é feito pois os vetores de posicionamento de órbita contidos nos metadados originais das imagens geralmente não são acurados. Nesse caso, o algoritmo deste operador atualiza os metadados de órbita com base em arquivos precisos que são gerados após a geração da imagem.


Em seguida, um recorte da cena (subset) é feito, pois a área de estudo é apenas uma parte da cena. Contudo, o principal motivo de recortar a imagem é diminuir o volume de dados e o tempo de processamento.

O polígono rosa indica a área de recorte da cena

A calibração radiométrica (Calibration) é feita para que os números digitais dos pixels da imagem sejam diretamente relacionados ao nível de retroespalhamento da superfície medido pelo sensor. Dessa forma, após a aplicação desse processamento, os pixels apresentam os coeficientes de retroespalhamento normalizados da região imageada. Além disso, a calibração radiométrica é essencial para a comparação de imagens adquiridas por um mesmo sensor em diferentes épocas e/ou em diferentes modos.


A filtragem de ruído speckle é feita pois imagens SAR apresentam uma textura característica similar a uma mistura de sal e pimenta causada por interferências construtivas e destrutivas no sinal que retorna ao sensor. O ruído speckle degrada a qualidade da imagem e dificulta a interpretação das feições da cena. Esse tipo de filtragem ocorre no domínio espacial, onde o filtro utiliza as informações dos pixels vizinhos para corrigir os efeitos do ruído speckle. Neste estudo foi utilizado o filtro de Lee com um kernel de 3x3.


A correção geométrica (Range Doppler Terrain Correction) é feita pois, devido a variações topográficas da cena e ao fato de que o sensor capta imagens obliquamente à superfície, as distâncias medidas em relação à superfície podem ser distorcidas nas imagens. Com isso, o algoritmo faz uma ortorretificação da imagem com base nos vetores de posicionamento da cena, dados de timing do sensor, parâmetros geométricos da aquisição da imagem juntamente com um Modelo Digital de Elevação (MDE) para calcular a geolocalização precisa dos objetos da cena. Tal processamento também corrige o efeito invertido da imagem bruta.


Por fim, os valores dos pixels são convertidos para uma escala em decibéis e a imagem é salva na pasta designada. O resultado dessa rotina é uma imagem geometricamente corrigida e com pixels que tem significado físico.

Após o processamernto, a imagem apresenta um histograma bimodal bem definido, isto é, podemos perceber dois "picos" de frequências bem separados. Com isso, o mapeamento de feições como os corpos hídricos é facilitado, bastando estabelecer um limite (threshold) que separa as duas modas.


Exemplo de histograma das imagens após a rotina de processamento
 

Implementação do script em Python


O script desenvolvido utiliza o snappy, módulo em Python baseado na API em Java do SNAP, como base para o processamento das imagens. Para realizar cada processamento é necessário instanciar o operador e seus parâmetros.


Importante: para utilizar o snappy é preciso ter instalado o SNAP na sua máquina. Um tutorial de como configurar o snappy pode ser lido aqui. Outro detalhe importante é o snappy só funciona em algumas versões específicas do interpretador Python, como o 2.7, 3.3, 3.4 e o 3.6.


O script de processamento segue a sequência lógica da rotina de processamento descrita anteriormente. Toda a construção foi feita em um notebook no Jupyter Notebooks, por questões de reprodutibilidade dos resultados de cada etapa. Este pode ser acessado abaixo:


A estrutura do código segue a seguinte sequência:

  1. Importação dos módulos do snappy e outras bibliotecas;

  2. Criação de uma função de plotagem da imagem;

  3. Importação do arquivo da imagem;

  4. Processamentos;

  5. Escrita do arquivo de saída (salvando a imagem).

 

O primeiro passo foi importar os módulos do snappy utilizados para os processamentos. Foram importadas também as bibliotecas numpy e matplotlib para auxiliarem na plotagem das imagens. Além disso, foi instanciado um reutilizador de memória RAM, o Garbage Collector do Java, que localiza objetos não utilizados e os exclui para liberar memória RAM.

Em seguida, criei uma função para plotar imagens, chamada "plotBand". Escolhi essa abordagem de função pois a intenção é plotar a imagem depois de cada processamento sem a necessidade de reescrever o mesmo bloco de código cada vez que uma imagem for plotada.


O algoritmo segue a seguinte estrutura:

  1. Leitura da largura e altura em número de pixels da imagem:

  2. Criação de uma matriz de zeros de dimensões largura x altura;

  3. Leitura dos valores de pixels e população da matriz de zeros;

  4. Formatação da imagem, para ser apresentada na horizontal;

  5. Plotagem da imagem em níveis de cinza utilizando a matriz com os valores dos pixels.


Para a importação da imagem, criei uma variável product e utilizei o módulo ProductIO para ler o arquivo .zip a partir do caminho do arquivo no disco. Este módulo possui a função .readProduct( ) que faz a leitura tanto da imagem quanto dos metadados.


Na importação da imagem, aproveitei para explorar algumas informações básicas da cena como a altura e o comprimento em pixels, o nome do produto e a lista de bandas disponíveis. Essa mesma estrutura de código que retorna informações sobre a cena foi repetido após cada processamento, a fim de monitorar as mudanças que ocorrem com a imagem ao longo dos processamentos.


A construção dos processamentos segue um padrão, repetido em todos os casos. Cada tipo de processamento é relacionado a um operador dentro da estrutura do SNAP, que deve ser "chamado" pelo código, tendo o módulo jpy como ponte entre o Python e o Java.


Para carregar o operador dentro do sistema, utilizei o módulo GPF (Graph Processing Framework), que contém os algoritmos dos operadores. Este faz o carregamento da instância padrão dos operadores, isto é, o operador apresentará parâmetros padronizados que devem (ou não) ser modificados, de acordo com o objetivo do processamento.

GPF.getDefaultInstance().getOperatorSpiRegistry().loadOperatorSpis()

Em cada caso, é necessário criar uma variável de parâmetros dos operador (parameters). Para isso, é utilizado um HashMap vazio, estrutura de dados do Java alusiva à um dicionário em Python. Em seguida esse HashMap é populado com os parâmetros específicos de cada operador.


Para executar o processamento, utilizei a função .createProduct( ) do GPF. Nessa função devem ser discriminados o tipo de processamento, os parâmetros e o "alvo" do processamento.

Produto = GPF.createProduct('processamento', parâmetros, alvo)

A cada processamento, o produto foi armazenado em uma variável utilizada como alvo para o próximo processamento. Dessa forma, os processamentos se tornam sequenciais e automatizados. O detalhamento das especificidades de cada processamento está na própria estrutura do notebook.


Por fim, para salvar a imagem, utilizei mais uma vez o módulo ProductIO com a função .writeProduct( ), indicando o nome do último produto gerado, o caminho para a pasta de salvamento e o formato do arquivo de saída.

ProductIO.writeProduct('produto', 'C:/Users/...', 'formato')

Conclusões


Nesse projeto executei uma série de processamentos em uma imagem do satélite Sentinel-1 em uma rotina automatizada. A abordagem do notebook foi adotada pois se trata de um estudo, onde é interessante visualizar o resultado de cada processamento, a fim de identificar erros.


Os mesmos princípios adotados no notebook podem ser utilizados para a construção de um script .py onde não há a supervisão do programador. Nessa abordagem podem ser criadas funções para cada processamento, tornando o script mais legível e otimizado.


A principal vantagem de utilizar um script como esse é poder incluir esses processamentos em sistemas totalmente automatizados, onde há a introdução de um dado bruto, processamento de dados e a conversão para o produto final. Um exemplo disso pode ser o monitoramento de riscos de cheias em áreas ribeirinhas, onde introduz-se uma imagem de radar bruta e obtém-se como produto final um mapa das áreas de risco.


Outro exemplo interessante é o contexto do meu projeto final, onde é possível utilizar essa mesma estrutura para montar um sistema automatizado que obtém um dado vetorial das máscaras das extensões dos rios a partir de imagens de radar. Tais dados, quando interseccionados com um Modelo Digital de Elevação (MDE), retornam a cota altimétrica do rio, podendo ser utilizada para a calibração de modelos hidráulicos.


Por fim, na execução desse projeto, uma das dificuldades que tive nesse estudo foi a questão da limitação de hardware. O fato de possuir um poder de processamento mediano pra atualidade, limitou bastante a quantidade de dados processados. Além disso, por vezes a plotagem da imagens (principalmente após a correção geométrica) demorava bastante tempo.


Referências Bibliográficas


HUANG, W.; DeVRIES, B.; HUANG, C.; JONES, J.; LANG, M. & CREED, I. (2017). Automated Extraction of Inland Surface Water Extent from Sentinel-1 Data. Anais do IGARSS 2017, p. 2259-2262.


LIU, C. (2016). Analysis of Sentinel-1 SAR data for mapping standing water in the Twente region. Dissertação de Mestrado, University of Twente, Faculty of GeoInformation Science and Earth Observation, Twente, França, 47p.


JENSEN, J. R. (2014). Remote Sensing Of The Environment - An Earth Resource

Perspective. 2. ed. Pearson, Harlow, Essex, Inglaterra, 505p.


WOODHOUSE, I. H. (2006). Introduction to Microwave Remote Sensing. CRC Press,

Boca Raton, E.U.A., 400p.

 




Comments


bottom of page