あるセミナーで、うちのチームの親分が『コンピュータが見ている画像は人が見ている画像とは異なって解釈して特徴をとらえている。』と説明していたのだけど、イマイチ参加者の方々がピンと来ていないような感じだったけどオイラ的には『ビビビ!!!』って感電してメチャわかりやすい説明やん!!!って思った。
コンピュータにとっての画像とは、色を数値化して、その色が画像(X,Y軸)上のどこにあるか?っていうただの数値の配列でしかありません。なのでコンピュータは、こんな感じにでも特徴をとらえてるんじゃね?っていうサンプルとして、画像データを分解して、どの色がどのように含まれているかRGB色を mplot3d の scatterplot で3D散布図として描いてみました。
処理概要
画像ファイルをnumpyの配列に入れて、1pix毎の情報を[R,G,B]のリストとして得て、ループ処理で1つ1つ取得した色で、X 軸に R、Y 軸に G、Z 軸に B として、プロットしていく。
入力画像
画像処理の世界ではお決まりのレナさん。
ちなみに、この画像が載っていた1972年11月号の「PLAYBOY」誌は 7,161,561部も販売され(発行部数ではなく、実売部数)いまだ破られていない最多販売部数として記録されているそうですよ。すげ~
http://www.lenna.org/ ←詳しくはこちらを参照
ソースコード
画像は512 × 512 ピクセル = 262,144 回のループ処理で3Dグラフにマッピングしているため激しく遅いです。
画像を出力するまでマックスくん環境のPC( Corei7-7700HQ/GeForce GTX 1060)で15分くらいかかります。GPUは使っていません。出力されたグラフも回転させてさまざまな角度から見ることができますが遅くて気が遠くなります。
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import datetime # 遅いから不安なので時間を出してみた。
# today()メソッドで現在日付・時刻のdatetime型データの変数を取得
d = datetime.datetime.today()
print (d.strftime("%x %X") )
# 画像→配列変換
img_path = 'lena.jpg' # レナさん画像
img = Image.open(img_path)
imgArray = np.asarray(img) # PILToNumpy
# 画像サイズ取得
maxcol, maxrow = img.size # get img size
# 画像サイズの出力この回数ループ処理が走る。
print ('input img size : ',str(maxcol) ,'*',str(maxrow),'=', str(maxcol * maxrow))
# numpy配列を書き換え可否の設定。
imgArray.flags.writeable = False # 今回の処理ではどちらでもよいが特に書き換える必要がないのでFalseにした。
# Figureのインスタンスを生成
fig = plt.figure()
# Axes3D のインスタンスを生成(描画領域の設定)
ax = fig.add_subplot(111, projection='3d') #111 は、1x1グリッド、第1のサブプロットを意味しています。
# プロットするRGBカラーの初期化
RGB_R = 0.0
RGB_G = 0.0
RGB_B = 0.0
# 画像サイズぶん回すよ!
for i in range(maxrow):
for j in range(maxcol):
# 1つ1つピクセルのRGB色を分解して取得してます。
X = imgArray[i,j][0] #R
Y = imgArray[i,j][1] #G
Z = imgArray[i,j][2] #B
# プロットする色を出すために計算してます。
RGB_R = X*1.0/255.0
RGB_G = Y*1.0/255.0
RGB_B = Z*1.0/255.0
# プロットする色を作ってます。
RGB_color = (RGB_R,RGB_G,RGB_B)
# XYZの位置にプロットする。 c は色、s はプロットした点のサイズ。
ax.scatter(X, Y, Z, c=RGB_color ,s=1 )
# XYZ軸のラベルをRGBにする。
ax.set_xlabel('R')
ax.set_ylabel('G')
ax.set_zlabel('B')
# today()メソッドで現在日付・時刻のdatetime型データの変数を取得
d = datetime.datetime.today()
print (d.strftime("%x %X") )
# 3Dプロットした画像の出力する。実はこれも時間かかる。激しく重い処理のようだ。
plt.savefig("mplot3d_scatterplot.png")
# today()メソッドで現在日付・時刻のdatetime型データの変数を取得
d = datetime.datetime.today()
print (d.strftime("%x %X") )
# 3Dプロットした画像を画面に出力する。実はこれも時間かかる。激しく重い処理のようだ。
plt.show()
出力結果
こんな感じ。
レナさん画像はこのような色の配置パターンとなっています。
もしかしたらコンピュータは、この色の配置で女性らしさというパターンを解釈して特徴点としてとらえいるかもしれません?
参考資料
http://effbot.org/zone/pil-changes-116.htm
https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#scatter-plots