Planetario con red neuronal que utiliza Python, Electron y Keras: 8 pasos
Planetario con red neuronal que utiliza Python, Electron y Keras: 8 pasos
Anonim
Planetario con red neuronal que utiliza Python, Electron y Keras
Planetario con red neuronal que utiliza Python, Electron y Keras

En este instructivo, les mostraré cómo escribí un generador de planetario 3D automático, usando Python y Electron

El video de arriba muestra uno de los planetarios aleatorios que generó el programa.

** Nota: este programa no es perfecto de ninguna manera y, en algunos lugares, no es muy pitónico. El discriminador de red neuronal tiene una precisión de solo ~ 89%, por lo que algunas imágenes extrañas llegarán al planetario **

Detalles específicos

El planetario consulta una API de la NASA en busca de imágenes relacionadas con el espacio y utiliza una red neuronal convolucional para determinar si la imagen es adecuada para su procesamiento. Luego, el programa usa OpenCV para eliminar el fondo de la imagen y, finalmente, las imágenes se unen en una imagen equirrectangular grande. Luego, esta imagen se guarda y una aplicación Electron Node.js abre la imagen y usa el paquete PhotoSphere.js para ver la imagen en un formato 3D estilo planetario.

Dependencias

Pitón:

  • Keras
  • Almohada
  • cv2
  • Numpy
  • Peticiones
  • urllib
  • Aleatorio
  • tiempo
  • io

Electrón:

Fotosfera

Paso 1: Configuración de su entorno

Instalación de Electron y Python

Primero, asegúrese de tener node.js y npm instalados (si no, puede descargar aquí)

A continuación, debe instalar Electron. Abra un símbolo del sistema e ingrese el siguiente comando:

npm instalar electron -g

A continuación, necesita Python, que se puede descargar aquí.

Configurar un entorno virtual

Abra un símbolo del sistema, luego ingrese los siguientes comandos para configurar su entorno virtual:

pip instalar virtualenv

espacio virtualenv

espacio de cd

scripts / activar

Instalación de dependencias de Python

Ejecute estos comandos en el símbolo del sistema para instalar sus dependencias de Python:

pip instalar keras

pip instalar almohada

pip instalar numpy

solicitudes de instalación de pip

pip instalar opencv-pythonSi desea entrenar la red usted mismo, asegúrese de configurar la aceleración de GPU para Keras

Paso 2: consultar la API de búsqueda de la NASA

Visión general

La NASA tiene muchas API realmente útiles que puede usar con sus proyectos. Para este proyecto, utilizaremos la API de búsqueda, que nos permite buscar en la base de datos de imágenes de la NASA imágenes relacionadas con el espacio.

El código

Primero, necesitamos definir una función de Python para aceptar un argumento que actuará como término de búsqueda:

def get_image_search (frase):

aprobar

A continuación, convertiremos el término de búsqueda a formato de URL, luego usaremos la biblioteca de solicitudes para consultar la API:

def get_image_search (frase):

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

Finalmente, decodificaremos la colección + cadena JSON que nos devolvió la API, y extraeremos una lista de enlaces a imágenes relacionadas con el término de búsqueda:

def get_image_search (frase):

params = {"q": urllib.parse.quote (arg), "media_type": "imagen"} resultados = solicitudes.get ("https://images-api.nasa.gov/search", params = params) data = [result ['href'] para el resultado en results.json () ["colección"] ["elementos"]

¡Aquí vamos! Ahora tenemos un fragmento de código que puede consultar la API de búsqueda de imágenes de la NASA y devolver una lista de enlaces a imágenes relacionadas con nuestro término de búsqueda.

Paso 3: la red neuronal convolucional

Visión general

El trabajo de la red neuronal es clasificar si una imagen es de algo en el espacio o no. Para hacer esto, usaremos una red neuronal convolucional, o CNN, para realizar una serie de operaciones matriciales en la imagen y determinar qué tan espacial es. No explicaré todo esto, porque hay mucha teoría detrás de esto, pero si quieres aprender sobre las redes neuronales, te sugiero "Dominio del aprendizaje automático".

El código

Primero, necesitamos importar nuestras dependencias:

importar sistema operativo

#Corregir el problema durante el tren stepn oN GPU os.environ ['CUDA_VISIBLE_DEVICES'] = '' import tensorflow as tf if tf.test.gpu_device_name (): print ('GPU found') else: print ("No GPU found") de keras.preprocessing.image importar ImageDataGenerator de keras.preprocessing importar imagen de keras.models importar secuencial de keras.layers importar Conv2D, MaxPooling2D de keras.layers importar Activación, Abandono, Aplanar, Denso de keras importar backend como K de PIL importar imagen importar numpy como np

A continuación, necesitamos definir nuestro 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_first': input_shepe = (3, img_sight_hape) = (img_width, img_height, 3) model = Sequential () model.add (Conv2D (32, (2, 2), input_shape = input_shape)) model.add (Activación ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Conv2D (32, (2, 2))) model.add (Activación ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Conv2D (64, (2, 2))) model.add (Activación ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Flatten ()) model. add (Dense (64)) model.add (Activación ('relu')) model.add (Dropout (0.5)) model.add (Dense (1)) model.add (Activación ('sigmoide')) model.compile (pérdida = 'binary_crossentropy', optimizer = 'rmsprop', metrics = ['precisión'])

He entrenado el modelo para usted, pero si desea entrenar el modelo usted mismo, en su propio conjunto de datos, adjunto el código de entrenamiento. De lo contrario, puede descargar el archivo HDF5 del modelo entrenado. Debido a las restricciones del archivo Instructables, tuve que renombrarlo con una extensión ".txt". Para usarlo, cambie el nombre del archivo a una extensión ".h5" y cárguelo con este código:

model.load_weights ("model_saved.h5")

Para usar la red para predecir qué tan espacial es una imagen, definiremos esta función:

def predecir (ruta_imagen):

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]

Paso 4: procesamiento de la imagen

Visión general

Para el procesamiento de imágenes, estoy usando la biblioteca OpenCV (cv2). Primero, desenfocaremos los bordes de la imagen y luego eliminaremos el fondo creando una máscara y cambiando los valores alfa de los colores más oscuros.

El código

Esta es la parte de la función que difumina los bordes:

def processImage (img):

RADIUS = 20 # Abrir una imagen im = Image.open ("pilbuffer.png") # Pegar imagen sobre fondo blanco diam = 2 * RADIUS back = Image.new ('RGB', (im.size [0] + diam, im.size [1] + diam), (0, 0, 0)) back.paste (im, (RADIUS, RADIUS)) # Crear máscara de máscara de desenfoque = 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)) # Desenfocar la imagen y pegar el borde difuminado de acuerdo con la máscara blur = back.filter (ImageFilter. GaussianBlur (RADIUS / 2)) back.paste (blur, mask = mask) back.save (" transición-p.webp

A continuación, configuraremos los colores más oscuros en transparentes y guardaremos la imagen temporalmente:

#Crear máscara y filtro reemplazar negro con alfa

image = cv2.imread ("transición.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 (imagen, cv2. COLOR_BGR2HSV) máscara = cv2.inRange (hsv, inferior, superior) salida = cv2.bitwise_and (imagen, imagen, máscara = máscara) * _, alfa = cv2.split (salida) dst = cv2.merge ((salida, alfa)) salida = dst con open ("buffer.png", "w +") como archivo: pass cv2.imwrite ("buffer.png", salida)

Paso 5: Unir imágenes en una proyección equirectangular

Visión general

Esta función toma varias imágenes y las une en un formato que puede ser interpretado por el paquete PhotoSphere.js, utilizando la biblioteca PIL (almohada).

El código

Primero, necesitamos crear una imagen que pueda actuar como anfitrión para las otras imágenes:

nuevo = Imagen.nuevo ("RGBA", (8000, 4000), color = (0, 0, 0))

A continuación, debemos recorrer la matriz de imágenes (que se han redimensionado a 1000x500) y colocarlas en la imagen:

h = 0

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

Ahora acabamos de resumir esto en una función que toma una matriz de imágenes como argumento y devuelve la nueva imagen:

def puntada_beta (img_arr):

nuevo = Imagen.nuevo ("RGBA", (8000, 4000), color = (0, 0, 0)) h = 0 w = 0 i = 0 para img en img_arr: new.paste (img, (w, h), img) w + = 1000 si w == 8000: h + = 500 w = 0 i + = 1 devuelve nuevo

Paso 6: el script de Python completo

Este es el script completo de la red neuronal de Python, que se guarda como net.py y se importa al script principal:

# importar bibliotecas

import os #Fix for issue during train stepn on GPU os.environ ['CUDA_VISIBLE_DEVICES'] = '' import tensorflow as tf if tf.test.gpu_device_name (): print ('GPU found') else: print ("No GPU found ") de ImageDataGenerator importación keras.preprocessing.image de la imagen de importación keras.preprocessing de keras.models importar secuencial desde el keras.layers importar Conv2D, MaxPooling2D de keras.layers importar activación, Dropout, Aplanar, denso de backend importación Keras como K de PIL import Image import numpy as 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 if 'K.image_data_format_formato: input_shape = (3, img_width, img_height) más: input_shape = (img_width, img_height, 3) modelo = Sequential () model.add (Conv2D (32, (2, 2), input_shape = input_shape)) model.add (activación ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Conv2D (32, (2, 2))) modelo. add (Activación ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Conv2D (64, (2, 2))) model.add (Activación ('relu')) model.add (MaxPooling2D (pool_size = (2, 2))) model.add (Flatten ()) model.add (Dense (64)) model.add (Activación ('relu')) model.add (Dropout (0.5))) model.add (Dense (1)) model.add (Activación ('sigmoide')) model.compile (loss = 'binary_crossentropy', optimizer = 'rmsprop', metrics = ['precision']) 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) return result [0] [0]

Este es el archivo principal de Python, api.py:

solicitudes de importación, sys, random, urllib.parse, cv2

de PIL import Image, ImageFilter de io import BytesIO import numpy as np import net def get_image_search (núm, frase): count = 0 img_arr = para arg en la frase: print (arg) print (f "Recuento de imágenes actual: {count } ") i = 0 params = {" q ": urllib.parse.quote (arg)," media_type ":" image "} results = orders.get (" https://images-api.nasa.gov/search ", params = params) data = [result ['href'] for result in results.json () [" colección "] [" elementos "] print (len (datos)) if num> len (data): num = len (datos) mientras cuenta = num: break print (f "\ n {count} imágenes 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 en img_arr: # pbar.set_description (f "Procesando imagen {i + 1}") new.paste (img, (w, h), img) w + = 1000 si w == 8000: h + = 500 w = 0 i + = 1 return new def processImage (img): RADIUS = 20 # Abrir una imagen im = Image.open ("pilbuffer.png") # Pegar imagen sobre fondo blanco diam = 2 * RADIUS back = Image.new ('RGB', (im.size [0] + diam, im.size [1] + diam), (0, 0, 0)) back.paste (im, (RADIUS, RADIUS)) # Crear máscara de desenfoque mask = 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)) # Desenfocar la imagen y pegar el borde borroso según la máscara desenfoque = back.filter (ImageFilter. tránsito 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 (imagen, cv2. COLOR_BGR2HSV) máscara = cv2.inRange (hsv, inferior, superior) salida = cv2.bitwise_and (imagen, imagen, máscara = máscara) * _, alpha = cv2.split (salida) dst = cv2.merge ((salida, alfa)) salida = dst con open ("buffer.png", "w +") como archivo: pass cv2.imwrite ("buffer.png", salida) #Detección de bordes y desenfoque si _name_ == "_main_": search_terms = ["supernova", "planeta", "galaxia", "vía láctea", "nebulosa", "estrellas"] #Los términos de búsqueda pueden modificarse por lo que quieras que incluya el planetario img_arr = get_image_search (64, search_terms) print ("Imágenes recuperadas y filtradas neuronalmente") img = stitch_beta (img_arr) print ("Imágenes unidas") img.save ("stitched.png")

Paso 7: la aplicación Electron

Visión general

Crearemos una aplicación de electrones simple que simplemente posiciona y carga el elemento PhotoSphere. Los archivos main.js y package.json provienen directamente del sitio web de Electron, y el HTML es una versión ligeramente modificada del HTML proporcionado en el sitio web de PhotoSphere. Incluí los archivos, pero renombré todos a.txt, ya que Instructables no permite estos tipos de archivos. Para usar los archivos, cámbieles el nombre con la extensión adecuada.

El 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 (). luego (createWindow) app.on ('ventana-cerrada', () => {if (process.platform! == 'darwin') {app.quit ()}}) app.on ('activar', () => {if (BrowserWindow.getAllWindows (). length === 0) {createWindow ()}})

package.json

{

"nombre": "espacio", "versión": "0.1.0", "main": "main.js", "scripts": {"start": "electron". }}

index.html

Paso 8: ejecución

Creando la imagen equirrectangular

Para crear la imagen, ejecute el script api.py en el símbolo del sistema, con su entorno virtual activado:

api.py

Una vez que los scripts hayan terminado de ejecutarse, ejecute la aplicación electron usando:

inicio npm¡Voila! ¡Tu planetario está activo! Gracias por leer:)

Recomendado: