[PYTHON] J'ai fait une animation qui renvoie la pierre d'Othello avec POV-Ray

introduction

Ceci est le troisième article du Calendrier de l'Avent d'Othello. Je pense que c'est difficile à lire négligemment parce que ce ne sont que de longs articles, mais cette fois c'est un article léger alors n'hésitez pas à le lire (je pensais, mais ce sera plus long que je ne le pensais J'ai fait ...). Cependant, le quatrième article qui doit être publié le 22 décembre est très long, j'espère donc que vous développerez votre esprit d'ici là.

C'est le thème de cette époque, mais l'introduction est de faire une image animée qui renvoie la pierre d'Othello. Je suppose une animation à utiliser lors du retour d'une pierre avec l'application Othello.

Parce que c'est le Calendrier de l'Avent d'Othello, je pense que beaucoup de gens pensent que c'est juste un article POV-Ray qui n'a rien à voir avec Othello, juste en utilisant la pierre d'Othello comme sujet. Cependant, cet article est très essentiellement lié au fait d'être Othello. La raison sera écrite plus tard dans le texte.

Vieille histoire

Il y a environ 30 ans, j'ai appris la technique du lancer de rayons. J'étais ravi de voir une image rendue d'une sphère brillante apparaître dans un magazine (Internet n'était pas très répandu à l'époque). Le lancer de rayons est une technologie qui trace et simule littéralement les rayons pour rendre l'image d'un objet, mais à ce moment-là, il fallait des heures et des jours pour dessiner une seule sphère, et cela s'appelle la course tardive. Il semble qu'il y ait eu aussi un cas. Si vous êtes un oseller aujourd'hui, vous pouvez réaliser la quantité de calcul en convertissant le mystère de combien vous pouvez augmenter le nombre de livres avec de telles ressources de calcul. Bien sûr, je n'avais pas l'environnement pour le faire à l'époque, mais cette technologie est restée dans le coin de ma tête.

Une trentaine d'années se sont écoulées et l'auteur, qui a dû faire une animation pour rendre la pierre d'Othello par hasard, s'est souvenu de cette technologie. Cette technologie est-elle toujours présente aujourd'hui? Lorsque j'ai recherché en utilisant une civilisation appelée Google, qui n'était pas disponible à l'époque, j'ai trouvé qu'il y avait un logiciel de Ray Tracing appelé POV-Ray, alors j'ai décidé de l'utiliser.

Tel est le contexte de cet article. Comme vous pouvez le voir à partir de cet arrière-plan, l'auteur n'est pas familier avec POV-Ray, donc j'espère que vous pouvez le considérer comme un article "essayé".

Sujet principal

Dessinez la pierre d'Othello avec POV-Ray

Commençons par dessiner des pierres d'Othello avec POV-Ray. Tout d'abord, je voudrais faire une image d'un carré d'un carré d'Othello. Modifions peu à peu l'angle de l'état où la pierre est placée dans ce carré et retournons-le. Je vais changer l'angle de 30 degrés. Si l'image de départ est la 0ème image, elle sera retournée à la 6ème image. Je voudrais faire un total de 13 cadres d'images, jusqu'au point où il revient à l'original dans le 12ème cadre.

En gros, vous pouvez dessiner une pierre en définissant la caméra (point de vue), en définissant la source de lumière, en définissant la surface d'arrière-plan, en définissant la pierre et en exécutant le rendu.

#declare discRadius = 1.75;   //Rayon de pierre
#declare discThickness = 0.7; //Épaisseur de pierre
#declare boxSize = 4.25;      //La taille d'un côté de la masse
#declare cameraDistance = 25; //Distance de la caméra à l'origine
#declare deg = 60;            //Angle de rotation de la pierre

//Les paramètres de la caméra
camera{ 
	location <0, 0, cameraDistance>  //Position de la caméra
	look_at <0, 0, 0>                //La caméra fait face à l'origine
	angle degrees(atan2(boxSize / 2, cameraDistance)) * 2  //Angle de vue
	right <1, 0, 0>  //Le système de coordonnées est le système de gauche, le rapport hauteur / largeur est 1:1
	up <0, 1, 0>
}

//Réglage de la source lumineuse
light_source { 
	<-5, 5, 50>    //Position de la source lumineuse
	color rgb <1.4, 1.4, 1.4>  //Couleur de la source lumineuse
}

//Définition du plan d'arrière-plan
object { 
	plane {<0, 0, 1>, -discThickness / 2}  //Distance du vecteur normal du plan et de l'origine
	texture { pigment { rgb <0, 1, 0> } }  //Couleur de l'avion
}

//Définition de la pierre(Côté blanc)
object { 
	cylinder {<0, 0, 0>, <0, 0, discThickness / 2>, discRadius} //Centre du haut et du bas cylindriques
	texture { pigment { rgb <1, 1, 1> } }  //Couleur
	rotate y*deg  //Faire pivoter les degrés autour de l'axe y
	rotate z*15   //Rotation de 15 degrés autour de l'axe z(Fixé)
	translate <0, 0, discRadius * abs(sin(radians(deg)))>  //Mouvement parallèle dans la direction de l'axe z
}
//Définition de la pierre(Côté noir)L'explication est la même que le côté blanc, donc il est omis
object { 
	cylinder {<0, 0, 0>, <0, 0, -discThickness / 2>, discRadius} 
	texture { pigment { rgb <0, 0, 0> } }    
	rotate y*deg
	rotate z*15 
	translate <0, 0, discRadius * abs(sin(radians(deg)))> 
}  

Depuis que j'ai ajouté un commentaire, je pense que vous pouvez comprendre le sens général, mais je vais compléter la partie où le sens est difficile à comprendre.

Le premier declare est la définition d'une constante. Différentes longueurs sont définies, mais cette fois, une unité dans l'espace de POV-Ray équivaut à 1 cm. Les pierres d'Othello d'un diamètre de 3,5 cm et d'un rayon de 1,75 cm ont la taille du couvercle d'une bouteille de lait, ce que tous les Ocellers connaissent.

La définition de la caméra «angle» est l'angle du champ de vision, et si vous essayez de faire de l'image un carré, il devrait être $ \ tan \ theta / 2 = (4.25 / 2) / 25 $, alors calculez-le en arrière. C'était. De plus, «droit» et «haut» semblent définir le rapport hauteur / largeur et le système de coordonnées de l'image, cette fois le rapport hauteur / largeur est de 1: 1 (carré) et les coordonnées sont gauches (probablement).

À l'origine, la couleur de la source lumineuse, RVB, semble être spécifiée de 0,0 à 1,0, mais l'image finale était sombre, donc lorsque j'ai essayé de spécifier une valeur de 1 ou plus, elle est devenue plus claire (les détails sont les suivants). Ce n'est pas bien compris ···)

La surface d'arrière-plan utilise la couleur primaire verte pour diverses raisons décrites plus loin. De plus, comme je voulais placer le centre de la pierre sur le plan XY, j'ai utilisé la surface qui a été déplacée dans la direction négative dans la direction Z de la moitié de l'épaisseur de la pierre comme surface de fond.

Tout d'abord, la pierre est dessinée en rotation de 60 degrés. J'ai senti que l'axe de rotation était trop droit s'il s'agissait de l'axe y lui-même, j'ai donc incliné l'axe de rotation 15 degrés plus tard. Si vous le faites simplement pivoter tel quel, il s'enfoncera dans la surface d'arrière-plan, il sera donc déplacé dans la direction positive de l'axe z de $ \ sin 60 ^ \ circ $ fois le rayon. (Il flottera légèrement de la planche)

Pour une grammaire détaillée, etc., l'Université d'Oita a créé une référence japonaise, veuillez donc vous y référer. Se il vous plaît se référer.

Maintenant, la définition est complète. Après cela, définissons l'option POV-Ray sur 288x288, AA 0.3 (taille de l'image et paramètres d'anti-crénelage), et rendons la ligne de commande comme + FN (sortie de fichier PNG). disc03.png

J'ai pu le dessiner comme ça.

Créer des images pour tous les cadres

Tout ce que vous avez à faire est de changer la partie #declare deg = 60; et de l'exécuter (en fait, lorsque vous l'avez fait pour la première fois), mais il y avait en fait une meilleure façon.

Si vous souhaitez créer une image continue à utiliser pour l'animation, ajoutez + KFF13 à l'endroit que vous avez spécifié + FN plus tôt, et 13 images seront rendues en continu. Ensuite, une variable appelée «horloge» est définie sur une valeur obtenue en divisant la plage de 0,0 à 1,0 en 13 parties égales (la première feuille vaut 0,0 et la 13e feuille est 1,0). En d'autres termes, où la variable d'angle a été définie

#declare deg = clock * 360;

Si tel est le cas, il créera 13 fichiers image à la fois de 0 degrés à 360 degrés par incréments de 30 degrés (bien sûr, les images de 0 degré et 360 degrés seront les mêmes).

image.png

C'est pratique!

Rendre la couleur d'arrière-plan transparente

À propos, le thème était cette fois-ci de créer une image animée d'une pierre à utiliser dans l'application Othello. Lorsque vous l'utilisez avec l'application Othello, le tableau lui-même peut être coloré pour diverses raisons, je voudrais donc garder l'arrière-plan de l'image de la pierre transparent. Vous pouvez ajouter des canaux alpha (transparence) aux fichiers PNG. La partie où le vert est visible dans l'image précédente est la partie qui devrait être transparente, je voudrais donc l'utiliser pour trouver et définir la valeur alpha. Pour faciliter ce calcul, j'ai rendu le fond vert. C'est une méthode comme la composition de la clé chroma. Cette fois, il y a une partie d'ombre, donc je veux régler la transparence dans le bon sens.

Puisque l'image à compléter est une image de la pierre d'Othello et de son ombre, elle est complètement en échelle de gris, le RVB de chaque pixel a tous la même valeur (appelons cette valeur V), et une valeur alpha $ \ alpha $ est définie. Sera. S'il y a une couleur primaire verte à l'arrière-plan de cette image, cela devrait être l'image précédente, donc si les valeurs RVB de l'image originale sont respectivement R, V, B

B = V * \alpha / 255\\\\ G = V * \alpha / 255 + 255 * (255 - \alpha) / 255

Devrait tenir. Résolvez ceci pour trouver les valeurs de $ \ alpha $ et V. Je l'ai écrit en Python.

import cv2
import matplotlib.pyplot as plt
import numpy as np

for i in range(1, 14):
    #Lire le fichier original
    file = 'disc{0}.png'.format(format(i, '02'))
    img = cv2.imread(file)
    #Pour les images converties
    convert_img = np.zeros((img.shape[0], img.shape[1], 4), dtype='uint8') 
    #Valeurs B et G dans l'image d'origine(Puisqu'il a été lu par OpenCV, il est dans l'ordre de BGR.)
    blue = img[:, :, 0]
    green = img[:, :, 1]
    alpha = 255 - (green - blue)
    alpha[green <= blue] = 255
    #La partie où le vert est complètement visible dans l'image d'origine n'est pas nécessairement G=Comme ce n'est pas 255, la partie qui était presque verte est G=Considérez 255.
    alpha[alpha < 20] = 0
    #Définir respectivement BGRA de l'image convertie
    #La partie longue de la seconde moitié de B empêche la division zéro(Référence https://www.it-swarm.net/ja/python/Comment retourner 0 en divisant par zéro/1049445598/)
    convert_img[:, :, 0] = blue * np.divide(255 * np.ones(alpha.shape, dtype='float'), 
          alpha.astype(np.float), 
          out=np.zeros_like(alpha, dtype='float'), 
          where=alpha!=0)
    convert_img[:, :, 1] = convert_img[:, :, 0]
    convert_img[:, :, 2] = convert_img[:, :, 0]
    convert_img[:, :, 3] = alpha
    #Sortie de fichier
    cv2.imwrite('cvt' + file, convert_img)

Cette méthode pouvait être utilisée facilement car l'objet était une pierre d'Othello et il était seulement nécessaire de faire une image de R = G = B en deux couleurs noir et blanc. Si c'est une image qui renvoie un morceau de shogi, cela ne devrait pas être si facile à bien des égards. Vous voyez, c'est un article pour le calendrier de l'Avent d'Othello, qui consiste essentiellement à être Othello! (De force)

J'ai collé l'image convertie dans Keynote sur mon Mac et dessiné un carré rouge en arrière-plan. C'est un peu difficile à voir, mais vous pouvez voir que les ombres sont également transparentes. image.png

Cela a également été tourné avec une instruction Python for, donc 13 images sont créées. image.png

Créer un fichier d'animation

Si vous pouvez le faire jusqu'à présent, vous pouvez animer comme un dessin animé para-para en affichant ces images en continu côté application.

Cependant, comme c'était un gros problème, j'ai pensé qu'il pouvait être affiché sur le navigateur, et après avoir étudié diverses choses, j'ai trouvé qu'il existe un format de fichier appelé PNG animé. C'est une version PNG d'un GIF animé. Cependant, il peut ne pas s'afficher correctement sur les navigateurs IE, Edge et plus anciens.

Quant à savoir comment le créer, sur Mac, c'est une application avec un nom simple [Vous convertissez en image d'anime](https://apps.apple.com/jp/app/Vous convertissez en image d'anime / id1127676902? Mt = 12) Il semble que vous puissiez y arriver. Même dans le cas de Windows, si vous google avec "Animation PNG", diverses applications de création sortiront.

"Kimi à convertir en image d'anime" peut créer un fichier d'animation pour les timbres LINE et un fichier d'animation pour les pages Web, mais cette fois je choisirai ce dernier. Vous pouvez facilement créer un fichier PNG animé en collant les 13 fichiers créés précédemment et en spécifiant la fréquence d'images et le nombre de boucles.

J'ai donc créé un PNG animé, je l'ai collé et publié l'article une fois, mais pour une raison quelconque, il semble que le PNG animé ne s'anime pas bien dans l'article publié de Qiita (je pouvais le voir au moment de la rédaction ... ). Je ne pouvais pas m'en empêcher, alors je l'ai rapidement transformé en GIF animé.

Voici le produit fini.

board_animation.gif Oh, j'ai fait une erreur dans le fichier à coller. C'est en fait ça. disc_animation.gif Le voyez-vous bien animé?

en conclusion

C'est la fin de cet article, mais j'ai l'impression qu'il y a probablement des gens qui en ont marre. Si vous êtes intéressé, j'ai mis le code source sur GitHub, alors veuillez vous y référer.

Rendez-vous dans l'article du 22 décembre!

Article de référence

Recommended Posts

J'ai fait une animation qui renvoie la pierre d'Othello avec POV-Ray
J'ai fait Othello pour enseigner Python3 aux enfants (4)
J'ai fait Othello pour enseigner Python3 aux enfants (2)
J'ai fait Othello pour enseigner Python3 aux enfants (5)
J'ai fait Othello pour enseigner Python3 aux enfants (3)
J'ai fait Othello pour enseigner Python3 aux enfants (1)
Je veux être OREMO avec setParam!
J'ai essayé de détecter un objet avec M2Det!
J'ai créé un installateur Ansible
Je veux convertir une image en WebP avec sucette
J'ai essayé de faire d'Othello pour enseigner Python3 aux enfants (6) Final
J'ai essayé d'implémenter le perceptron artificiel avec python
J'ai essayé de créer une application OCR avec PySimpleGUI
Je l'ai fait avec le traitement, "Le gars d'Othello live de Sakanaction".
J'ai essayé de trouver la classe alternative avec tensorflow
[IOS] Animation GIF avec Pythonista3. J'en étais accro.
J'ai créé une bibliothèque d'opérations matricielles à N dimensions Matft avec Swift
J'ai créé un package pour filtrer les séries chronologiques avec python
J'ai fait un blackjack avec du python!
J'ai créé un appareil IoT pour acquérir naturellement une pensée positive
J'ai créé COVID19_simulator avec JupyterLab
J'ai créé Word2Vec avec Pytorch
J'ai fait un blackjack avec Python.
Je voulais calculer un tableau avec la méthode des subs de Sympy
Othello fait avec python (comme GUI)
J'ai créé wordcloud avec Python.
J'ai essayé de créer un article dans Wiki.js avec SQL Alchemy
J'ai créé une bibliothèque qui lit facilement les fichiers de configuration avec Python
J'ai créé un serveur Web avec Razpai pour regarder des anime
J'obtiens une erreur en essayant d'installer maec 4.0.1.0 avec pip
Je souhaite utiliser une bibliothèque externe avec IBM Cloud Functions
[Introduction à Matplotlib] Axes Animation 3D: J'ai joué avec des figurines 3D Lisaju ♬
J'ai essayé de créer une fonction de similitude d'image avec Python + OpenCV
J'ai fait une loterie avec Python.
J'ai envoyé un SMS avec Python
J'ai fait un kit de démarrage angulaire
Je veux faire ○○ avec les Pandas
Je veux déboguer avec Python
J'ai créé un démon avec Python
J'ai fait un package npm pour obtenir l'ID de la carte IC avec Raspberry Pi et PaSoRi
J'ai créé un outil pour parcourir automatiquement plusieurs sites avec Selenium (Python)
J'ai fait une IA pour juger si c'est de l'alcool ou non!
J'ai créé un capteur d'ouverture / fermeture (lien Twitter) avec TWE-Lite-2525A
[Django] a créé un champ pour saisir des dates avec des nombres à 4 chiffres
Maintenance de l'environnement réalisée avec Docker (je souhaite post-traiter GrADS en Python
J'ai créé un outil pour convertir Jupyter py en ipynb avec VS Code
Je souhaite créer un profil utilisateur Ubuntu Chrome avec Colab uniquement
J'ai créé la partie APL avec la compétence Alexa "Conversion des termes de l'industrie"
J'obtiens une erreur avec les pandas d'importation.
Je veux détecter des objets avec OpenCV
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé de commencer avec Hy
J'ai fait un compteur de caractères avec Python
Je veux écrire un blog avec Jupyter Notebook
J'ai créé une application d'analyse de fréquence en ligne
J'ai créé un module alternatif pour les japandas.
Je voulais résoudre ABC160 avec Python
Je veux installer Python avec PythonAnywhere