Planetarium zasilane siecią neuronową przy użyciu Pythona, elektronu i Keras: 8 kroków
Planetarium zasilane siecią neuronową przy użyciu Pythona, elektronu i Keras: 8 kroków
Anonim
Planetarium zasilane siecią neuronową przy użyciu języka Python, Electron i Keras
Planetarium zasilane siecią neuronową przy użyciu języka Python, Electron i Keras

W tej instrukcji pokażę, jak napisałem automatyczny generator planetarium 3D, używając Pythona i Electrona

Powyższy film przedstawia jedno z losowych planetariów wygenerowanych przez program.

**Uwaga: ten program nie jest w żaden sposób doskonały, aw niektórych miejscach niezbyt pytoniczny. Dyskryminator sieci neuronowej jest dokładny tylko w ~89%, więc niektóre dziwne obrazy trafią do planetarium**

Specyfika

Planetarium wysyła zapytanie do NASA API o obrazy związane z przestrzenią kosmiczną i wykorzystuje splotową sieć neuronową, aby określić, czy obraz nadaje się do przetwarzania. Następnie program używa OpenCV do usunięcia tła z obrazu, a na koniec obrazy są łączone w jeden duży, równoprostokątny obraz. Obraz ten jest następnie zapisywany, a aplikacja Electron Node.js otwiera obraz i używa pakietu PhotoSphere.js do wyświetlania obrazu w formacie 3D w stylu planetarium.

Zależności

Pyton:

  • Keras
  • Poduszka
  • cv2
  • Numpy
  • Upraszanie
  • urllib
  • Losowy
  • czas
  • ja

Elektron:

Fotosfera

Krok 1: Konfiguracja środowiska

Instalowanie Electron i Pythona

Najpierw upewnij się, że masz zainstalowane node.js i npm (jeśli nie, możesz pobrać tutaj)

Następnie musisz zainstalować Electron. Otwórz wiersz polecenia i wprowadź następujące polecenie:

npm zainstaluj elektron -g

Następnie potrzebujesz Pythona, który możesz pobrać tutaj

Konfigurowanie środowiska wirtualnego

Otwórz wiersz polecenia, a następnie wprowadź następujące polecenia, aby skonfigurować środowisko wirtualne:

pip zainstaluj virtualenv

przestrzeń wirtualna

miejsce na cd

skrypty\aktywuj

Instalowanie zależności Pythona

Uruchom te polecenia w wierszu poleceń, aby zainstalować zależności Pythona:

pip zainstalować keras

pip zainstalować poduszkę

pip zainstaluj numpy

prośby o instalację pip

pip zainstaluj opencv-pythonJeśli chcesz samodzielnie szkolić sieć, skonfiguruj akcelerację GPU dla Keras

Krok 2: Wysyłanie zapytań do API wyszukiwania NASA

Przegląd

NASA ma wiele naprawdę przydatnych interfejsów API, których możesz używać w swoich projektach. W tym projekcie użyjemy API wyszukiwania, które pozwoli nam przeszukiwać bazę obrazów NASA pod kątem obrazów związanych z przestrzenią kosmiczną.

Kod

Najpierw musimy zdefiniować funkcję Pythona, aby zaakceptować argument, który będzie działał jako wyszukiwany termin:

def get_image_search(fraza):

przechodzić

Następnie skonwertujemy wyszukiwane hasło do formatu adresu URL, a następnie użyjemy biblioteki żądań do zapytania API:

def get_image_search(fraza):

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

Na koniec zdekodujemy ciąg kolekcja+JSON zwrócony przez interfejs API i wyodrębnimy listę linków do obrazów związanych z wyszukiwanym terminem:

def get_image_search(fraza):

params = {"q": urllib.parse.quote(arg), "media_type": "image"} results = requests.get("https://images-api.nasa.gov/search", params=params) data = [wynik['href'] dla wyniku w results.json()["kolekcja"]["elementy"]

No to jedziemy! Mamy teraz fragment kodu, który może wysyłać zapytania do interfejsu API wyszukiwania obrazów NASA i zwracać listę linków do obrazów powiązanych z naszym terminem wyszukiwania.

Krok 3: Splotowa sieć neuronowa

Przegląd

Zadaniem sieci neuronowej jest klasyfikowanie, czy obraz przedstawia coś w przestrzeni, czy nie. Aby to zrobić, użyjemy splotowej sieci neuronowej lub CNN, aby wykonać serię operacji na macierzach na obrazie i określić, jaka jest przestrzeń-y. Nie będę tego wszystkiego wyjaśniał, bo kryje się za tym sporo teorii, ale jeśli chcesz poznać sieci neuronowe, proponuję "Machine Learning Mastery"

Kod

Najpierw musimy zaimportować nasze zależności:

importuj system

#Napraw błąd podczas trenowania stepn na GPU os.environ['CUDA_VISIBLE_DEVICES'] = '' import tensorflow jako tf if tf.test.gpu_device_name(): print('Znaleziono GPU') else: print("Nie znaleziono GPU") z keras.preprocessing.image import ImageDataGenerator z keras.preprocessing import obrazu z keras.models import Sequential z keras.layers import Conv2D, MaxPooling2D z keras.layers import Activation, Dropout, Flatten, Dense z keras import Backend jako K z PIL import Image importuj numer jako np

Następnie musimy zdefiniować nasz model:

szerokość_obrazu, wysokość_obrazu = 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_shapeth =, img_shapeth = (3, = (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()). add(Dense(64)) model.add(Aktywacja('relu')) model.add(Dropout(0.5)) model.add(Dense(1)) model.add(Aktywacja('sigmoid')) model.compile (loss='binary_crossentropy', Optimizer='rmsprop', metrics=['accuracy'])

Wytrenowałem model dla Ciebie, ale jeśli chciałbyś sam trenować model na własnym zbiorze danych, to załączam kod treningowy. W przeciwnym razie możesz pobrać plik HDF5 wytrenowanego modelu. Ze względu na ograniczenia plików Instructables musiałem zmienić jego nazwę na rozszerzenie ".txt". Aby z niego skorzystać, zmień nazwę pliku na rozszerzenie ".h5" i załaduj go tym kodem:

model.load_weights("model_saved.h5")

Aby użyć sieci do przewidywania, jak spacja-y jest na obrazie, zdefiniujemy tę funkcję:

def przewidywać(ścieżka_obrazu):

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]

Krok 4: Przetwarzanie obrazu

Przegląd

Do przetwarzania obrazu używam biblioteki OpenCV (cv2). Najpierw rozmyjemy krawędzie obrazu, a następnie usuniemy tło, tworząc maskę i zmieniając wartości alfa ciemniejszych kolorów

Kod

Oto część funkcji, która zaciera krawędzie:

def processImage(img):

RADIUS = 20 # Otwórz obraz im = Image.open("pilbuffer.png") # Wklej obraz na białym tle diam = 2 * RADIUS back = Image.new('RGB', (im.size[0] + diam, im.size[1] + diam), (0, 0, 0)) back.paste(im, (RADIUS, RADIUS)) # Utwórz maskę rozmycia = 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) maska. paste(blck, (diam, diam)) # Rozmyj obraz i wklej rozmytą krawędź zgodnie z maską blur = back.filter(ImageFilter. GaussianBlur(RADIUS / 2)) back.paste(blur, mask=mask) back.save(" przejście.png") wstecz.zamknij()

Następnie ustawimy ciemniejsze kolory na przezroczyste i tymczasowo zapiszemy obraz:

#Utwórz maskę i filtr zamień czarny na alfa

image = cv2.imread("przejście.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(obraz, cv2. COLOR_BGR2HSV) maska = cv2.inRange(hsv, dolny, górny) output = cv2.bitwise_and(obraz, obraz, maska=maska) *_, alpha = cv2.split(wyjście) dst = cv2.merge((wyjście, alfa)) output = dst z open("buffer.png", "w+") jako plik: pass cv2.imwrite("buffer.png", output)

Krok 5: Łączenie obrazów w projekcję równoboczną

Przegląd

Ta funkcja pobiera wiele obrazów i łączy je w format, który może być interpretowany przez pakiet PhotoSphere.js, przy użyciu biblioteki PIL (poduszka)

Kod

Najpierw musimy stworzyć obraz, który może pełnić rolę hosta dla innych obrazów:

nowy = Obraz.nowy("RGBA", (8000, 4000), kolor=(0, 0, 0))

Następnie musimy przejrzeć tablicę obrazów (które zostały przeskalowane do 1000x500) i umieścić je w obrazie:

h = 0

w = 0 i = 0 dla img w img_arr: new.paste(img, (w, h), img) w += 1000 jeśli w == 8000: h += 500 w = 0 i += 1

Teraz po prostu zapakujemy to w funkcję, która jako argument przyjmuje tablicę obrazów i zwraca nowy obraz:

def stitch_beta(img_arr):

new = Image.new("RGBA", (8000, 4000), color=(0, 0, 0)) h = 0 w = 0 i = 0 for img in img_arr: new.paste(img, (w, h), img) w += 1000 jeśli w == 8000: h += 500 w = 0 i += 1 return new

Krok 6: Pełny skrypt Pythona

To jest pełny skrypt sieci neuronowej Pythona, który jest zapisany jako net.py i zaimportowany do głównego skryptu:

# importowanie bibliotek

import os #Napraw problem podczas etapu trenowania na GPU os.environ['CUDA_VISIBLE_DEVICES'] = '' import tensorflow jako tf if tf.test.gpu_device_name(): print('Znaleziono GPU') else: print("Nie znaleziono GPU ") z keras.preprocessing.image import ImageDataGenerator z keras.preprocessing import obrazu z keras.models import Sequential z keras.layers import Conv2D, MaxPooling2D z keras.layers import Activation, Dropout, Flatten, Dense z keras import backendu jako K z 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_st '_channel_st (): 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(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']) model.load_weights("model_saved.h5") def predict(image_path): img = image.load_img(image_saved, target_size=(1000, 500)) img = np.expand_dims(img, axis=0) result=model.predict_classes(img) zwróć wynik [0][0]

To jest główny plik Pythona, api.py:

żądania importu, sys, random, urllib.parse, cv2

z PIL import Image, ImageFilter z io import BytesIO import numpy as np import net def get_image_search(num, fraza): count = 0 img_arr = for arg we frazie: print(arg) print(f"Ilość bieżącego obrazu: {count }") i = 0 params = {"q": urllib.parse.quote(arg), "media_type": "image"} results = requests.get("https://images-api.nasa.gov/search ", params=params) data = [wynik['href'] dla wyniku w results.json()["kolekcja"]["elementy"] print(len(data)) if num > len(data): num = len(dane) podczas count = num: break print(f"\n{count} pobranych obrazów") return img_arr def stitch_beta(img_arr): new = Image.new("RGBA", (8000, 4000), color=(0, 0, 0)) h = 0 w = 0 i = 0 for img in img_arr: #pbar.set_description(f"Przetwarzanie obrazu {i+1}") new.paste(img, (w, h), img) w += 1000 jeśli w == 8000: h += 500 w = 0 i += 1 return new def processImage(img): RADIUS = 20 # Otwórz obraz im = Image.open("pilbuffer.png") # Wklej obraz na białym tle diam = 2 * RADIUS back = Image.new('RGB', (im.size[0] + diam, im.size[1] + diam), (0, 0, 0)) back.paste(im, (RADIUS, RADIUS)) # Utwórz maskę rozmycia = 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)) # Rozmyj obraz i wklej rozmytą krawędź zgodnie z maską blur = back.filter(ImageFilter. GaussianBlur(RADIUS / 2)) back.paste(blur, mask=mask) back.save("transition.png") back.close() #Utwórz maskę i filtr zamień czarny na alpha image = cv2.imread(" tranzyt ion.png") hMin = 0 sMin = 0 vMin = 20 hMax = 180 sMax = 255 vMax = 255 niższy = np. tablica ([hMin, sMin, vMin]) górny = np. tablica ([hMax, sMax, vMax]) hsv = cv2.cvtColor(obraz, cv2. COLOR_BGR2HSV) maska = cv2.inRange(hsv, dolny, górny) output = cv2.bitwise_and(obraz, obraz, maska=maska) *_, alpha = cv2.split(wyjście) dst = cv2.merge((output, alpha)) output = dst z open("buffer.png", "w+") jako plik: pass cv2.imwrite("buffer.png", output) #Wykrywanie krawędzi i rozmycie jeśli _name_ == "_main_": search_terms = ["supernowa", "planeta", "galaktyka", "droga mleczna", "mgławica", "gwiazdy"] #Wyszukiwane hasła można zmienić na dowolne, które ma zawierać planetarium img_arr = get_image_search(64, search_terms) print("Obrazy pobrane i przefiltrowane neuronowo") img = stitch_beta(img_arr) print("Obrazy zszyte") img.save("stitched.png")

Krok 7: Aplikacja elektronowa

Przegląd

Stworzymy prostą aplikację elektronową, która tylko pozycjonuje i ładuje element PhotoSphere. Pliki main.js i package.json pochodzą bezpośrednio ze strony Electron, a HTML to nieco zmodyfikowana wersja kodu HTML udostępnionego na stronie PhotoSphere. Dołączyłem pliki, ale zmieniłem nazwę na.txt, ponieważ Instructables nie zezwala na te typy plików. Aby użyć plików, zmień ich nazwy z odpowiednim rozszerzeniem.

Kod

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

pakiet.json

{

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

index.html

Krok 8: Wykonanie

Tworzenie obrazu równoprostokątnego

Aby utworzyć obraz, uruchom skrypt api.py w wierszu poleceń z aktywowanym środowiskiem wirtualnym:

api.py

Po zakończeniu wykonywania skryptów uruchom aplikację Electron za pomocą:

początek npmVoila! Twoje planetarium jest aktywne! Dziękuje za przeczytanie:)

Zalecana: