Table des matières:
- Étape 1: Configuration de votre environnement
- Étape 2: Interroger l'API de recherche de la NASA
- Étape 3: Le réseau de neurones convolutifs
- Étape 4: traitement de l'image
- Étape 5: Assemblage d'images dans une projection équirectangulaire
- Étape 6: le script Python complet
- Étape 7: L'application Electron
- Étape 8: Exécution
2025 Auteur: John Day | [email protected]. Dernière modifié: 2025-01-23 14:45
Dans ce instructable, je vais vous montrer comment j'ai écrit un générateur de planétarium 3D automatique, à l'aide de Python et Electron
La vidéo ci-dessus montre l'un des planétariums aléatoires générés par le programme.
**Remarque: ce programme n'est en aucun cas parfait, et à certains endroits pas très pythonique. Le discriminateur de réseau neuronal n'est précis qu'à environ 89 %, donc certaines images étranges seront intégrées au planétarium**
Détails
Le planétarium interroge une API de la NASA pour les images liées à l'espace et utilise un réseau de neurones convolutifs pour déterminer si l'image est adaptée au traitement. Le programme utilise ensuite OpenCV pour supprimer l'arrière-plan de l'image, et enfin les images sont assemblées en une grande image équirectangulaire. Cette image est ensuite enregistrée et une application Electron Node.js ouvre l'image et utilise le package PhotoSphere.js pour afficher l'image dans un format 3D de style planétarium.
Dépendances
Python:
- Keras
- Oreiller
- cv2
- Numpy
- Demandes
- urllib
- Aléatoire
- temps
- io
Électron:
Photosphère
Étape 1: Configuration de votre environnement
Installer Electron et Python
Tout d'abord, assurez-vous que node.js et npm sont installés (sinon, vous pouvez télécharger ici)
Ensuite, vous devez installer Electron. Ouvrez une invite de commande et entrez la commande suivante:
npm installer l'électron -g
Ensuite, vous avez besoin de python, qui peut être téléchargé ici
Configuration d'un environnement virtuel
Ouvrez une invite de commande, puis saisissez les commandes suivantes pour configurer votre environnement virtuel:
pip installer virtualenv
espace virtuel
espace disque
scripts\activer
Installation des dépendances Python
Exécutez ces commandes dans l'invite de commande pour installer vos dépendances python:
pip installer keras
pip installer oreiller
pip installer numpy
demandes d'installation de pip
pip installer opencv-pythonSi vous souhaitez former le réseau vous-même, assurez-vous de configurer l'accélération GPU pour Keras
Étape 2: Interroger l'API de recherche de la NASA
Aperçu
La NASA a beaucoup d'API vraiment utiles que vous pouvez utiliser avec vos projets. Pour ce projet, nous utiliserons l'API de recherche, qui nous permet de rechercher dans la base de données d'images de la NASA des images liées à l'espace.
Le code
Tout d'abord, nous devons définir une fonction python pour accepter un argument qui servira de terme de recherche:
def get_image_search(phrase):
passe
Ensuite, nous allons convertir le terme de recherche au format URL, puis utiliser la bibliothèque de requêtes pour interroger l'API:
def get_image_search(phrase):
params = {"q": urllib.parse.quote(arg), "media_type": "image"} résultats = request.get("https://images-api.nasa.gov/search", params=params)
Enfin, nous allons décoder la chaîne collection+JSON que l'API nous a renvoyée, et extraire une liste de liens vers des images liées au terme de recherche:
def get_image_search(phrase):
params = {"q": urllib.parse.quote(arg), "media_type": "image"} resultats = request.get("https://images-api.nasa.gov/search", params=params) data = [result['href'] pour le résultat dans results.json()["collection"]["items"]
C'est parti ! Nous avons maintenant un extrait de code qui peut interroger l'API de recherche d'images de la NASA et renvoyer une liste de liens vers des images liées à notre terme de recherche.
Étape 3: Le réseau de neurones convolutifs
Aperçu
Le travail du réseau de neurones est de classer si une image est de quelque chose dans l'espace, ou si ce n'est pas le cas. Pour ce faire, nous utiliserons un réseau de neurones convolutifs, ou CNN, pour effectuer une série d'opérations matricielles sur l'image et déterminer son espace-y. Je ne vais pas tout expliquer, car il y a beaucoup de théorie derrière, mais si vous voulez en savoir plus sur les réseaux de neurones, je suggère "Machine Learning Mastery"
Le code
Tout d'abord, nous devons importer nos dépendances:
importer le système d'exploitation
#Correction du problème pendant le 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 keras.preprocessing.image importer ImageDataGenerator de keras.preprocessing importer l'image de keras.models importer Sequential de keras.layers importer Conv2D, MaxPooling2D de keras.layers importer Activation, Dropout, Flatten, Dense de keras importer le backend en tant que K de PIL importer l'image importer numpy en tant que np
Ensuite, nous devons définir notre modèle:
largeur_img, hauteur_img = 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_shape = (3, img_height, else) = (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))) modèle.add(Conv2D(64, (2, 2))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) modèle. 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', optimiseur='rmsprop', metrics=['accuracy'])
J'ai entraîné le modèle pour vous, mais si vous souhaitez entraîner le modèle vous-même, sur votre propre ensemble de données, j'ai joint le code d'entraînement. Sinon, vous pouvez télécharger le fichier HDF5 du modèle entraîné. En raison des restrictions de fichier Instructables, j'ai dû le renommer avec une extension ".txt". Pour l'utiliser, renommez le fichier en une extension ".h5", et chargez-le avec ce code:
model.load_weights("model_saved.h5")
Pour utiliser le réseau pour prédire l'espace-y d'une image, nous allons définir cette fonction:
def prédire (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]
Étape 4: traitement de l'image
Aperçu
Pour le traitement d'image, j'utilise la bibliothèque OpenCV (cv2). Tout d'abord, nous allons brouiller les bords de l'image, puis nous supprimerons l'arrière-plan en créant un masque et en modifiant les valeurs alpha des couleurs les plus sombres
Le code
C'est la partie de la fonction qui brouille les contours:
def processImage(img):
RADIUS = 20 # Ouvrir une image im = Image.open("pilbuffer.png") # Coller l'image sur fond blanc diam = 2 * RADIUS back = Image.new('RGB', (im.size[0] + diam, im.size[1] + diam), (0, 0, 0)) back.paste(im, (RADIUS, RADIUS)) # Créer un masque de flou 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) masque. paste(blck, (diam, diam)) # Flou l'image et colle le bord flou selon le masque blur = back.filter(ImageFilter. GaussianBlur(RADIUS / 2)) back.paste(blur, mask=mask) back.save(" transition.png") back.close()
Ensuite, nous allons définir les couleurs les plus sombres sur transparentes et enregistrer l'image temporairement:
#Créer un masque et un filtre remplacer le noir par alpha
image = cv2.imread("transition.png") hMin = 0 sMin = 0 vMin = 20 hMax = 180 sMax = 255 vMax = 255 inférieur = np.array([hMin, sMin, vMin]) supérieur = 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 avec open("buffer.png", "w+") comme fichier: pass cv2.imwrite("buffer.png", sortie)
Étape 5: Assemblage d'images dans une projection équirectangulaire
Aperçu
Cette fonction prend plusieurs images et les assemble dans un format pouvant être interprété par le package PhotoSphere.js, en utilisant la bibliothèque PIL (oreiller)
Le code
Tout d'abord, nous devons créer une image qui peut servir d'hôte pour les autres images:
nouveau = Image.nouveau("RVBA", (8000, 4000), couleur=(0, 0, 0))
Ensuite, nous devons parcourir le tableau d'images (qui ont toutes été redimensionnées à 1000x500) et les placer dans l'image:
h = 0
w = 0 i = 0 pour img dans img_arr: new.paste(img, (w, h), img) w += 1000 si w == 8000: h += 500 w = 0 i += 1
Maintenant, nous enveloppons simplement cela dans une fonction qui prend un tableau d'images comme argument et renvoie la nouvelle image:
def stitch_beta(img_arr):
new = Image.new("RGBA", (8000, 4000), color=(0, 0, 0)) h = 0 w = 0 i = 0 pour img dans img_arr: new.paste(img, (w, h), img) w += 1000 if w == 8000: h += 500 w = 0 i += 1 return new
Étape 6: le script Python complet
Il s'agit du script complet du réseau de neurones python, qui est enregistré sous net.py et importé dans le script principal:
# importation de bibliothèques
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("Aucun GPU trouvé ") de keras.preprocessing.image importer ImageDataGenerator de keras.preprocessing importer une image de keras.models importer Sequential de keras.layers importer Conv2D, MaxPooling2D de keras.layers importer Activation, Dropout, Flatten, Dense de keras importer le backend en tant que 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'_formats (): 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))) modèle. 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) renvoie le résultat [0][0]
Voici le fichier python principal, api.py:
demandes d'importation, sys, aléatoire, urllib.parse, cv2
de PIL importer Image, ImageFilter de 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"Current image count: {count }") i = 0 params = {"q": urllib.parse.quote(arg), "media_type": "image"} resultats = request.get("https://images-api.nasa.gov/search ", params=params) data = [result['href'] pour le résultat dans results.json()["collection"]["items"] print(len(data)) if num > len(data): num = len(données) pendant le compte
Étape 7: L'application Electron
Aperçu
Nous allons créer une application électronique simple qui positionne et charge simplement l'élément PhotoSphere. Les fichiers main.js et package.json proviennent directement du site Web d'Electron et le code HTML est une version légèrement modifiée du code HTML fourni sur le site Web de PhotoSphere. J'ai inclus les fichiers, mais j'ai tout renommé en.txt, car Instructables n'autorise pas ces types de fichiers. Pour utiliser les fichiers, renommez-les avec l'extension appropriée.
Le code
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
Étape 8: Exécution
Création de l'image équirectangulaire
Pour créer l'image, exécutez le script api.py dans l'invite de commande, avec son environnement virtuel activé:
api.py
Une fois l'exécution des scripts terminée, exécutez l'application electron en utilisant:
début npmVoila ! Votre planétarium est actif ! Merci d'avoir lu:)
Conseillé:
Text to Speech Cliquez sur un UChip alimenté par ARMbasic et d'autres SBC alimentés par ARMbasic : 3 étapes
Text to Speech Cliquez sur un UChip alimenté par ARMbasic et sur d'autres SBC alimentés par ARMbasic : Introduction : Bonne journée. Je m'appelle Tod. Je suis un professionnel de l'aérospatiale et de la défense qui est aussi un peu un geek dans l'âme.Inspiration: Originaire de l'ère des BBS commutés, des microcontrôleurs 8 bits, des ordinateurs personnels Kaypro/Commodore/Tandy/TI-994A, quand R
Onduleur DIY Grid Tied (n'alimente pas le réseau) Alternative UPS : 7 étapes (avec photos)
Onduleur DIY Grid Tied (n'alimente pas le réseau) UPS Alternative : il s'agit d'un post de suivi de mon autre Instructable sur la fabrication d'un onduleur Grid Tied qui ne réinjecte pas dans le réseau, car il est maintenant toujours possible de le faire dans certaines zones comme un projet de bricolage et certains endroits ne permettent pas d'y alimenter g
Est-ce une main ? (Caméra Raspberry Pi + Réseau de neurones) Partie 1/2 : 16 étapes (avec photos)
Est-ce une main ? (Caméra Raspberry Pi + Réseau de neurones) Partie 1/2 : Il y a quelques jours, je me suis blessé au poignet droit au gymnase. Ensuite, chaque fois que j'utilisais ma souris d'ordinateur, cela causait beaucoup de douleur à cause de l'angle raide du poignet. C'est à ce moment-là que cela m'a frappé " ne serait-ce pas génial si nous pouvions convertir n'importe quelle surface en un trackp
Contrôle du réseau matriciel LED avec Arduino Uno (face de robot alimenté par Arduino): 4 étapes (avec images)
Contrôle du tableau de matrices LED avec Arduino Uno (face de robot alimenté par Arduino) : cette instructable montre comment contrôler un tableau de matrices LED 8x8 à l'aide d'un Arduino Uno. Ce guide peut être utilisé pour créer un affichage simple (et relativement bon marché) pour vos propres projets. De cette façon, vous pouvez afficher des lettres, des chiffres ou des animations personnalisées
Fer à souder alimenté par batterie au lithium construit par l'utilisateur : 8 étapes (avec photos)
Fer à souder alimenté par batterie au lithium construit par l'utilisateur : récemment, j'ai trouvé une source excédentaire de pannes à souder alimentées par batterie Weller(r) BP1. Le soudage électronique nécessite parfois une visite de réparation sur site et les outils de terrain peuvent être un défi. Je construis souvent mes propres outils, trouvant des solutions sur étagère trop coûteuses