Este é o código-fonte e o modelo pré-treinado para a demonstração da webcam pix2pix que postei recentemente no Twitter e no Vimeo. Ele usa aprendizado profundo, ou para acrescentar algumas palavras-chave: autoencoder de rede adversária generativa condicional convolucional profunda .
vídeo 1
vídeo 2
O código neste repositório específico, na verdade, não tem nada a ver com pix2pix, GANs ou mesmo aprendizado profundo. Ele apenas carrega qualquer modelo de tensorflow pré-treinado (desde que esteja em conformidade com algumas restrições), alimenta-o com uma entrada de webcam processada e exibe a saída do modelo. Acontece que o modelo que treinei e usei é o pix2pix (detalhes abaixo).
Ou seja, as etapas podem ser resumidas como:
Peguei coleções de arte de todo o mundo do Google Art Project na wikimedia. Muitas das imagens são retratos clássicos de caras brancos ricos, então usei apenas cerca de 150 coleções, tentando manter os dados o mais diversificados geográfica e culturalmente possível (a lista completa que usei está aqui). Mas os dados ainda são muito centrados no euro, pois podem existir centenas ou milhares de digitalizações de um único museu europeu, mas apenas 8 digitalizações de um museu árabe.
Baixei as versões de 300px das imagens e executei um processo em lote para:
Também executei um processo em lote para obter vários cortes das imagens (em vez de um redimensionamento não uniforme), mas ainda não treinei nisso. Em vez de uma detecção astuta de bordas, também comecei a pesquisar o muito melhor 'Holistically-Nested Edge Detection' (também conhecido como HED) de Xie e Tu (conforme usado no artigo pix2pix original), mas também não treinei nisso ainda.
Isso é feito pelo script preprocess.py (desculpe, não há argumentos de linha de comando, edite o script para alterar caminhos e configurações, deve ser bastante autoexplicativo).
Uma pequena amostra dos dados de treinamento – incluindo previsões do modelo treinado – pode ser vista aqui. A coluna mais à direita é a imagem original, a coluna mais à esquerda é a versão pré-processada. Essas duas imagens são alimentadas na rede pix2pix como um 'par' para serem treinadas. A coluna do meio é o que o modelo aprende a produzir, dada apenas a coluna mais à esquerda . (As imagens mostram cada iteração de treinamento - ou seja, o número à esquerda, que vai de 20.000 a 58.000, então fica melhor gradualmente à medida que você desce na página).
Também treinei um GAN incondicional (ou seja, DCGAN normal nesses mesmos dados de treinamento. Um exemplo de sua saída pode ser visto abaixo. (Isso está gerando imagens 'completamente aleatórias' que se assemelham aos dados de treinamento).
O treinamento e a arquitetura são ' Tradução de imagem para imagem com redes adversárias condicionais ' por Isola et al (também conhecido como pix2pix). Treinei com a porta tensorflow de @affinelayer (Christopher Hesse), que também é o que está alimentando aquela demonstração 'sketch-to-cat' que se tornou viral recentemente. Ele também escreveu um bom tutorial sobre como funciona o pix2pix. Agradecimentos infinitos aos autores (e a todos em quem eles construíram) por tornarem seu código de código aberto!
Fiz apenas uma alteração infinitamente pequena no código de treinamento tensorflow-pix2pix: adicionar tf.Identity às entradas e saídas do gerador com um nome legível por humanos, para que eu possa alimentar e buscar os tensores com facilidade. Portanto, se você quiser usar seus próprios modelos com este aplicativo, precisará fazer o mesmo . (Ou anote os nomes dos tensores de entrada/saída e modifique o json de acordo, mais sobre isso abaixo).
Você pode baixar meu modelo pré-treinado na guia Releases.
O que esse aplicativo específico faz é carregar o modelo pré-treinado, fazer o pré-processamento ao vivo de uma entrada de webcam e alimentá-lo ao modelo. Eu faço o pré-processamento com visão computacional básica e antiquada, usando opencv. É realmente mínimo e básico. Você pode ver a GUI abaixo (a GUI usa pyqtgraph).
Cenas diferentes requerem configurações diferentes.
Por exemplo, para 'ação ao vivo', achei astuto fornecer resultados melhores (IMHO), e foi o que usei no primeiro vídeo no topo. Os limites (canny_t1, canny_t2) dependem da cena, da quantidade de detalhes e da aparência desejada.
Se houver muito ruído em sua imagem, você pode adicionar um pouquinho de pre_blur ou pre_median . Ou brinque com eles para obter 'efeito artístico'. Por exemplo, no primeiro vídeo, por volta de 1h05-1h40, adiciono uma tonelada de mediana (valores em torno de 30-50).
Para cenas de desenho (por exemplo, segundo vídeo), descobri que o limite adaptativo fornece resultados mais interessantes do que o astuto (ou seja, desativar o astuto e ativar o limite adaptativo), embora você possa discordar.
Para uma entrada completamente estática (ou seja, se você congelar a captura, desativando a atualização da câmera), é provável que a saída pisque um pouco, pois o modelo faz previsões diferentes para a mesma entrada - embora isso geralmente seja bastante sutil. No entanto, para uma transmissão de câmera ao vivo , o ruído na entrada provavelmente criará muitas oscilações na saída, especialmente devido à alta suscetibilidade do limiar astuto ou adaptativo ao ruído, portanto, algum desfoque temporal pode ajudar.
accum_w1 e accum_w2 são para desfoque temporal da entrada, antes de entrar no modelo: new_image = old_image * w1 + new_image * w2 (então, idealmente, eles devem somar um - ou próximo a).
Prediction.pre_time_lerp e post_time_lerp também fazem suavização temporal: new_image = old_image * xxx_lerp + new_image * (1 - xxx_lerp) pre_time_lerp é antes de entrar no modelo e post_time_lerp é depois de sair do modelo.
Zero para qualquer um dos desfoques temporais os desativa. Os valores para estes dependem do seu gosto. Para ambos os vídeos acima, eu tinha todos os desfoques pré-modelo (ou seja, accum_w1, accum_w2 e pre_time_lerp) definidos como zero e joguei com diferentes configurações de post_time_lerp variando de 0,0 (muito tremeluzente e piscando) a 0,9 (muito lento, desbotado e 'sonhador' ). Normalmente, cerca de 0,5-0,8 é minha faixa favorita.
Se quiser usar um modelo diferente, você precisa configurar um arquivo JSON semelhante ao abaixo. A motivação aqui é que na verdade tenho vários JSONs em minha pasta app/models que posso verificar e recarregar dinamicamente, e os dados do modelo são armazenados em outro lugar em outros discos, e o aplicativo pode carregar e trocar entre modelos em tempo de execução e escala entradas/saídas etc. automaticamente.
{
"name" : "gart_canny_256", # name of the model (for GUI)
"ckpt_path" : "./models/gart_canny_256", # path to saved model (meta + checkpoints). Loads latest if points to a folder, otherwise loads specific checkpoint
"input" : { # info for input tensor
"shape" : [256, 256, 3], # expected shape (height, width, channels) EXCLUDING batch (assumes additional axis==0 will contain batch)
"range" : [-1.0, 1.0], # expected range of values
"opname" : "generator/generator_inputs" # name of tensor (':0' is appended in code)
},
"output" : { # info for output tensor
"shape" : [256, 256, 3], # shape that is output (height, width, channels) EXCLUDING batch (assumes additional axis==0 will contain batch)
"range" : [-1.0, 1.0], # value range that is output
"opname" : "generator/generator_outputs" # name of tensor (':0' is appended in code)
}
}
Testado apenas no Ubuntu 16.04, mas deve funcionar em outras plataformas.
Eu uso a distribuição python Anaconda que vem com quase tudo que você precisa, então é (espero) tão simples quanto:
Baixe e instale o anaconda em https://www.continuum.io/downloads
Instale o tensorflow https://www.tensorflow.org/install/ (o que - se você tiver o anaconda - geralmente é bastante simples, já que a maioria das dependências está incluída)
Instale opencv e pyqtgraph
conda instalar -c menpo opencv3 conda instalar pyqtgraph
Infinito obrigado mais uma vez a