[PYTHON] I made an animation to return Othello stones with POV-Ray

Introduction

This is the third article for Othello Advent Calendar. I think it's hard to read because it's just a long article, but this time it's a light article so please feel free to read it (I thought, but it will be longer than I thought. I did ...). However, the fourth article scheduled to be published on December 22nd is very long, so I hope that you will develop your spirit by then.

This is the theme of this time, but the introduction is to make an animation image that returns the stone of Othello. I'm assuming an animation to use when returning a stone with the Othello app.

I think many people thought that it was just a POV-Ray article that had nothing to do with Othello, just because it was an Othello Advent Calendar and the subject matter was Othello's stone. However, this article is very essentially related to being Othello. The reason will be written later in the text.

Old tale

About 30 years back in time, I learned about the technique of ray tracing. It was exciting to see a rendered image of a glossy sphere in a magazine (the internet wasn't widespread at the time). Ray tracing is a technology that renders an image of an object by literally tracking and simulating light rays, but at that time it took hours and days just to draw one sphere, and it is called ray tracing etc. It seems that there was also a case. If you are an oseller today, you may realize the amount of calculation by converting the mystery of how much you can increase the number of books with such computational resources. Of course, I didn't have the environment to do it at the time, but this technology remained in the corner of my head.

About 30 years have passed, and the author, who was forced to make an animation to return Othello stones by chance, remembered this technology. Is that technology still present today? When I searched using a civilization called Google, which was not available at that time, I found that there was a ray tracing software called POV-Ray, so I decided to use it.

That is the background of this article. As you can see from this background, I am not familiar with POV-Ray, so I hope you can think of it as a "tried" article.

Main subject

Draw Othello stones with POV-Ray

Let's start by drawing Othello stones using POV-Ray. First of all, I would like to make an image of a square for one square of Othello. Let's change the angle little by little from the state where the stone is placed in this one square and turn it over. I will change the angle by 30 degrees. If the starting frame is the 0th frame, it will be turned over at the 6th frame. I would like to make a total of 13 frames of images, up to the point where the image returns to the original in the 12th frame.

Roughly speaking, you can draw a stone by setting the camera (viewpoint), setting the light source, defining the background surface, defining the stone, and performing rendering.

#declare discRadius = 1.75;   //Stone radius
#declare discThickness = 0.7; //Stone thickness
#declare boxSize = 4.25;      //The size of one side of the square
#declare cameraDistance = 25; //Distance from camera to origin
#declare deg = 60;            //Stone rotation angle

//Camera settings
camera{ 
	location <0, 0, cameraDistance>  //Camera position
	look_at <0, 0, 0>                //The camera is facing the origin
	angle degrees(atan2(boxSize / 2, cameraDistance)) * 2  //Viewing angle
	right <1, 0, 0>  //The coordinate system is the left-handed system, and the aspect ratio is 1.:1
	up <0, 1, 0>
}

//Light source settings
light_source { 
	<-5, 5, 50>    //Light source position
	color rgb <1.4, 1.4, 1.4>  //Light source color
}

//Background plane definition
object { 
	plane {<0, 0, 1>, -discThickness / 2}  //Plane normal vector and distance from origin
	texture { pigment { rgb <0, 1, 0> } }  //Plane color
}

//Definition of stone(White side)
object { 
	cylinder {<0, 0, 0>, <0, 0, discThickness / 2>, discRadius} //Center of cylindrical top and bottom
	texture { pigment { rgb <1, 1, 1> } }  //color
	rotate y*deg  //Rotate deg degrees around the y-axis
	rotate z*15   //Rotate 15 degrees around the z-axis(Fixed)
	translate <0, 0, discRadius * abs(sin(radians(deg)))>  //Translation in the z-axis direction
}
//Definition of stone(Black side)The explanation is the same as the white side, so it is omitted
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)))> 
}  

Since I added a comment, I think that you can understand the general meaning, but I will supplement the part where the meaning is difficult to understand.

The first declare is the definition of a constant. Various lengths are defined, but this time, one unit in the space of POV-Ray is equivalent to 1 cm. The diameter of the Othello stone = 3.5 cm and the radius = 1.75 cm, which every Oceller knows, is the size of the lid of a milk bottle.

The camera definition ʻangleis the angle of the field of view, and if you try to make the image the size of one square, it should be $ \ tan \ theta / 2 = (4.25 / 2) / 25 $, so calculate it back. It was. Also,right and ʻup seem to define the aspect ratio and coordinate system of the image, this time the aspect ratio is 1: 1 (square) and the coordinates are left-handed (probably).

Originally, the light source color rgb seems to be specified by 0.0 to 1.0, but the finished image was dark, so when I tried specifying a value of 1 or more, it became brighter, so I did this (details are It is not well understood···)

For the background surface, the primary color green is used due to various circumstances described later. Also, since I wanted to place the center of the stone on the XY plane, I used the surface that was moved in the negative direction in the Z direction by half the thickness of the stone as the background surface.

First of all, the stone is drawn rotated by 60 degrees. I felt that the axis of rotation was too straight if it was the y-axis itself, so I tilted the axis of rotation 15 degrees later. If you just rotate it as it is, it will sink into the background surface, so it is moved in the positive direction of the z-axis by $ \ sin 60 ^ \ circ $ times the radius. (It will float slightly from the board)

For detailed grammar, etc., Oita University has created a Japanese Reference, so please refer to that. Please refer.

Now, the definition is complete. After that, let's render the POV-Ray option as 288x288, AA 0.3 (image size and antialiasing settings) and the command line as + FN (PNG file output). disc03.png

I was able to draw it like that.

Create images for all frames

All you have to do is change the # declare deg = 60; part and execute it (in fact, when you first made it), but there was actually a better way.

If you want to create a continuous image to be used for animation, add + KFF13 to the place you specified + FN earlier, and 13 images will be rendered continuously. Then, the variable clock is set to a value obtained by dividing the range of 0.0 to 1.0 into 13 equal parts (the first sheet is 0.0 and the 13th sheet is 1.0). In other words, where the angle variable was defined

#declare deg = clock * 360;

If so, it will create 13 image files at once from 0 degrees to 360 degrees in 30 degree increments (of course, 0 degree and 360 degree images will be the same).

image.png

It's convenient!

Make the background color transparent

By the way, the theme this time was to create an animated image of a stone for use in the Othello app. When using it with the Othello app, the board itself may be colored for various reasons, so I would like to keep the background of the stone image transparent. You can add an alpha channel (transparency) to PNG files. The part where green is visible in the previous image is the part that should be transparent, so I would like to use this to find and set the alpha value. To make this calculation easier, I used the primary color green as the background. It's a method like chroma key composition. This time there is a shadow part, so I want to set the transparency in a good way.

Since the image to be completed is an image of Othello stone and its shadow, it is completely grayscale, RGB of each pixel is all the same value (let's call this value V), and some alpha value $ \ alpha $ is set. Will be. If there is a primary color green in the background of this image, it should be the previous image, so if the RGB values of the original image are R, G, B respectively

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

Should hold. Solve this to find the values of $ \ alpha $ and V. I wrote it in Python.

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

for i in range(1, 14):
    #Read the original file
    file = 'disc{0}.png'.format(format(i, '02'))
    img = cv2.imread(file)
    #For converted images
    convert_img = np.zeros((img.shape[0], img.shape[1], 4), dtype='uint8') 
    #B and G values in the original image(Since it was read by OpenCV, it is in the order of BGR)
    blue = img[:, :, 0]
    green = img[:, :, 1]
    alpha = 255 - (green - blue)
    alpha[green <= blue] = 255
    #The part where green is completely visible in the original image is not necessarily G=Since it is not 255, the part that was almost green is G=Consider 255.
    alpha[alpha < 20] = 0
    #Set BGRA of converted image respectively
    #The long part of the second half of B prevents division by zero(Reference https://www.it-swarm.net/ja/python/How to return 0 by division by zero/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
    #File output
    cv2.imwrite('cvt' + file, convert_img)

This method could be used easily because the object was Othello stone and it was only necessary to make an image of R = G = B in two black and white colors. If it is an image that returns a piece of shogi, it should not be so easy in many ways. You see, it's an article for the Othello Advent Calendar, which involves being essentially Othello! (Forcibly)

I pasted the converted image into Keynote on my Mac and drew a red square on the background. It's a little hard to see, but you can see that the shadows are also transparent. image.png

This was also turned with a Python for statement, so 13 images are created. image.png

Create an animation file

If you can do so far, you can animate like a flip book by displaying these images continuously on the application side.

However, since it was a big deal, I thought that it could be displayed on the browser, and after investigating various things, I found that there is a file format called animated PNG. It's a PNG version of an animated GIF. However, it may not display well in IE, Edge or older browsers.

As for how to create it, on Mac, it is an app with a straight name [You convert to anime image](https://apps.apple.com/jp/app/You convert to anime image / id1127676902? Mt = 12) It seems that you can make it. Even in the case of Windows, if you google with "Animation PNG", various creation apps will come out.

"Kimi to convert to anime image" can create an animation file for LINE stamps and an animation file for web pages, but this time I will choose the latter. You can easily create an animated PNG file by pasting the 13 files created earlier and specifying the frame rate and the number of loops.

So, I made an animated PNG and pasted it and published the article once, but for some reason it seems that the animated PNG does not animate well in the published article of Qiita (I could see it at the time of drafting ... ). I couldn't help it, so I hurriedly remade it into an animated GIF.

Here is the finished product.

board_animation.gif Oh, I made a mistake in the file to paste. This is actually this. disc_animation.gif Do you see it animated properly?

in conclusion

This is the end of this article, but I feel that there are probably some people who are sick of it. If you are interested, I have put the source code on GitHub, so please refer to it.

See you in the article on December 22nd!

Reference article

-How to make animation with POV-Ray

Recommended Posts

I made an animation to return Othello stones with POV-Ray
I made Othello to teach Python3 to children (4)
I made Othello to teach Python3 to children (2)
I made Othello to teach Python3 to children (5)
I made Othello to teach Python3 to children (3)
I made Othello to teach Python3 to children (1)
I want to be an OREMO with setParam!
I tried to detect an object with M2Det!
I made an Ansible-installer
I want to convert an image to WebP with lollipop
I made Othello to teach Python3 to children (6) Final episode
I tried to implement an artificial perceptron with python
I tried to make an OCR application with PySimpleGUI
I made an action to automatically format python code
I made it with processing, "Sakanaction's live Othello guy".
I tried to find an alternating series with tensorflow
[IOS] GIF animation with Pythonista3. I was addicted to it.
I made an N-dimensional matrix operation library Matft with Swift
I made a package to filter time series with python
I made blackjack with python!
I made an IoT device to naturally acquire positive thinking
I made COVID19_simulator with JupyterLab
I made Word2Vec with Pytorch
I made blackjack with Python.
I wanted to calculate an array with Sympy's subs method
Othello made with python (GUI-like)
I made wordcloud with Python.
I tried to create an article in Wiki.js with SQLAlchemy
I made a library to easily read config files with Python
I made a web server with Raspberry Pi to watch anime
I get an error when trying to install maec 4.0.1.0 with pip
I want to use an external library with IBM Cloud Functions
[Introduction to Matplotlib] Axes 3D animation: I played with 3D Lissajous figures ♬
I tried to make an image similarity function with Python + OpenCV
I made a fortune with Python.
I sent an SMS with Python
I made an Angular starter kit
I want to do ○○ with Pandas
I want to debug with Python
I made a daemon with Python
I made an npm package to get the ID of the IC card with Raspberry Pi and PaSoRi
I made a tool to automatically browse multiple sites with Selenium (Python)
I made an AI to judge whether it is alcohol or not!
I tried to make an open / close sensor (Twitter cooperation) with TWE-Lite-2525A
[Django] I made a field to enter the date with 4 digit numbers
I tried to discriminate a 6-digit number with a number discrimination application made with python
Environment maintenance made with Docker (I want to post-process GrADS in Python
I made a tool to convert Jupyter py to ipynb with VS Code
I want to create an Ubuntu chrome User Profile with Colab only
I made an APL part with the Alexa skill "Industry Terminology Conversion"
I get an error with import pandas.
I want to detect objects with OpenCV
I tried to implement Autoencoder with TensorFlow
I tried to get started with Hy
I made a character counter with Python
I want to blog with Jupyter Notebook
I made an online frequency analysis app
I made an alternative module for japandas.DataReader
I wanted to solve ABC160 with Python
I want to pip install with PythonAnywhere
When I get an error with PyInstaller