• Nenhum resultado encontrado

Criação do plugin no plugin builder

A criação do plugin teve como objetivo automatizar a metodologia de extração das copas de árvores. Para criar o plugin, recorreu-se ao plugin builder [8]. requeridos.

Interface gráfica

No qt designer foi aberto o ficheiro copas_arvores_dialog_base.ui, que contém a interface gráfica do plugin. Ao abrir esse ficheiro no qt designer, foi possível observar uma caixa de diálogo vazia, que continha apenas uma button box: caixa com as opções básicas ok e cancelar. Para definir a interface gráfica, foram escolhidos os seguintes widgets da widget box:

 Line edit  Label  Push button

A line edit é uma caixa de texto editável onde são definidos os diretórios para os inputs e outputs. Esses diretóriossão atribuídos através do push button, que abre uma interface que permite atribuir os diretóriosàs line edits. A label, é uma etiqueta que é adicionada normalmente ao lado de outro widget, para indicar qual o objetivo desse widget. No caso deste plugin, a label foi colocada acima da line edit de modo a indicar o objetivo de cada ligação.

Foram escolhidos 4 line edits, 4 push buttons e 4 labels. Cada push button e label está relacionado com cada line edit. Os dois primeiros line edit servem para colocar os inputs, imagem multiespetral e imagem NDVI, enquanto as duas últimas line edit permitem definir o diretório onde são guardados os outputs resultantes, a shapefile com as copas das árvores e o ficheiro de texto com a informação métrica.

Figura 37 - Interface gráfica do plugin desenvolvido

De seguida, foi aberto o ficheiro copas_arvores.py, que contém o código principal do plugin, no IDE(Integrated development environment) Microsoft visual studio 2015 e visual studio code com o objetivo de escrever o código que define o plugin, na linguagem Python 2.7 [17]. Ao abrir este ficheiro, é possível verificar código pré-definido pelo plugin builder que permite, por exemplo, a interação do plugin com a interface gráfica do QGIS. Neste script também foi escrito o código que define a interação com a interface gráfica criada no qt designer e o código que define a metodologia para extração e cálculo de métricas das copas de árvores.

Implementação da metodologia no plugin

Nas primeiras linhas do código, foram importados os módulos qgis.core e processing com os métodos necessários a usar. Os restantes módulos foram pré-definidos pelo plugin builder.

Um dos métodos pré-definidos no script copas_arvores.py é o initGui. No initGui foi escrito o código que define a interação do plugin com a interface gráfica (Figura 38). A variável dlg permite aceder ao código da interface gráfica e os 4 pushButton são os botões criados (dois inputs e dois outputs).

Para os pushButton localizarem e guardarem ficheiros, foram definidas as funções inputfile e inputfile2 para os inputs e as funções output e output2 como outputs.

Figura 38 - Método initGui

A metodologia foi implementada na função run, uma vez que dentro desta função é definido o procedimento a efetuar.

Foram definidas duas variáveis para acederem à imagem multiespetral e à imagem NDVI, com os respetivos diretórios. Foram utilizadas funções da classe QgsRasterLayer()

de modo a aceder aos valores do número total de bandas e da extensão da imagem (valores do x máximo, x mínimo, y máximo e y mínimo), número total de bandas e número total de bandas da imagem multiespetral (Figura 39).

Figura 39 - Definição dos ficheiros de entrada no script e a extração de vários parâmetros da imagem multiespetral

Para aceder aos algoritmos da processing toolbox, foi utilizada a função

Processing.runAlgorithm() do módulo processing.

Na segmentação da imagem multiespetral, foi necessário separar a imagem multiespetral em bandas. Recorreu-se ao algoritmo da orfeo toolbox denominado split image (Figura 40). O diretório das bandas foi guardado em formato lista.

Figura 40 - Código desenvolvido para a separação das bandas

A seguir, foi efetuada a segmentação (Figura 41), através do i.segment do GRASS GIS 7. Primeiro, definiu-se uma linha de código para processar a primeira imagem semente com o valor para o thresholding de 0.05. Para processar a imagem segmentada final foi necessário executar o algoritmo i.segment várias vezes. Definiu-se então um ciclo for para processar as imagens segmentadas com as imagens semente, em que a variável que percorre o ciclo é a variável do valor thresholding, em que, na primeira iteração o thresholding é de 0.1 e na última é de 0.65, com incrementos de 0.05. No final de cada iteração a imagem segmentada é considerada a imagem semente.

Figura 41 - Código para a segmentação da imagem

Uma vez obtida a imagem segmentada com valor thresholding 0.65, as linhas de código seguintes destinam-se à classificação da imagem (Figura 42). Para isso recorreu-se ao algoritmo de classificação não-supervisionada da orfeo toolbox, unsupervised kmeans image classification, onde a imagem NDVI foi utilizada como input e a imagem segmentada como máscara de validação. Definiu-se ainda o parâmetro training set size, o número de píxeis utilizados como área de treino, no valor total de píxeis multiplicado pela constante 0.00705, de modo a obter um valor próximo de 100 000 píxeis a partir do valor total de píxeis e manter a proporção do valor deste parâmetro para o processamento com outras imagens. Nos restantes parâmetros foram considerados os valores por defeito.

Figura 42 - Código para a classificação da imagem

A seguir, considerou-se a imagem classificada como raster, através da classe

QgsRasterLayer(), com o objetivo de utilizar as bibliotecas Python do QGIS para extrair o valor máximo da imagem raster classificada (Figura 43). É considerado o valor máximo da imagem, pois as copas das árvores estão associadas a esse valor.

Figura 43- Código para extrair o valor máximo da imagem classificada

Para diferenciar as copas das árvores das restantes classes, foi utilizado o algoritmo GDAL raster calculator, na qual as copas das árvores são identificadas com o valor 1 e as restantes classes são consideradas valor 0 (Figura 44). No ficheiro de saída

considerou-se que os objetos com valor máximo da imagem classificada são as copas das árvores.

Figura 44 - Código para o GDAL raster calculator

Na linha de código seguinte a imagem foi convertida num ficheiro vetorial recorrendo-se ao algoritmo GDAL polygonize (Figura 45). O ficheiro de saída foi o ficheiro definido no diretório output das copas das árvores. Neste algoritmo, foram identificados os polígonos definidos no GDAL raster calculator, com os valores 0 e 1 na tabela de atributos. A coluna que armazena a identificação dos objetos, foi designada por “DN”.

Figura 45 - Código para a vetorização da imagem classificada

A shapefile das copas de árvores foi considerada como um ficheiro vetorial através da classe QgsVectorLayer() de modo a manipular os dados da shapefile das copas de árvores. Neste ficheiro vetorial eliminaram-se os objetos que não são considerados copas de árvores e também se extraíram os valores métricos. A shapefile foi identificada como variável layer (Figura 46).

Figura 46 - Código para considerar a shapefile

Para eliminar outros elementos existentes na imagem foram definidos os seguintes critérios:

 Área menor que 1 𝑚 , para excluir objetos demasiado pequenos para serem copas de árvores.

 Área maior que 50 𝑚 , para excluir objetos demasiado grandes para serem copas de árvores.

 Elementos onde a classe seja diferente de 1.

 Rácio entre o comprimento e largura da bounding box dos polígonos.

A bounding box é um polígono com forma regular em que os seus limites correspondem aos valores x mínimo, x máximo, y mínimo e y máximo de um polígono irregular. No

caso das copas das árvores é espectável que a bounding box tenha uma forma aproximadamente quadrangular, ou seja, que o rácio entre o comprimento e largura não seja muito diferente de 1. O principal motivo de incluir este critério deve-se ao facto da classificação de imagem ter identificado uma zona da imagem, como copas de árvores, em que as bandas não estão bem sobrepostas e terem um formato bastante irregular (Figura 47).

Figura 47 - Parte da imagem em que as bandas não estão totalmente sobrepostas

Foi necessário chamar a função edit() que permite manipular elementos ou campos de atributos da shapefile. Definiu-se um ciclo for com a variável f a percorrer todos os elementos da shapefile e extrair o valor da área, comprimento (como variável height) e largura (como variável width) da bounding box. Com o comprimento e a largura, calculou-se o rácio para cada polígono. Uma vez que as copas não apresentam uma forma regular, ou seja, o rácio nunca será exatamente 1, foi definido um valor de tolerância para o rácio. O valor de tolerância escolhido foi 0.55, ou seja, qualquer polígono com um rácio inferior a 0.45 e superior a 1.55 é excluído da shapefile. Este valor de tolerância corresponde ao valor máximo que permite excluir a zona de má sobreposição de bandas e eliminar o número mínimo possível de copas de árvores. Caso as condições referidas se cumpram, será executada a linha layer.deleteFeature(f.id())

Figura 48 - Código que permite eliminar polígonos

Uma vez eliminados os polígonos não pretendidos, foi desenvolvido código no script para criar o ficheiro de texto (Figura 49) com as seguintes métricas:

 Área  Perímetro

 Centro da árvore (centroide)  Número total de árvores  Área total de árvores

O ficheiro de texto é guardado no diretório definido no output da “informação métrica” (variável info) (Figura 49). Foi criada a variável tabela para definir a tabela a guardar no ficheiro de texto, sendo acrescentadas as linhas com os respetivos parâmetros de cada copa de árvore, através da função .write(). Definiu-se o cabeçalho com os seguintes títulos:  Id  Área  Perímetro  x (centroide)  y (centroide)

Acedeu-se à tabela de atributos da shapefile, de modo a eliminar a coluna com os valores das classes (desginada por DN) e acrescentar uma coluna para os valores de identficação de cada árvore.

A seguir, definiram-se as variáveis para calcular o somatório da área das copas de árvores e o contador do número total de polígonos, ou seja, o número total de árvores que existem na imagem. O valor inicial de cada variável é de 0 (zero). Foi ainda definido um dicionário vazio para armazenar os centroides de cada árvore, tendo como nome de variável centroides.

Para extrair as métricas para cada polígono, definiu-se um ciclo for para percorrer todos os polígonos.

Os valores foram armazenados na variável line que cria uma linha com o valor id de cada polígono e com as métricas referidas acima. Os valores do total de área e do número total de árvores são atualizados a cada iteração. Ao dicionário centroides são acrescentados os centroides de cada árvore na classe QgsPoint (Figura 49), em que o valor “chave” é o valor de identificação de cada árvore. São ainda adicionados à tabela de atributos o valor de identificação de cada árvore, de modo a que o utilizador possa identificar as árvores da shapefile no ficheiro de texto.

Figura 49- Código que permite criar o ficheiro de texto, definir um dicionário com centroides e acrescentar o valor id na tabela de atributos da shapefile

Para calcular a distância entre as árvores mais próximas em cada fiada, foi necessário definir o rumo das fiadas. A classe QgsPoint contém a função azimuth que permite calcular o rumo entre dois pontos. São calculados os rumos de um centroide em relação

aos restantes centroides, considerando apenas os rumos com valor superior a zero. Os rumos obtidos são armazenados numa lista com a designação rumos (Figura 50).

Figura 50 - Definição da lista com os rumos

Como o valor mais frequente da lista rumos é o valor do rumo entre os centroides das fiadas, definiu-se então a moda dos valores da lista como o rumo para calcular a distância entre as árvores de uma fiada(Figura 51).

Figura 51 - Definição da moda do rumo das fiadas

Foi também definido código que divide a secção das métricas das árvores e cria o cabeçalho da secção das distâncias entre árvores (Figura 52).

Figura 52 - Código que define a divisão entre as secções e criação do cabeçalho da secção das distâncias entre árvores

Com o rumo das fiadas definido, procedeu-se à implementação de código para o cálculo da distância entre as árvores mais próximas em cada fiada. Foram definidos dois ciclos

for para calcular o rumo de um ponto em relação aos restantes pontos que se encontram nas fiadas e guardar o valor dessas distâncias, em metros, num dicionário definido com a variável fila em que os valores “chave” são o valor de identificação das árvores. Foram apenas armazenadas as distâncias entre os centroides com o rumo correspondente ao rumo das fiadas e dentro da tolerância estabelecida no código (Figura 53).

Algumas árvores localizadas nos extremos das fiadas não têm árvores no rumo definido, pelo qual os dicionários desses pontos são ignorados. Para os restantes casos são armazenadas as distâncias entre duas árvores que possuam o valor do rumo definido anteriormente no dicionário fila e considerada a distância mínima, ou seja, a distância entre as árvores mais próximas. Essa distância mínima é armazenada no ficheiro de texto através da variável line, com o valor “chave” das duas árvores correspondentes. Foi ainda criada uma lista com as distâncias entre as árvores com o intuito de identificar as falhas existentes, ou seja, as árvores que faltam em cada fiada. Essa lista é armazenada na variável distância (Figura 53).

Figura 53 - Código que define a distância mínima entre as árvores mais próximas

Para identificar as falhas nas fiadas, foi implementado código que calcula a distância média entre as árvores e foi também definida uma tolerância dado que o valor da distância entre as árvores nunca é exatamente igual ao da distância média. Ao percorrer a lista distancias através de um ciclo for e identificada uma distância superior a essa

tolerância estabelecida, essa distância é considerada uma árvore em falta e o número de falhas são armazenadas na variável falhas (Figura 54).

Figura 54 - Contagem de falhas de árvores

Também foram armazenados no ficheiro de texto os seguintes valores (Figura 55):  Número total de árvores.

 Área total ocupada pelas árvores.  Distância média entre árvores.  Total de falhas de árvores.

Figura 55 - Código que acrescenta ao ficheiro de texto o número total de árvores, área total ocupada pelas árvores, distância média entre árvores e total de falhas de árvores

Resultados obtidos

Ao executar o plugin, foi criada a shapefile (Figura 56) e o ficheiro de texto com as métricas. Ao comparar com a shapefile obtida na metodologia (Figura 57), a principal diferença é a exclusão de objetos que formassem uma bounding box com valor de rácio para além do critério estabelecido. Através do rácio, foi eliminado o objeto equivalente à zona da imagem em que as bandas não estão completamente sobrepostas, assim como 3 árvores que foram obtidas com a metodologia manual.

Ao analisar o ficheiro de texto, verificou-se que o critério da eliminação de objetos através do valor da área foi cumprido, uma vez que todos os objetos têm valores de área superior a 1 𝑚 e inferior a 50 𝑚 .

Foram também registadas as distâncias entre as árvores mais próximas. No QGIS, verificou-se manualmente se o valor de identificação das árvores correspondia às árvores mais próximas registadas no ficheiro de texto. Após essa verificação concluiu- se que os valores de identificação estavam corretos.

Quanto ao número de árvores, o plugin contabilizou um total de 178 árvores, enquanto que o valor total da área ocupada pelas copas foi de 1401.268 𝑚 . Obteve-se ainda a distância média entre as árvores, sendo de 7.828 metros, e contabilizado o número total de falhas, obtendo-se um total de 23 árvores em falta.

Figura 57 - Comparação entre a shapefile obtida com o plugin (à esquerda) e a shapefile obtida com metodologia manual à direita)

Porém, foram detetadas algumas limitações nos resultados obtidos:

 Foram eliminadas duas árvores pertencentes à cultura de oliveiras com a aplicação do valor do rácio no plugin.

 Algumas das árvores não foram totalmente separadas (Figura 58) uma vez que alguns ramos apresentam proximidade suficiente para o algoritmo não conseguir distinguir as árvores (Figura 59). Neste caso, é apenas contabilizada uma copa em vez de duas.

Figura 59 - Parte da imagem em que as árvores se encontram muito próximas

 Alguma vegetação indesejada, com propriedades espetrais semelhantes às oliveiras, foi identificada (Figura 60 e Figura 61).

Figura 60 - Parte da shapefile com a vegetação indesejada (shp)

Figura 61 - Parte da imagem com a vegetação indesejada

Quanto ao número de falhas, verificou-se que o número de árvores em falta obtido (23) foi elevado para aquilo que se verifica na imagem. Para além do facto do plugin não ter registado algumas das árvores, outro fator que contribuiu para este número elevado de falhas foram as estradas que atravessam parte da cultura. Uma vez que algumas das

fiadas têm continuação do outro lado das estradas, as árvores mais próximas dessas estradas registam uma distância entre si superior à tolerância estabelecida (Figura 62).

Figura 62 - Exemplo de uma estrada que atravessa várias fiadas

Métodos que podem melhorar a eficácia do plugin

A qualidade de informação obtida através do plugin não é 100% eficaz, como é referido no final da secção anterior. A melhoria da qualidade dessa informação poderá passar por alguns dos seguintes métodos:

 Sobreposição de bandas mais eficiente: a parte da imagem em que as bandas não estão sobrepostas são identificadas como objetos.

 Utilização de imagens hiperespectrais em vez de imagens multiespetrais: as imagens hiperespectrais apresentam bandas contínuas, obtendo píxeis com valores contínuos, enquanto que as imagens multiespetrais apresentam bandas discretas, obtendo píxeis com valores discretos. Uma vez que na imagem hiperespectral, os píxeis apresentam vetores com valores contínuos, este tipo de imagens permite uma maior diferenciação dos objetos presentes na imagem do que a imagem multiespectral [19]. A utilização destas imagens poderia resolver a questão levantada na Figura 61, eliminando assim vegetação indesejada.

 Operações morfológicas: algumas árvores não ficaram separadas e operações morfológicas como a erosão e dilatação dos objetos podem ser uma solução para esse problema. A erosão permite a eliminação dos píxeis circundantes, separando os objetos que estão ligados por ramos. Quanto à dilatação, acrescenta píxeis às zonas circundantes dos objetos, mas é necessário ter em conta o cuidado de não voltar a unir os objetos [20].

 Classificação supervisionada: como um dos objetivos do plugin implementado era a maior automatização possível para o utilizador, foidada mais atenção ao algoritmo de classificação não-supervisionada do que na classificação supervisionada. Porém a classificação supervisionada permite um maior controlo dos resultados, em que a possibilidade de efetuar mais testes com diferentes parâmetros poderá aumentar a eficácia do plugin.

Capítulo 5 - Teste do plugin com outras

Documentos relacionados