Leia nosso artigo sobre

.

Um guia passo a passo sobre como coletar e pré-processar imagens de satélite data para algoritmos de aprendizado de máquina

Este artigo é a primeira parte de uma série de duas partes que explora os usos de algoritmos de aprendizado de máquina em imagens de satélite. Aqui, vamos nos concentrar nas etapas de coleta e pré-processamento do data, enquanto a segunda parte mostrará o uso de vários algoritmos de aprendizado de máquina.

TL;DR
Este artigo abordará:

  • Proporcionar ao senhor uma melhor compreensão das imagens de satélite
  • Mostrar ao senhor que tipo de imagem pode ser coletada em código aberto
  • Orientá-lo nas etapas necessárias para ter imagens “prontas para o aprendizado de máquina”.

    Usaremos a detecção e a classificação de campos agrícolas como exemplo. O Python e o jupyter notebook são usados para as etapas de pré-processamento. O notebook do jupyter para reproduzir as etapas está disponível no github.
    Este artigo pressupõe fundamentos básicos em ciência data e python.

  • A visão computacional é um ramo fascinante do aprendizado de máquina que vem se desenvolvendo rapidamente nos últimos anos. Com acesso público a muitas bibliotecas de algoritmos prontos para uso (Tensorflow, OpenCv, Pytorch, Fastai ...), bem como os datasets de código aberto (CIFAR -10, Imagenet, IMDB ...) é muito fácil para um cientista data obter experiência prática nesse tópico.

    Mas o senhor sabia que também pode acessar imagens de satélite de código aberto? Esses tipos de imagens podem ser usados em uma grande variedade de casos de uso (agricultura, logística, energia...). No entanto, elas representam desafios adicionais para um cientista data devido ao seu tamanho e complexidade. Escrevi este artigo para compartilhar alguns dos meus principais aprendizados ao trabalhar com elas.

    Etapa 1 - Selecione a fonte do satélite aberto data

    Primeiro, o senhor precisa escolher o satélite que deseja usar. Os principais recursos a serem observados aqui são :

    • Resolução espacialO senhor sabe que a resolução mais alta é a mais alta do mundo: quantos metros são cobertos por pixel, uma resolução mais alta desbloqueará alguns casos de uso e proporcionará melhor desempenho para a maioria dos algoritmos.

    • Instrumentos disponíveisO senhor pode usar os seguintes instrumentos: os instrumentos capturarão diferentes bandas espectrais, tanto do espectro visível quanto do invisível. A utilidade das bandas varia de acordo com o caso de uso.

    • Resolução temporal Tempo entre duas visitas em um determinado ponto da Terra. Observe que muitos sistemas de satélite incluem, na verdade, vários satélites e, nesse caso, a resolução temporal global geralmente é igual à de um de seus satélites dividida pelo número de satélites.

    • Resolução radiométrica Número de valores possíveis que o instrumento captura. Quanto maior, mais precisas são as medições.

    Aqui estão os satélites cujo data está disponível gratuitamente:

    Benchmark de sistemas de satélite

    Como nosso objetivo é detectar e identificar culturas agrícolas, o espectro visível (que é usado para fornecer imagens coloridas padrão) deve ser bastante útil. Além disso, há correlações entre o nível de nitrogênio das plantações e as bandas espectrais NIR (infravermelho próximo). No que diz respeito às opções gratuitas, o Sentinel 2 é atualmente o melhor em termos de resolução, com 10 m para essas bandas espectrais, portanto, usaremos esse satélite.

    Obviamente, a resolução de 10 m é muito menor em comparação com o estado da arte em imagens de satélite, com satélites comerciais que atingem uma resolução de 30 cm. O acesso ao satélite comercial data pode desbloquear muitos casos de uso, mas, apesar da crescente concorrência com novos participantes entrando nesse mercado, eles permanecem com preços altos e, portanto, difíceis de integrar em um caso de uso em escala.

    Etapa 2 - Coletar as imagens de satélite data do Sentinel 2

    Agora que selecionamos nossa fonte de satélite, a nova etapa é fazer o download das imagens. O Sentinel 2 faz parte do Programa Copernicus da Agência Espacial Europeia. Podemos acessar seu data usando o API em python do SentinelSat.

    Primeiro, precisamos criar uma conta no site do Centro de Acesso Aberto do Copernicus. Como alternativa, observe que esse site também oferece uma maneira de consultar imagens com uma GUI.

    Uma maneira de especificar as zonas que o senhor deseja explorar é fornecer à API um arquivo geojson, que é um json contendo a posição das coordenadas GPS (latitude e longitude) de uma zona. O Geojson pode ser criado rapidamente no seguinte site.

    Dessa forma, o senhor pode consultar todas as imagens de satélite que cruzam a zona fornecida.

    Aqui listamos todas as imagens disponíveis em uma determinada zona e intervalo de tempo:

    api = SentinelAPI(
    credenciais[“nome de usuário”],
    credenciais[“senha”],
    “https://scihub.copernicus.eu/dhus”
    )

    shape = geojson_to_wkt(read_geojson(geojson_path))

    images = api.query(
    forma,
    date=(date(2020, 5, 1), date(2020, 5, 10)),
    platformname=”Sentinel-2″,
    processinglevel = “Level-2A”,
    cloudcoverpercentage=(0, 30)
    )

    images_df = api.to_dataframe(images)

    Observe o uso de argumentos:

    • dataO senhor deve definir esse intervalo tendo em mente a resolução temporal de 6 dias. Como vamos detectar plantações, definimos esse intervalo para o período pré-colheita

    • nível de processamento : O nível 2A é o nível mais avançado de pré-processamento. Por exemplo, as correções atmosféricas já foram realizadas nas imagens (para se aprofundar nos níveis de processamento)

    • cloudpercentagem de cobertura : As nuvens dificultarão a exploração de algumas imagens. Filtramos imagens com mais de 30 %, pois elas provavelmente não poderão ser usadas

    images_df

    Images_df é um pandas dataframe que contém todas as imagens que correspondem à nossa consulta. Selecionamos uma com baixa cobertura de cloud e a baixamos usando a API :

    uuid = “01d97f6b-8eb5-4edc-9261-10e3f4d437d0”
    api.download(uuid)

    Etapa 3 - Entenda quais bandas espectrais devem ser usadas e gerencie a quantização

    Após o download do arquivo zip, podemos ver que ele contém várias imagens.

    Isso ocorre porque, como dissemos na etapa 1, o Sentinel 2 captura muitas bandas espectrais e não apenas Vermelho, Verde e Azul, e cada banda é capturada em uma única imagem.

    Além disso, nem todos os instrumentos têm a mesma resolução espacial, portanto, há uma subpasta para cada resolução diferente de 10, 20 e 60 metros.

    Se verificarmos o GRANULE//IMG_DATA vemos que há uma subpasta para cada resolução diferente: 10, 20 e 60 metros como as bandas espectrais. Vamos usar aquelas com resolução máxima de 10 m, pois elas fornecem as bandas 2, 3, 4 e 8, que são azul, verde, vermelho e NIR. As bandas 7, 8 e 9, que são a borda vermelha da vegetação (bandas espectrais entre o vermelho e o NIR que marcam uma transição no valor de refletância da vegetação), também poderiam ser interessantes para a detecção de plantações, mas como são de resolução mais baixa, vamos deixá-las de lado agora

    Aqui carregamos cada banda como uma matriz numpy 2D:

    def get_band(image_folder, band, resolution=10):
    subpasta = [f for f in os.listdir(image_folder + "/GRANULE") if f[0] == "L"][0] image_folder_path = f"/GRANULE//IMG_DATA/Rm"
    image_files = [im for im in os.listdir(image_folder_path) if im[-4:] == ".jp2"] selected_file = [im for im in image_files if im.split("_")[2] == band][0]

    com rasterio.open(f"/") as infile:
    img = infile.read(1)

    retornar img

    band_dict =

    para banda em ["B02", "B03", "B04", "B08"]:
    band_dict[band] = get_band(image_folder, band, 10)

    Um teste rápido para ter certeza de que tudo está funcionando é tentar recriar a imagem de cor verdadeira (ou seja, RGB) e exibi-la usando opencv e matplotlib:

    img = cv2.merge((band_dict[“B04”], band_dict[“B03”], band_dict[“B02”]))
    plt.imshow(img)

    Imagem de satélite - Problema de intensidade de cor (Copernicus Sentinel data 2020)

    No entanto, há um problema com a intensidade da cor. Isso ocorre porque a quantização (número de valores possíveis) difere do padrão para matplotlib, que assume um valor int 0-255 ou um valor float 0-1. As imagens padrão geralmente usam uma quantização de 8 bits (256 valores possíveis), mas as imagens do Sentinel 2 usam uma quantização de 12 bits e um reprocessamento converte os valores em um inteiro de 16 bits (65536 valores).

    Se quisermos escalar um inteiro de 16 bits para um inteiro de 8 bits, deveríamos, em teoria, dividir por 256, mas isso, na verdade, resulta em uma imagem muito escura, pois não é usado todo o intervalo de valores possíveis. O valor máximo em nossa imagem é, na verdade, 16752 de 65536 e poucos pixels atingem valores superiores a 4000, portanto, a divisão por 8 proporciona uma imagem com um contraste decente

    img_processed = img / 8
    img_processed = img_processed.astype(int)
    plt.imshow(img_processed)

    Imagem de satélite - Intensidade da cor direita (Copernicus Sentinel data 2020)

    Agora temos um tensor de 3 dimensões de formato (10980, 10980, 3) de números inteiros de 8 bits na forma de uma matriz numpy

    Observe que :

    • Poderíamos ir além, usando uma abordagem de escala não linear para melhorar o contraste.

    • Converter como inteiro equivale a arredondar o valor, portanto, na verdade, estamos perdendo algumas informações. Isso é bom para muitos casos de uso e melhora a velocidade de processamento, mas se a precisão for fundamental, talvez seja melhor converter o valor da refletância em um float de 0-1 (um formato também gerenciado pela maioria das bibliotecas de ML) em vez de um inteiro de 0-255.

    • Por enquanto, estamos deixando de lado a banda espectral NIR. Isso nos ajudará a testar mais rapidamente, pois muitos algoritmos prontos para uso esperam imagens com 3 canais de cores. Mas pode ser interessante reintegrá-la em algum momento, seja substituindo um dos outros canais ou personalizando os algoritmos para que esperem 4 canais de cores.

    Etapa 4 - Dividir as imagens em tamanhos prontos para aprendizado de máquina

    Poderíamos tentar aplicar um algoritmo à nossa imagem atual, mas, na prática, isso não funcionaria com a maioria das técnicas devido ao seu tamanho. Mesmo com grande capacidade de computação, a maioria dos algoritmos (e especialmente a aprendizagem profunda) estaria fora de cogitação.

    Portanto, precisamos dividir a imagem em fragmentos. Uma questão é como definir o tamanho do fragmento.

    • Pequenos fragmentos melhorarão o desempenho.

    • Fragmentos maiores reduzem o número de objetos que serão difíceis de detectar devido à divisão em várias imagens. No entanto, fragmentos muito grandes podem ser um problema para alguns algoritmos de ML que redimensionam imagens ou não são capazes de dimensionar bem além de um determinado número de objetos em uma determinada imagem.

    Decidimos dividir cada imagem em uma grade de 45 * 45 (45 sendo convenientemente um divisor de 10980)

    Após a fixação do parâmetro, esta etapa é simples, usando a manipulação de matriz numpy. Armazenamos nossos valores em um dict usando tuplas (x, y) como chaves.

    frag_count = 45
    frag_size = int(img_processed.shape[0] / frag_count)
    frag_dict =

    for y, x in itertools.product(range(frag_count), range(frag_count)):
    frag_dict[(x, y)] = img_processed[y*frag_size: (y+1)*frag_size,
    x*frag_size: (x+1)*frag_size, :]

    plt.imshow(frag_dict[(10, 10)])

    Fragmento da imagem de satélite (Copernicus Sentinel data 2020)

    Etapa 5 - Vincule seu data às imagens de satélite usando a conversão de GPS para UTM

    Por fim, precisamos vincular nossas imagens ao data que temos nos campos agrícolas para permitir uma abordagem de aprendizado de máquina supervisionado. No nosso caso, temos o data em campos agrícolas na forma de uma lista de coordenadas de GPS (latitude, longitude), semelhante ao geojson que usamos na etapa 2, e queremos poder encontrar a posição do pixel. No entanto, para fins de clareza, começarei mostrando uma conversão de pixel em coordenadas de GPS e, em seguida, mostrarei o inverso

    O metadata coletado ao solicitar a API do SentinelSat fornece as coordenadas de GPS dos cantos da imagem (coluna footprint) e queremos as coordenadas de pixels específicos. A latitude e a longitude, que são valores angulares, não evoluem linearmente em uma imagem, portanto não podemos fazer uma relação simples usando a posição do pixel. Há maneiras de resolver isso usando equações matemáticas, mas já existem soluções prontas em python.

    Uma solução rápida é converter a posição do pixel em UTM (Universal Transverse Mercator), na qual uma posição é definida por uma zona, bem como uma posição (x, y) (em unidade de metro) que evolui linearmente com a imagem. Podemos então usar uma conversão de UTM para Latitude/Longitude fornecida na biblioteca utm. Para fazer isso, primeiro precisamos obter a zona UTM e a posição do canto superior esquerdo da imagem, que pode ser encontrada no metadata da imagem true color.

    #Ocontendo meatadata
    transform = rasterio.open(tci_file_path, driver=’JP2OpenJPEG’).transform
    zone_number = int(tci_file_path.split(“/”)[-1][1:3])
    letra_da_zona = tci_file_path.split(“/”)[-1][0] utm_x, utm_y = transform[2], transform[5]

    # Conversão da posição do pixel em utm
    east = utm_x + pixel_column * 10
    norte = utm_y + pixel_row * - 10

    # Conversão de UTM em latitude e longitude
    latitude, longitude = utm.to_latlon(east, north, zone_number, zone_letter)

    A conversão da posição GPS em pixels é feita usando as fórmulas inversas. Nesse caso, temos de nos certificar de que a zona obtida corresponde à nossa imagem. Isso pode ser feito especificando a zona. Se o nosso objeto não estiver presente na imagem, isso resultará em um valor de pixel fora do limite.

    # Conversão de latitude e longitude para UTM
    east, north, zone_number, zone_letter = utm.from_latlon(
    latitude, longitude, force_zone_number=número_da_zona
    )

    # Conversão de UTM em coluna e linha
    pixe_column = round((east - utm_x) / 10)
    pixel_row = round((north - utm_y) / -10)
    ver bruto

    Conclusão

    Agora estamos prontos para usar as imagens de satélite para aprendizado de máquina!

    No próximo artigo desta série de duas partes, veremos como podemos usar essas imagens para detectar e classificar superfícies de campos usando aprendizado de máquina supervisionado e não supervisionado.

    Obrigado pela leitura e não hesite em Siga o blog de tecnologia do Artefact se o senhor quiser ser notificado quando o próximo artigo for lançado!

    O senhor pode saber mais sobre nós e nossos projetos em nosso blog no Medium