よちよちpython

独習 python/Qpython/Pydroid3/termux

【Numpy】np.stackを使った2次元配列の3次元方向への結合と画像生成の実験

前回 の続き。



前回と同じことをしているが、全然簡単にできた。

使用環境

  • Python3.8
  • Jupyter Notebook



前回は、3つの二次元の配列をそれぞれRGB(赤・緑・青)の配列と見立てて、それらを二次元のまま結合させて三次元画像に変換する実験をした。

狙い通りの正しい画像として表示するためには、配列の結合の仕方や三次元配列の形状変換、座標変換などを上手くやらなければならなかった。

が、今回分かったのは、そんなことしなくともNumpyのnp.stack([配列1, 配列2,・・・], axis=座標軸) を使い、二次元配列を三次元方向(axis=2)に結合するだけで簡単に出来てしまう。



np.stack([配列1, 配列2, ・・・], axis=2 )で2次元配列を3次元方向に結合


手順

RGBの色チャンネルに見立てた二次元配列を3つ作る。
2つは要素の数値が255で埋められたもの。もうひとつは全て0。
各配列は、30行40列とする。
それら3つの二次元配列を、np.stack()で三次元方向に結合する。
出来た三次元配列を画像と見立て、matplotlibのplt.imshow()で表示させる。
RGBのうち、RとGは全て255、Bは全て0の配列だったので、表示される画像が黄色になれば実験成功。

import numpy as np
import matplotlib.pyplot as plt
# 30行40列の二次元配列を生成
red = np.arange(1200).reshape(30,40)
# 配列表示
red
array([[   0,    1,    2, ...,   37,   38,   39],
       [  40,   41,   42, ...,   77,   78,   79],
       [  80,   81,   82, ...,  117,  118,  119],
       ...,
       [1080, 1081, 1082, ..., 1117, 1118, 1119],
       [1120, 1121, 1122, ..., 1157, 1158, 1159],
       [1160, 1161, 1162, ..., 1197, 1198, 1199]])
# 生成した二次元配列の要素を全て255に置換
a[:,:] = 255

a
array([[255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       ...,
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255]])
# 配列をコピー
green = red.copy()

green
array([[   0,    1,    2, ...,   37,   38,   39],
       [  40,   41,   42, ...,   77,   78,   79],
       [  80,   81,   82, ...,  117,  118,  119],
       ...,
       [1080, 1081, 1082, ..., 1117, 1118, 1119],
       [1120, 1121, 1122, ..., 1157, 1158, 1159],
       [1160, 1161, 1162, ..., 1197, 1198, 1199]])
# 配列コピー
blue = red.copy()
# 要素を全て0に置換
blue[:,:] = 0

blue
array([[0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       ...,
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]])

2次元配列を3次元方向に結合

# 二次元配列を3次元方向に結合
color_array_3d = np.stack([red,green,blue], axis=2)
# 形状確認
color_array_3d.shape
(30, 40, 3)

30行40列で三次元の配列が出来た。



三次元配列を画像として表示

三次元のnumpy配列をmatplotlibで表示させる。
黄色い単色画像が表示されれば狙いは成功。

import matplotlib.pyplot as plt

plt.imshow(color_array_3d)

<matplotlib.image.AxesImage at 0x728388fc40>

・キャプチャー画像

20200912082111

上手く行った。
なんと簡単!!

3次元配列をnp.hstack()とnp.vstack()で結合


今度は、画像に見立てた3次元配列を縦や横に結合させ、繋げた3次元配列を画像表示させる実験。

np.vstack()np.hstack()を使う。
使い方を確認しておこう。

a = [1,2,3]
b = [4,5,6]

print("【hstack】 \n", np.hstack([a,b]))
print("【vstack】 \n", np.vstack([a,b]))
【hstack】 
 [1 2 3 4 5 6]
【vstack】 
 [[1 2 3]
 [4 5 6]]

h : horizontalのh。水平に(横に)結合。
v : verticalのv。垂直に(縦に)結合。



要素が全て0の2次元配列a_0と、要素が全て255の2次元配列a_255を用意する。
上で作ったものを使い回す。

# 全て0の、30行40列二次元配列
a_0 = blue
# 全て255の、30行40列二次元配列
a_255 = red

print("【a_0 の形状】",a_0.shape)
print("【a_255 の形状】 ", a_255.shape)
【a_0 の形状】 (30, 40)
【a_255 の形状】  (30, 40)



R,G,B 色チャンネル(255を1に置き換えて表すと)

0,0,0 black
0,0,1 blue
0,1,0 green
0,1,1 blue green
1,0,0 red
1,0,1 purple
1,1,0 yellow
1,1,1 white



2次元配列を3次元方向に結合する時に使ったnp.stack()で、8色の画像に見立てた3次元配列を生成する。

black = np.stack([a_0,a_0,a_0],axis=2)

blue = np.stack([a_0,a_0,a_255],2)

green = np.stack([a_0,a_255,a_0],2)

bluegreen = np.stack([a_0,a_255,a_255],2)

red = np.stack([a_255,a_0,a_0],2)

purple = np.stack([a_255,a_0,a_255],2)

yellow = np.stack([a_255,a_255,a_0],2)

white = np.stack([a_255,a_255,a_255],2)

黒、青、緑、青緑
赤、紫、黄、白

の形を狙って3次元配列を縦や横に結合する。

panel_1 = np.hstack([black,blue,green,bluegreen])
panel_2 = np.hstack([red,purple,yellow,white])

panel = np.vstack([panel_1, panel_2])

# 表示
plt.imshow(panel)

# 画像として保存
plt.imsave("panel_8.jpg", panel)
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

(画像省略)



ランダムな単色画像を生成


最後に。
ランダムな値を生成して2次元配列を3つ作り、それらを3次元方向に結合して3次元配列を生成。
出来た3次元配列を画像として表示。10枚縦に並べる。



整数をランダムで1つ生成するにはnp.random.randint(数値)を使うとできる。数値までの整数がランダムで返る。

使い方

# 0~255の整数をランダムに生成
np.random.randint(255)
81

ランダム値による3次元配列生成の関数

# 100行150列の3次元配列を生成する関数

def make_random_panel():
    random_int = np.random.randint(255)
    
    mono_panel_r = np.arange(15000).reshape(100,150)
    mono_panel_r[:,:] = random_int
    
    mono_panel_g = mono_panel_r.copy()
    mono_panel_g[:,:] = np.random.randint(255)
    
    mono_panel_b = mono_panel_g.copy()
    mono_panel_b[:,:] = np.random.randint(255)
    
    panel_array = np.stack([mono_panel_r,mono_panel_g,mono_panel_g],2)
    
    return panel_array
    

ランダムな単色画像の生成と表示

cnt=0
while cnt<10:
    # 3次元配列生成
    panel_array = make_random_panel()
    cnt +=1
    
    # 画像として表示
    plt.subplot(10,1,cnt)
    plt.imshow(panel_array)

キャプチャー画像

f:id:chayarokurokuro:20200912082452j:plain



おわりに

2次元配列から3次元方向へ結合するnp.stack()を使うと簡単にできることが分かった。
Excelドット絵のような2次元配列を使って何かできないかと思ったり。



以上です。