Planetário movido a rede neural usando Python, Electron e Keras: 8 etapas
Planetário movido a rede neural usando Python, Electron e Keras: 8 etapas
Anonim
Planetário movido a rede neural usando Python, Electron e Keras
Planetário movido a rede neural usando Python, Electron e Keras

Neste instrutível, mostrarei como escrevi um gerador de planetário 3D automático, usando Python e Electron

O vídeo acima mostra um dos planetários aleatórios que o programa gerou.

** Nota: Este programa não é de forma alguma perfeito e, em alguns lugares, não é muito pitônico. O discriminador da rede neural é apenas ~ 89% preciso, então algumas imagens estranhas vão chegar ao planetário **

Especificidades

O planetário consulta uma API da NASA para imagens relacionadas ao espaço e utiliza uma rede neural convolucional para determinar se a imagem é adequada para processamento. O programa então usa OpenCV para remover o fundo da imagem e, finalmente, as imagens são costuradas em uma grande imagem equirretangular. Esta imagem é então salva e um aplicativo Electron Node.js abre a imagem e usa o pacote PhotoSphere.js para visualizar a imagem em um formato 3D estilo planetário.

Dependências

Pitão:

  • Keras
  • Almofada
  • cv2
  • Numpy
  • solicitações de
  • urllib
  • Aleatória
  • Tempo
  • io

Elétron:

Fotosfera

Etapa 1: Configurando Seu Ambiente

Instalando Electron e Python

Primeiro, certifique-se de ter o node.js e o npm instalados (se não, você pode fazer o download aqui)

Em seguida, você precisa instalar o Electron. Abra um prompt de comando e digite o seguinte comando:

npm instalar elétron -g

Em seguida, você precisa do python, que pode ser baixado aqui

Configurando um Ambiente Virtual

Abra um prompt de comando e digite os seguintes comandos para configurar seu ambiente virtual:

pip install virtualenv

espaço virtualenv

espaço do cd

scripts / ativar

Instalação de dependências Python

Execute estes comandos no prompt de comando para instalar suas dependências Python:

pip install keras

pip instalar travesseiro

pip install numpy

pedidos de instalação pip

pip install opencv-pythonSe você quiser treinar a rede sozinho, certifique-se de configurar a aceleração de GPU para Keras

Etapa 2: Consultando a API de pesquisa da NASA

Visão geral

A NASA tem muitas APIs realmente úteis que você pode usar em seus projetos. Para este projeto, usaremos a API de pesquisa, que nos permite pesquisar no banco de dados de imagens da NASA por imagens relacionadas ao espaço.

O código

Primeiro, precisamos definir uma função python para aceitar um argumento que funcionará como o termo de pesquisa:

def get_image_search (frase):

passar

Em seguida, converteremos o termo de pesquisa para o formato de URL e, em seguida, usaremos a biblioteca de solicitações para consultar a API:

def get_image_search (frase):

params = {"q": urllib.parse.quote (arg), "media_type": "image"} resultados = requests.get ("https://images-api.nasa.gov/search", params = params)

Por fim, decodificaremos a coleção + string JSON que a API retornou para nós e extrairemos uma lista de links para imagens relacionadas ao termo de pesquisa:

def get_image_search (frase):

params = {"q": urllib.parse.quote (arg), "media_type": "image"} resultados = requests.get ("https://images-api.nasa.gov/search", params = params) data = [result ['href'] para resultado em results.json () ["coleção"] ["itens"]

Aqui vamos nós! Agora temos um trecho de código que pode consultar a API de pesquisa de imagens da NASA e retornar uma lista de links para imagens relacionadas ao nosso termo de pesquisa.

Etapa 3: a rede neural convolucional

Visão geral

O trabalho da rede neural é classificar se uma imagem é de algo no espaço ou não. Para fazer isso, usaremos uma rede neural convolucional, ou CNN, para realizar uma série de operações de matriz na imagem e determinar o quão espacial ela é. Não vou explicar tudo isso, porque há muita teoria por trás disso, mas se você quiser aprender sobre redes neurais, sugiro "Domínio do aprendizado de máquina"

O código

Primeiro, precisamos importar nossas dependências:

importar os

#Fix for issue during train stepn on GPU os.environ ['CUDA_VISIBLE_DEVICES'] = '' importar tensorflow as tf if tf.test.gpu_device_name (): print ('GPU found') else: print ("No GPU found") from keras.preprocessing.image import ImageDataGenerator from keras.preprocessing importar imagem de keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D de keras.layers import Activation, Dropout, Flatten, Dense from keras import backend como K from PIL import Image importar numpy como np

Em seguida, precisamos definir nosso modelo:

img_width, img_height = 1000, 500

train_data_dir = 'v_data / train' validation_data_dir = 'v_data / test' nb_train_samples = 203 nb_validation_samples = 203 epochs = 10 batch_size = 8 if K.image_data_format () == 'channels_firsthape': img_firsthape = (3, img_hewidth) = (img_width, img_height, 3) model = Sequential () model.add (Conv2D (32, (2, 2), input_shape = input_shape)) model.add (Activation ('relu')) model.add (MaxPooling2D (pool_size) = (2, 2))) model.add (Conv2D (32, (2, 2))) model.add (Ativação ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) modelo.add (Conv2D (64, (2, 2))) model.add (Activation ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Flatten ()) model. add (Denso (64)) model.add (Ativação ('relu')) model.add (Dropout (0,5)) model.add (Denso (1)) model.add (Ativação ('sigmoid')) model.compile (perda = 'binary_crossentropy', otimizador = 'rmsprop', metrics = ['precisão'])

Eu treinei o modelo para você, mas se você quiser treinar o modelo sozinho, em seu próprio conjunto de dados, anexei o código de treinamento. Caso contrário, você pode baixar o arquivo HDF5 do modelo treinado. Devido às restrições do arquivo Instructables, tive que renomeá-lo com uma extensão ".txt". Para usá-lo, renomeie o arquivo com a extensão ".h5" e carregue-o com este código:

model.load_weights ("model_saved.h5")

Para usar a rede para prever quão espacial é uma imagem, definiremos esta função:

def Predict (image_path):

img = image.load_img (image_path, target_size = (1000, 500)) img = np.expand_dims (img, axis = 0) result = model.predict_classes (img) return result [0] [0]

Etapa 4: Processando a imagem

Visão geral

Para o processamento de imagens, estou usando a biblioteca OpenCV (cv2). Primeiro, borraremos as bordas da imagem e, em seguida, removeremos o fundo criando uma máscara e alterando os valores alfa das cores mais escuras

O código

Esta é a parte da função que desfoca as bordas:

def processImage (img):

RADIUS = 20 # Abra uma imagem im = Image.open ("pilbuffer.png") # Cole a imagem no fundo branco diam = 2 * RADIUS back = Image.new ('RGB', (im.size [0] + diam, im.size [1] + diam), (0, 0, 0)) back.paste (im, (RADIUS, RADIUS)) # Criar máscara de máscara de desfoque = Image.new ('L', (im.size [0] + diam, im.size [1] + diam), 255) blck = Image.new ('L', (im.size [0] - diam, im.size [1] - diam), 0) máscara. paste (blck, (diam, diam)) # Desfoque a imagem e cole a borda desfocada de acordo com a máscara blur = back.filter (ImageFilter. GaussianBlur (RADIUS / 2)) back.paste (blur, mask = mask) back.save (" transição-p.webp

Em seguida, definiremos as cores mais escuras como transparentes e salvaremos a imagem temporariamente:

#Criar máscara e filtro substituir preto por alfa

image = cv2.imread ("transaction.png") hMin = 0 sMin = 0 vMin = 20 hMax = 180 sMax = 255 vMax = 255 inferior = np.array ([hMin, sMin, vMin]) superior = np.array ([hMax, sMax, vMax]) hsv = cv2.cvtColor (imagem, cv2. COLOR_BGR2HSV) mask = cv2.inRange (hsv, inferior, superior) output = cv2.bitwise_and (imagem, imagem, máscara = máscara) * _, alfa = cv2.split (output) dst = cv2.merge ((output, alpha)) output = dst com open ("buffer.png", "w +") como arquivo: passe cv2.imwrite ("buffer.png", saída)

Etapa 5: juntando imagens em uma projeção equirretangular

Visão geral

Esta função pega várias imagens e as une em um formato que pode ser interpretado pelo pacote PhotoSphere.js, usando a biblioteca PIL (travesseiro)

O código

Primeiro, precisamos criar uma imagem que possa atuar como hospedeira para as outras imagens:

novo = Image.new ("RGBA", (8000, 4000), cor = (0, 0, 0))

Em seguida, precisamos iterar pela matriz de imagens (que foram redimensionadas para 1000 x 500) e colocá-las na imagem:

h = 0

w = 0 i = 0 para img em img_arr: new.paste (img, (w, h), img) w + = 1000 se w == 8000: h + = 500 w = 0 i + = 1

Agora, acabamos de encerrar isso em uma função que recebe uma matriz de imagens como argumento e retorna a nova imagem:

def stitch_beta (img_arr):

new = Image.new ("RGBA", (8000, 4000), color = (0, 0, 0)) h = 0 w = 0 i = 0 para img em img_arr: new.paste (img, (w, h), img) w + = 1000 se w == 8000: h + = 500 w = 0 i + = 1 return new

Etapa 6: o script Python completo

Este é o script de rede neural Python completo, salvo como net.py e importado para o script principal:

# bibliotecas de importação

import os #Fix para o problema durante a etapa do trem na GPU os.environ ['CUDA_VISIBLE_DEVICES'] = '' importar tensorflow como tf if tf.test.gpu_device_name (): print ('GPU encontrada') else: print ("Nenhuma GPU encontrada ") from keras.preprocessing.image import ImageDataGenerator from keras.preprocessing import image from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D de keras.layers import Activation, Dropout, Flatten, Dense from keras import backend como K de PIL importar imagem importar numpy como np img_width, img_height = 1000, 500 train_data_dir = 'v_data / train' validation_data_dir = 'v_data / test' nb_train_samples = 203 nb_validation_samples = 203 epochs = 10 batch_size = 8 se K._firstata_format = ': input_shape = (3, img_width, img_height) else: input_shape = (img_width, img_height, 3) model = Sequential () model.add (Conv2D (32, (2, 2), input_shape = input_shape)) model.add (Ativação ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Conv2D (32, (2, 2))) modelo. add (Activation ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Conv2D (64, (2, 2))) model.add (Activation ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Flatten ()) model.add (Dense (64)) model.add (Ativação ('relu')) model.add (Dropout (0,5)) model.add (Dense (1)) model.add (Ativação ('sigmoid')) model.compile (loss = 'binary_crossentropy', otimizador = 'rmsprop', metrics = ['precisão']) model.load_weights ("model_saved.h5") def Predict (image_path): img = image.load_img (image_path, target_size = (1000, 500)) img = np.expand_dims (img, axis = 0) result = model.predict_classes (img) resultado de retorno [0] [0]

Este é o arquivo python principal, api.py:

solicitações de importação, sys, aleatório, urllib.parse, cv2

from PIL import Image, ImageFilter from io import BytesIO import numpy as np import net def get_image_search (num, frase): count = 0 img_arr = para arg na frase: print (arg) print (f "Contagem de imagem atual: {count } ") i = 0 params = {" q ": urllib.parse.quote (arg)," media_type ":" imagem "} resultados = requests.get (" https://images-api.nasa.gov/search ", params = params) data = [result ['href'] para o resultado em results.json () [" coleção "] [" itens "] print (len (data)) if num> len (data): num = len (dados) enquanto contagem = num: break print (f "\ n {count} imagens recuperadas") return img_arr def stitch_beta (img_arr): new = Image.new ("RGBA", (8000, 4000), color = (0, 0, 0)) h = 0 w = 0 i = 0 para img em img_arr: # pbar.set_description (f "Processando imagem {i + 1}") new.paste (img, (w, h), img) w + = 1000 se w == 8000: h + = 500 w = 0 i + = 1 return new def processImage (img): RADIUS = 20 # Abra uma imagem im = Image.open ("pilbuffer.png") # Cole a imagem no fundo branco diam = 2 * RADIUS back = Image.new ('RGB', (im.size [0] + diam, im.size [1] + diam), (0, 0, 0)) back.paste (im, (RADIUS, RADIUS)) # Criar máscara de máscara de desfoque = Image.new ('L', (im.size [0] + diam, im.size [1] + diam), 255) blck = Image.new ('L', (im.size [0] - diam, im.size [1] - diam), 0) mask.paste (blck, (diam, diam)) # Desfoque a imagem e cole a borda desfocada de acordo com a máscara blur = back.filter (ImageFilter. GaussianBlur (RADIUS / 2)) back.paste (blur, mask = mask) back.save ("transaction.png") back.close () #Criar máscara e filtro substituir preto por alpha image = cv2.imread (" transito ion.png ") hMin = 0 sMin = 0 vMin = 20 hMax = 180 sMax = 255 vMax = 255 inferior = np.array ([hMin, sMin, vMin]) superior = np.array ([hMax, sMax, vMax]) hsv = cv2.cvtColor (image, cv2. COLOR_BGR2HSV) mask = cv2.inRange (hsv, inferior, superior) output = cv2.bitwise_and (image, image, mask = mask) * _, alpha = cv2.split (output) dst = cv2.merge ((output, alpha)) output = dst com open ("buffer.png", "w +") como arquivo: pass cv2.imwrite ("buffer.png", output) #Detecção de borda e desfoque se _name_ == "_main_": search_terms = ["supernova", "planeta", "galáxia", "via láctea", "nebulosa", "estrelas"] # Os termos de pesquisa podem ser alterados para o que você quiser que o planetário inclua img_arr = get_image_search (64, search_terms) print ("Imagens recuperadas e neural filtradas") img = stitch_beta (img_arr) print ("Imagens costuradas") img.save ("stitched.png")

Etapa 7: o aplicativo Electron

Visão geral

Criaremos um aplicativo de elétrons simples que apenas posiciona e carrega o elemento PhotoSphere. Os arquivos main.js e package.json vêm direto do site Electron, e o HTML é uma versão ligeiramente modificada do HTML fornecido no site PhotoSphere. Incluí os arquivos, mas renomei todos para.txt, pois o Instructables não permite esses tipos de arquivo. Para usar os arquivos, renomeie-os com a extensão apropriada.

O código

main.js

const {app, BrowserWindow} = require ('electron')

function createWindow () {const win = new BrowserWindow ({width: 800, height: 600, webPreferences: {nodeIntegration: true}}) win.loadFile ('index.html')} app.whenReady (). then (createWindow) app.on ('window-all-closed', () => {if (process.platform! == 'darwin') {app.quit ()}}) app.on ('activate', () => {if (BrowserWindow.getAllWindows (). length === 0) {createWindow ()}})

package.json

{

"name": "space", "version": "0.1.0", "main": "main.js", "scripts": {"start": "electron." }}

index.html

Etapa 8: Execução

Criação da imagem equirretangular

Para criar a imagem, execute o script api.py no prompt de comando, com seu ambiente virtual ativado:

api.py

Após a conclusão dos scripts de execução, execute o aplicativo electron usando:

npm startVoila! Seu planetário está ativo! Obrigado por ler:)

Recomendado: