BioErrorLog Tech Blog

試行錯誤の記録

実験 | 画像をtxtファイルから3Dグラフで可視化したい | Python

txtファイルとして出力した画像ファイルを、Pythonを用いて3Dプロットで可視化してみます。


はじめに

こんにちは、@bioerrorlogです。

先日、画像ファイルというものは所詮数値に過ぎないと改めて実感する出来事がありました。 画像解析ソフトFiji1で画像解析をしていると、面白いものを見つけたのです。 名前をつけて保存"Save as"の欄に、"Text Image"というファイル形式がありました。

画像ファイルの保存形式としてはJPEGやPNGなどを使っていましたが、"Text Image"形式とはどういうことでしょうか。 試してみると、0から255までの数値で各ピクセルが表現されたtxtファイルが出力されました(Fig. 1)。

Fig. 1 画像ファイルをtxtファイルとして出力。右のtxtデータは一部抜粋したもの。

ひとつ思いついたのは、このtxtファイルをもとにして、3Dグラフを描画したいということです。 画像ファイルが数値の連なりに過ぎない、ということを実感できるいい経験になると思います。

それではPythonを使ってやっていきます。

作業環境

Pythonバージョン:

$ python3 --version
Python 3.6.7


Ubuntu18.04.1 LTS を
Windows10の上に、VMwareによって構築した仮想環境で起動しています。
www.bioerrorlog.work


画像をtxtファイルから3Dグラフで可視化する

txtファイルの読み込み | pd.read_csv()

まずは、Fijiで出力したtxtファイル"peterpan_syndrome.txt"をpandasのread_csv()で読み込んで、行数と列数を出力してみます。 正しく読み込めていれば、画像のピクセル数"796 800"が表示されるはずです。

import pandas as pd

img_txt = pd.read_csv('peterpan_syndrome.txt',sep='\t',header=None)

row_count = img_txt.shape[0]
col_count = img_txt.shape[1]
print(col_count,row_count)
796 800#出力

予想通りの出力が得られ、正しく読み込めたのがわかります。

ちなみに、txtファイルだからといってread_table()で読み込もうとすると、

FutureWarning: read_table is deprecated, use read_csv instead, passing sep='\t'.
  img_txt = pd.read_table('peterpan_syndrome.txt',header=None)

read_table()は良くないからread_csv()でsep='\t'を使いなさいと怒られてしまいました。


XYの用意 | np.arange() / np.meshgrid()

私が描画しようとしている3Dグラフは、X軸とY軸がそれぞれ画像のwidthとHeightに相当し、Z軸が格子状にtxtファイルの値を示すものです。

そこでX軸とY軸を得るために、xyに1間隔でそれぞれのピクセル数を上限とした配列を与え、そこから格子列XYを生成します。

import numpy as np

x = np.arange(0, col_count, 1)
y = np.arange(0, row_count, 1)

X, Y = np.meshgrid(x, y)

これで、必要なXYを規定できました。

ここからは、3Dグラフにプロットしていきます。


3Dグラフプロット | mplot3d

ModuleNotFoundError: No module named 'tkinter'

しかし、3dグラフの描画に必要なモジュールのひとつmatplotlibをインポートをした際に、エラーを吐かれてしまいました。

from matplotlib import pyplot as plt
~
ModuleNotFoundError: No module named 'tkinter'

'tkinter'モジュールがない、と怒られてしまった訳です。 しかしここで、'tkinter'モジュールをインストールしようとしても、上手くいきませんでした。

解決策を探すと、同じ問題に当たった人を見つけました。

stackoverflow.com

これによると、'python3-tk'をインストールすればいいようです。

$ sudo apt install python3-tk

私もこれで、上記のエラーが解消されました。


mplot3dで3Dグラフを描画する

それでは、ついに3Dグラフを描画します。

3Dグラフの描画には、mplot3 Toolkitという便利なライブラリがあるようです。

https://matplotlib.org/tutorials/toolkits/mplot3d.html#sphx-glr-tutorials-toolkits-mplot3d-pymatplotlib.org

このmplot3 Toolkitドキュメントにしたがって、3Dグラフの描画処理を書いていきます。 今回は、きれいなグラフになりそうなFilled contour plots "contourf()"を用いて描画しました。

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = Axes3D(fig)

ax.contourf(X,Y,img_txt)

plt.show()

これで、上手くいくはずです。 ここまでのコードをすべてまとめます。

import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

img_txt = pd.read_csv('peterpan_syndrome.txt',sep='\t',header=None)
row_count = img_txt.shape[0]
col_count = img_txt.shape[1]

x = np.arange(0,col_count,1)
y = np.arange(0,row_count,1)

X, Y = np.meshgrid(x, y)

fig = plt.figure()
ax = Axes3D(fig)

ax.contourf(X,Y,img_txt)

plt.show()

これを実行すると、じつに美しい3Dプロットが得られました(Fig. 2)。

お見事です。

Fig. 2 画像のtxtファイルから得られた3Dプロット


おわりに

今回は、画像をtxtファイルで出力し、それをもとにPythonで3Dプロットを行いました(Fig. 3)。

Fig. 3 png画像からtxtファイル、そして3Dグラフへ変遷した

このように、私のような経験の浅いものでも簡単にプロットを行えるのが、Pythonのいいところでしょう。 今回使用したmplot3dも、公式のチュートリアルドキュメントが大変充実していました。

ところで、今回使ったFilled contour plots以外にも、mplot3には多くの描画形式がありました。 また、カラーなどの多くのオプションもあり、まだまだそれらも使いこなせていません。

Pythonでのデータ可視化というのも、いろいろ遊んで慣れていきたいものです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work


  1. Fiji: ImageJ, with "Batteries Included" - 生物系では広く利用されているオープンソースの画像解析ソフトです。