Neuronales Netzbetriebenes Planetarium mit Python, Electron und Keras - Gunook
Neuronales Netzbetriebenes Planetarium mit Python, Electron und Keras - Gunook
Anonim
Neuronales Netzbetriebenes Planetarium mit Python, Electron und Keras
Neuronales Netzbetriebenes Planetarium mit Python, Electron und Keras

In diesem anweisbaren zeige ich Ihnen, wie ich einen automatischen 3D-Planetarium-Generator mit Python und Electron geschrieben habe

Das obige Video zeigt eines der zufälligen Planetarien, die das Programm generiert hat.

**Hinweis: Dieses Programm ist keineswegs perfekt und an manchen Stellen nicht sehr pythonisch. Der Diskriminator des neuronalen Netzes ist nur zu ~89 % genau, sodass einige seltsame Bilder es ins Planetarium schaffen**

Besonderheiten

Das Planetarium fragt eine NASA-API nach weltraumbezogenen Bildern ab und verwendet ein neuronales Faltungsnetzwerk, um zu bestimmen, ob das Bild für die Verarbeitung geeignet ist. Das Programm verwendet dann OpenCV, um den Hintergrund aus dem Bild zu entfernen, und schließlich werden die Bilder zu einem großen gleicheckigen Bild zusammengefügt. Dieses Bild wird dann gespeichert, und eine Electron Node.js-Anwendung öffnet das Bild und verwendet das PhotoSphere.js-Paket, um das Bild in einem 3D-Format im Planetariumsstil anzuzeigen.

Abhängigkeiten

Python:

  • Keras
  • Kopfkissen
  • cv2
  • Numpy
  • Anfragen
  • urllib
  • Willkürlich
  • Zeit
  • io

Elektron:

PhotoSphere

Schritt 1: Einrichten Ihrer Umgebung

Electron und Python installieren

Stellen Sie zunächst sicher, dass node.js und npm installiert sind (wenn nicht, können Sie sie hier herunterladen).

Als nächstes müssen Sie Electron installieren. Öffnen Sie eine Eingabeaufforderung und geben Sie den folgenden Befehl ein:

npm install Elektron -g

Als nächstes benötigen Sie Python, das hier heruntergeladen werden kann

Einrichten einer virtuellen Umgebung

Öffnen Sie eine Eingabeaufforderung und geben Sie die folgenden Befehle ein, um Ihre virtuelle Umgebung einzurichten:

pip installieren virtualenv

Virtualenv-Raum

CD-Platz

Skripte\aktivieren

Python-Abhängigkeiten installieren

Führen Sie diese Befehle in der Eingabeaufforderung aus, um Ihre Python-Abhängigkeiten zu installieren:

pip install keras

Pip installieren Kissen

pip install numpy

Pip-Installationsanfragen

pip install opencv-pythonWenn Sie das Netzwerk selbst trainieren möchten, stellen Sie sicher, dass Sie die GPU-Beschleunigung für Keras einrichten

Schritt 2: Abfragen der NASA-Such-API

Überblick

Die NASA hat viele wirklich nützliche APIs, die Sie für Ihre Projekte verwenden können. Für dieses Projekt werden wir die Such-API verwenden, die es uns ermöglicht, die Bilddatenbank der NASA nach weltraumbezogenen Bildern zu durchsuchen.

Der Code

Zuerst müssen wir eine Python-Funktion definieren, um ein Argument zu akzeptieren, das als Suchbegriff fungiert:

def get_image_search(phrase):

passieren

Als Nächstes konvertieren wir den Suchbegriff in das URL-Format und verwenden dann die Anforderungsbibliothek, um die API abzufragen:

def get_image_search(phrase):

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

Schließlich decodieren wir den collection+JSON-String, den die API an uns zurückgegeben hat, und extrahieren eine Liste von Links zu Bildern, die sich auf den Suchbegriff beziehen:

def get_image_search(phrase):

params = {"q": urllib.parse.quote(arg), "media_type": "image"} results = request.get("https://images-api.nasa.gov/search", params=params) data = [result['href'] for result in results.json()["collection"]["items"]

Na, bitte! Wir haben jetzt ein Code-Snippet, das die NASA-Bildsuch-API abfragen und eine Liste mit Links zu Bildern zurückgeben kann, die sich auf unseren Suchbegriff beziehen.

Schritt 3: Das Convolutional Neural Network

Überblick

Die Aufgabe des neuronalen Netzes besteht darin, zu klassifizieren, ob ein Bild von etwas im Raum ist oder nicht. Dazu verwenden wir ein Convolutional Neural Network oder CNN, um eine Reihe von Matrixoperationen an dem Bild durchzuführen und zu bestimmen, wie räumlich-y es ist. Ich werde das alles nicht erklären, da dahinter viel Theorie steckt, aber wenn Sie etwas über neuronale Netze lernen möchten, empfehle ich "Machine Learning Mastery".

Der Code

Zuerst müssen wir unsere Abhängigkeiten importieren:

Importieren von OS

#Fix für das Problem beim Trainieren von Stepn auf der GPU os.environ['CUDA_VISIBLE_DEVICES'] = '' import 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 import image from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D from keras.layers import Activation, Dropout, Flatten, Dense from keras import backend als K aus PIL import Image numpy als np importieren

Als nächstes müssen wir unser Modell definieren:

img_width, img_height = 1000, 500

train_data_dir = 'v_data/train' valid_data_dir = 'v_data/test' nb_train_samples = 203 nb_validation_samples = 203 Epochen = 10 batch_size = 8 if K.image_data_format() == 'channels_first': input_shape = (3, img_width, img_height, img_height), img = (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(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(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(1)) model.add(Activation('sigmoid')) model.compile (loss='binary_crossentropy', Optimizer='rmsprop', metrics=['accuracy'])

Ich habe das Modell für Sie trainiert, aber wenn Sie das Modell selbst trainieren möchten, an Ihrem eigenen Datensatz, dann habe ich den Trainingscode angehängt. Andernfalls können Sie die HDF5-Datei des trainierten Modells herunterladen. Aufgrund von Instructables-Dateibeschränkungen musste ich sie mit einer Erweiterung ".txt" umbenennen. Um es zu verwenden, benennen Sie die Datei in die Erweiterung ".h5" um und laden Sie sie mit diesem Code:

model.load_weights("model_saved.h5")

Um das Netzwerk zu verwenden, um vorherzusagen, wie groß ein Bild ist, definieren wir diese Funktion:

def vorhersagen(image_path):

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

Schritt 4: Verarbeiten des Bildes

Überblick

Zur Bildbearbeitung verwende ich die OpenCV (cv2) Bibliothek. Zuerst verwischen wir die Ränder des Bildes und entfernen dann den Hintergrund, indem wir eine Maske erstellen und die Alpha-Werte der dunkleren Farben ändern

Der Code

Dies ist der Teil der Funktion, der die Kanten verwischt:

def processImage(img):

RADIUS = 20 # Bild öffnen im = Image.open("pilbuffer.png") # Bild auf weißem Hintergrund einfügen diam = 2 * RADIUS back = Image.new('RGB', (im.size[0] + diam, im.size[1] + diam), (0, 0, 0)) back.paste(im, (RADIUS, RADIUS)) # Unschärfemaske erstellen 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. past(blck, (diam, diam)) # Bild verwischen und verschwommene Kante gemäß Maske einfügen blur = back.filter(ImageFilter. GaussianBlur(RADIUS / 2)) back.paste(blur, mask=mask) back.save(" Übergang.png") zurück.close()

Als nächstes werden wir die dunkleren Farben auf transparent setzen und das Bild vorübergehend speichern:

#Maske und Filter erstellen, Schwarz durch Alpha ersetzen

image = cv2.imread("transition.png") hMin = 0 sMin = 0 vMin = 20 hMax = 180 sMax = 255 vMax = 255 Lower = np.array([hMin, sMin, vMin]) Upper = np.array([hMax, sMax, vMax]) hsv = cv2.cvtColor(image, cv2. COLOR_BGR2HSV) mask = cv2.inRange(hsv, Lower, Upper) output = cv2.bitwise_and(image, image, mask=mask) *_, alpha = cv2.split(output) dst = cv2.merge((output, alpha)) output = dst with open("buffer.png", "w+") als Datei: pass cv2.imwrite("buffer.png", output)

Schritt 5: Zusammenfügen von Bildern zu einer äquirektangulären Projektion

Überblick

Diese Funktion nimmt mehrere Bilder und fügt sie unter Verwendung der PIL-Bibliothek (Kissen) in ein Format zusammen, das vom PhotoSphere.js-Paket interpretiert werden kann

Der Code

Zuerst müssen wir ein Image erstellen, das als Host für die anderen Images fungieren kann:

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

Als nächstes müssen wir das Array von Bildern (die alle auf 1000x500 verkleinert wurden) durchlaufen und in das Bild einfügen:

h = 0

w = 0 i = 0 für img in img_arr: new.paste(img, (w, h), img) w += 1000 if w == 8000: h += 500 w = 0 i += 1

Jetzt packen wir dies einfach in eine Funktion ein, die ein Array von Bildern als Argument verwendet und das neue Bild zurückgibt:

def stich_beta(img_arr):

new = Image.new("RGBA", (8000, 4000), color=(0, 0, 0)) h = 0 w = 0 i = 0 für img in img_arr: new.paste(img, (w, h), img) w += 1000 wenn w == 8000: h += 500 w = 0 i += 1 Rückgabe neu

Schritt 6: Das vollständige Python-Skript

Dies ist das vollständige Skript für das neuronale Python-Netzwerk, das als net.py gespeichert und in das Hauptskript importiert wird:

# Bibliotheken importieren

import os #Fix für das Problem während des Trainierens auf der GPU os.environ['CUDA_VISIBLE_DEVICES'] = '' import 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 import image from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D from keras.layers import Activation, Dropout, Flatten, Dense from keras import backend als K from 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 Epochen = 10 batch_size = 8 if K.image='_channelsformat(): 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(Aktivierung ('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(32, (2, 2))) model. 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(Activation('relu')) model.add(Dropout(0.5.))) model.add(Dense(1)) model.add(Activation('sigmoid')) model.compile(loss='binary_crossentropy', Optimizer='rmsprop', metrics=['accuracy']) 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) Ergebnis zurückgeben [0][0]

Dies ist die Hauptpythondatei api.py:

Importanfragen, sys, random, urllib.parse, cv2

from PIL import Image, ImageFilter from io import BytesIO import numpy as np import net def get_image_search(num, phrase): count = 0 img_arr = for arg in phrase: print(arg) print(f"Aktuelle Bildanzahl: {count }") i = 0 params = {"q": urllib.parse.quote(arg), "media_type": "image"} results = request.get("https://images-api.nasa.gov/search ", params=params) data = [result['href'] for result in results.json()["collection"]["items"] print(len(data)) if num > len(data): num = len(data) während count = num: break print(f"\n{count} images retreived") return img_arr defstich_beta(img_arr): new = Image.new("RGBA", (8000, 4000), color=(0, 0, 0)) h = 0 w = 0 i = 0 für img in img_arr: #pbar.set_description(f"Processing image {i+1}") new.paste(img, (w, h), img) w += 1000 if w == 8000: h += 500 w = 0 i += 1 return new def processImage(img): RADIUS = 20 # Bild öffnen im = Image.open("pilbuffer.png") # Bild auf weißem Hintergrund einfügen diam = 2 * RADIUS back = Image.new('RGB', (im.size[0] + diam, im.size[1] + diam), (0, 0, 0)) back.paste(im, (RADIUS, RADIUS)) # Unschärfemaske erstellen 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)) # Bild verwischen und verschwommene Kante gemäß Maske einfügen blur = back.filter(ImageFilter. GaussianBlur(RADIUS / 2)) back.paste(blur, mask=mask) back.save("transition.png") back.close() #Maske und Filter erstellen Schwarz durch Alpha ersetzen image = cv2.imread(" Transit ion.png") hMin = 0 sMin = 0 vMin = 20 hMax = 180 sMax = 255 vMax = 255 Lower = np.array([hMin, sMin, vMin]) Upper = np.array([hMax, sMax, vMax]) hsv = cv2.cvtColor(image, cv2. COLOR_BGR2HSV) mask = cv2.inRange(hsv, Lower, Upper) output = cv2.bitwise_and(image, image, mask=mask) *_, alpha = cv2.split(output) dst = cv2.merge((output, alpha)) output = dst with open("buffer.png", "w+") as file: pass cv2.imwrite("buffer.png", output) #Kantenerkennung und Unschärfe if _name_ == "_main_": search_terms = ["Supernova", "Planet", "Galaxie", "Milchstraße", "Nebel", "Sterne"] #Die Suchbegriffe können beliebig geändert werden, was das Planetarium enthalten soll img_arr = get_image_search(64, search_terms) print("Bilder abgerufen und neural gefiltert") img = Stitch_beta(img_arr) print("Bilder genäht") img.save("stitched.png")

Schritt 7: Die Electron-App

Überblick

Wir werden eine einfache Elektronen-App erstellen, die nur das PhotoSphere-Element positioniert und lädt. Die Dateien main.js und package.json stammen direkt von der Electron-Website, und der HTML-Code ist eine leicht modifizierte Version des HTML-Codes, der auf der PhotoSphere-Website bereitgestellt wird. Ich habe die Dateien eingefügt, aber alle in.txt umbenannt, da Instructables diese Dateitypen nicht zulässt. Um die Dateien zu verwenden, benennen Sie sie mit der entsprechenden Erweiterung um.

Der Code

main.js

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

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() } })

Paket.json

{

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

index.html

Schritt 8: Ausführung

Erstellen des äquirektangulären Bildes

Um das Image zu erstellen, führen Sie das api.py-Skript in der Eingabeaufforderung mit aktivierter virtueller Umgebung aus:

api.py

Nachdem die Ausführung der Skripte abgeschlossen ist, führen Sie die Elektron-App mit folgendem Befehl aus:

npm startVoila! Ihr Planetarium ist aktiv! Danke fürs Lesen:)

Empfohlen: