Linhas terrestres

Resumo

O Land Lines é um experimento que permite explorar imagens de satélite do Google Earth por gestos. Usando uma combinação de machine learning, otimização de dados e potência da placa de vídeo, o experimento pode ser executado de maneira eficiente no navegador da Web do seu smartphone sem a necessidade de servidores de back-end. Esta é uma análise do nosso processo de desenvolvimento e das várias abordagens que tentamos nos levar ao resultado final.

https://g.co/LandLines

Quando a equipe de Data Arts me aproximou para explorar um conjunto de dados de imagens da Terra, fiquei muito empolgada. As imagens eram lindas, revelando todos os diferentes tipos de estruturas e texturas, feitas por humanos e naturais, e fiquei intrigada com como conectar esse conjunto de dados. Fiz vários experimentos iniciais para analisar a semelhança de imagens e diferentes formas de filtrá-las e organizá-las.

layout de similaridade t-sne
Layout de semelhança t-sne, 50 mb de alta resolução

Como grupo, continuamos voltando às linhas belas e dominantes nas imagens. Foi fácil identificar essas linhas: rodovias, rios, bordas de montanhas e lotes de terra. Por isso, desenvolvemos alguns projetos para explorar essas linhas. Como artista, me inspirei nas coisas bonitas que podem ser feitas com coleções de linhas, como o trabalho de Cassandra C Jones com raios. Fiquei feliz em trabalhar com esse conjunto de dados.

Detecção de linha

Um dos desafios iniciais foi como detectar linhas nas imagens. É fácil pegar um pedaço de papel tachado, jogá-lo em cima de uma impressão de uma dessas fotos e desenhar as linhas que seu olho vê, mas, em geral, algoritmos de visão computacional para encontrar linhas tendem a não funcionar bem em imagens muito diversas.

Desenvolvi uma versão anterior da pesquisa desenhando o algoritmo em um projeto com projetos locais. Para isso, anotamos as linhas a serem pesquisadas. Foi divertido desenhar sobre obras de arte, mas era tedioso conforme passamos de dezenas de imagens para milhares. Eu queria tentar automatizar o processo de encontrar linhas.

Com essas imagens aéreas, testei algoritmos tradicionais de detecção de linha, como o algoritmo de detecção de borda Canny da openCv, mas descobri que eles geravam segmentos de linha muito descontínuos ou, se o limite estava muito relaxado, muitas linhas falsas. Além disso, os limites para receber bons resultados eram diferentes em diferentes conjuntos de imagens, e eu queria um algoritmo para encontrar um conjunto consistente de linhas boas sem supervisão.

Testei diversos algoritmos de detecção de linha, incluindo algoritmos recentes, como gPb (PDF) que, embora produza resultados incríveis, exigiu minutos para ser executado por imagem. No final, concordo com a detecção de borda de floresta estruturada, um algoritmo que é enviado com openCV.

Depois de ter uma boa "imagem em linha", ainda tive o problema de identificar as linhas individuais umas das outras, ou seja, como faço para usar esses dados rasterizados e torná-los vetoriais. Muitas vezes, quando preciso analisar problemas de visão computacional, investigo o imageJ, um ambiente de processamento de imagens baseado em Java de código aberto usado por cientistas e pesquisadores que tem um ecossistema íntegro de plug-ins. Encontrei um plug-in chamado detecção de cristas, que ajuda a transformar uma imagem de intensidade em um conjunto de segmentos de linha. Como observação, também achei esse código de detecção e rotulagem de bordas do Matlab útil.

Imagem com segmentos de linha detectados
Imagem com segmentos de linha detectados

Sem servidor

Também queria saber se é possível criar um app de visualização de dados que não use servidor, em que o trabalho árduo de correspondência e conexão acontece no lado do cliente. Geralmente trabalho em openFrameworks, um framework c++ para codificação de criativos. Além de alguns projetos node, não fiz muita programação no lado do servidor. Eu queria saber se é possível fazer todo o cálculo no lado do cliente e usar o servidor apenas para exibir dados JSON e de imagem.

Para o aplicativo de desenho, a correspondência é uma operação muito pesada. Quando você desenha uma linha, precisamos encontrar a correspondência mais próxima entre dezenas de milhares de segmentos de linha. Para calcular a distância de um desenho para outro, usamos uma métrica do reconhecedor de gestos de dólar, que, por si só, envolve muitos cálculos de distância. No passado, usei linhas de execução e outros truques, mas, para funcionar em tempo real em um dispositivo cliente (incluindo smartphones), precisava de algo melhor. Analisei as árvores de métricas para encontrar vizinhos mais próximos/próximos e me acomodei com árvores de pontos privilegiados (implementação de JavaScript). Basicamente, a árvore de pontos de vista é criada com base em um conjunto de dados e uma métrica de distância e, quando você insere um novo dado, ela fornece rapidamente uma lista dos valores mais próximos. A primeira vez que vi esse trabalho em um celular instantaneamente fiquei chocado. Um dos grandes benefícios dessa implementação de árvore de pontos de vista específica é que você pode salvar a árvore depois que ela é calculada e economizar nos custos de computação.

Resultados mais próximos Resultados desenhados
Exemplos de resultados da árvore de posições privilegiadas. A entrada desenhada está no lado direito, e os resultados mais próximos estão à esquerda.

Outro desafio de fazer isso funcionar sem um servidor é fazer com que os dados sejam carregados em um dispositivo móvel. Para desenhar, os dados de segmentos de árvore e linha tinham mais de 12 MB e as imagens são muito grandes. Queríamos que a experiência parecesse rápida e responsiva, e o objetivo era tentar manter o download pequeno. Nossa solução foi carregar os dados progressivamente. No app de desenho, dividimos o conjunto de dados da árvore de pontos de vista em cinco partes. Quando o app carrega, ele só carrega o primeiro bloco e, a cada 10 segundos, outro bloco de dados é carregado em segundo plano. Portanto, essencialmente o app fica cada vez melhor no primeiro minuto de uso. No app de arrastar, também trabalhamos muito para armazenar imagens em cache para que, ao arrastar, novas imagens sejam carregadas em segundo plano.

Por fim, algo que achei mais difícil do que esperado foi criar um pré-carregador para os dois apps, então o atraso inicial nos carregamentos de dados seria compreensível. Usei o retorno de chamada de progresso nas solicitações Jupyter e, no lado do pixi.js, verifiquei que as imagens que estavam carregando de forma assíncrona foram realmente carregadas e as usei para gerar a mensagem de pré-carregamento.

Linha conectada

Para a ação de arrastar, eu queria criar uma linha infinita a partir das linhas que encontramos na detecção de borda. A primeira etapa foi filtrar linhas do algoritmo de detecção de linhas e identificar linhas longas que começam em uma borda e terminam em uma das três outras bordas.

Linhas boas para conexão marcadas em vermelho Linhas boas para conexão marcadas em vermelho
Linhas boas para conexão marcadas em vermelho

Quando eu tinha um conjunto de linhas longas (ou, para usar um termo mais preciso, polilinhas, uma coleção de pontos conectados), para conectá-las, converti essas linhas em um conjunto de mudanças de ângulo. Normalmente, ao pensar em uma polilinha, você a imagina como um conjunto de pontos: o ponto A está conectado ao ponto b, que está conectado ao ponto c. Em vez disso, é possível tratar a linha como um conjunto de mudanças de ângulo: avançar, girar um valor, avançar e girar um pouco. Uma boa maneira de visualizar isso é pensando em máquinas de dobramento de fios, que pegam um pedaço de fio e, à medida que ele é deslocado, realizam rotações. A forma do desenho vem da rotação.

Se você considerar a linha como mudanças de ângulo, e não como pontos, fica mais fácil combinar linhas em uma linha maior com menos descontinuidades. Em vez de pontos de união, você está essencialmente adicionando mudanças de ângulo relativas. Para adicionar uma linha, pegue o ângulo atual da linha principal aimage0 e adicione a ela as mudanças relativas da linha que você quer adicionar.

Como observação, usei essa técnica de conversão de uma linha em um conjunto de mudanças de ângulo para exploração artística. Você pode fazer desenhos "descurl" semelhante a como o fio pode curl e descurl. Alguns exemplos: um, dois, três

Esse cálculo de ângulo é o que nos permite direcionar a linha enquanto você arrasta. Nós calculamos a distância do ângulo principal de onde queremos estar e procuramos uma imagem que ajude mais a fazer a linha ir na direção certa. É tudo uma questão de pensar relativamente.

Finalmente, só quero dizer que este foi um projeto muito divertido de se envolver. É empolgante para o artista ser solicitado a usar um conjunto de dados tão bonito quanto essas imagens. É uma honra que a equipe de Data Arts tenha entrado em contato. Espero que tenha se divertido experimentando!