Python 3Dグラフを回転する。さらに各画像や動画で保存する方法「matplotlib×OpenCV」

 本記事では、matplotlibで作成した3Dグラフを回転して表示する方法と、それらを画像(png, jpg)や動画(mp4)で保存する雛形コードを載せました。

■本プログラムの仕様
三次元にプロットするデータは何でも構いませんが、ここでは下表のような4点としました。

  x y z
a 87 -14 20
b 85 -15 15
c 90 -16 19
d 86 -15 23

本コードを実行すると、下図左のような3次元散布図を作成します。そして、その視野角を10度ずつ変えて360度分の画像(.png)を保存します。

f:id:HK29:20210327141012p:plain

その後、作成した画像を連結して動画ファイル(.mp4)を作成します。

www.youtube.com

■本プログラム

#!/usr/bin/env python
# coding: utf-8

# In[8]:


# -*- coding: utf-8 -*-
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
plt.rcParams['font.size'] = 18


### データの読み込み
df = pd.read_csv('data.csv', index_col=0)
print(df)


# In[14]:


### グラフを作成する
# 画像オブジェクトの作成
fig = plt.figure(figsize=(12, 8))
ax = Axes3D(fig)
colors = ['r', 'y', 'b', 'g']


# 散布図を作成する
for (index, row), color in zip(df.iterrows(), colors):
    ax.scatter(row['x'], row['y'], row['z'],
               marker="o", label=index, c=color, s=90)

# 節点間を直線で結ぶ
df2 = df.copy()
rows = df.shape[0]
for i in range(rows):
    df_0 = df2.iloc[[0, rows-1]] # 0行目と最終行を抽出
    df2 = df2.drop(df2.index[[0, rows-1]]) # 0行目と最終行を削除
    df2 = pd.concat([df2, df_0]) # 行方向へ結合
    ax.plot(df2['x'], df2['y'], df2['z'], "-", color='k')

# グラフ表示オプション
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.legend()
plt.gca().invert_xaxis()

images = []
os.makedirs('pictures', exist_ok=True)
for angle in range(0, 360):
    ax.view_init(elev=15, azim=angle)
    
    # リアル表示する場合
    #plt.draw()
    #plt.pause(0.001)
  
    # 画像で保存する場合
    if angle % 10 == 0:
        fig.savefig("pictures/fig_" + str(angle) + ".png")


# In[21]:


# 動画作成する場合
import glob, re

filepath_list = glob.glob("pictures/*.png")
filepath_list = sorted(filepath_list, key=lambda x:int((re.search(r"[0-9]+", x)).group(0)))
filepath_list


# In[22]:


import cv2

img_list = []
for file_path in filepath_list:
    img = cv2.imread(file_path)
    height, width, layers = img.shape
    size = (width, height)
    img_list.append(img)

out = cv2.VideoWriter('movie.mp4',
                      cv2.VideoWriter_fourcc(*'MP4V'),
                      5.0, 
                      size)

for i in range(len(img_list)):
    out.write(img_list[i])
out.release()


# In[ ]:

以上

<広告>