24bits画像データを開きBGRに分離して重ねて24bitsに戻す

下記の画像を Pillow で読み込んで ndarray に変換し、Blue, Green, Red のカラープレーンに分解して、そのときの ndarray の扱いをサンプルソースで示します。

grad_bpp24.bmp

画像の幅は 512 ピクセルです。画像の高さは 256 ピクセルです。これを Pillow で Image.open() し、np.array() を使ってデータを ndarray に変換します。

このとき、ndarray は下記のような3次元配列の shape を示します。

(256, 512, 3)

これは下記のようなイメージでとらえればいいです。手前が Red のプレーンで、奥が Blue のプレーンです。

余談ですが、X11 のピクスマップは、こんな考え方でしたね。

3次元配列を2次元配列に分割(スライス)する

この3次元配列を、それぞれのカラープレーン2次元配列に分解(スライス)するには data[:,:,n] という記法をつかいます。

[:,:,n] において
n = 0 のときが Red 成分の2次元配列です。
n = 1 のときが Green 成分の2次元配列です。
n = 2 のときが Blue 成分の2次元配列です。

2次元配列を重ねて(スタック)3次元配列にする

逆に、2次元配列を重ねて(スタック)3次元配列にするには、np.stack(( r, g, b ), axis=2 ) というメソッドを使います。axis = 2 という引数は2次元配列を奥行方向に重ねるということを意味します。ためしに axis = 0 や axis = 1 にしてみると "Cannot handle this data type" というエラーがでます。

また、(r, g, b) の順にスタックするか、(b, g, r) の順にスタックするかで実行結果が変わってきます。2次元配列としては同じ形なのでエラーにはなりませんが注意してください。

axis の方向については numpy.org のウェブページのドキュメントをお読みください・・・と言いたいところなのですが numpy.org では、ビジュアルな説明がされていないので、適当にウェブ検索をかけて調べたほうがいいです。

サンプルソース

下記がサンプルソースです。このウェブページの最初にある画像を右クリックでローカルに保存してください。形式はビットマップ形式です。そのファイルをc:/tmp/grad_bpp24.bmp に配置してください。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# ------------------------------------------
# 任意のデータだけをゼロにする関数.
def data_set_zero( arr_data_b, arr_data_g, arr_data_r, width, height, flag_set_zero_B, flag_set_zero_G, flag_set_zero_R ):

    arr_data_b = arr_data_b.reshape( -1 )
    arr_data_g = arr_data_g.reshape( -1 )
    arr_data_r = arr_data_r.reshape( -1 )
    
    w = width
    h = height
    numpix = w * h
    
    if ( flag_set_zero_B == True ):
        for n in range( numpix ):
            arr_data_b[n] = 0

    if ( flag_set_zero_G == True ):
        for n in range( numpix ):
            arr_data_g[n] = 0
    
    if ( flag_set_zero_R == True ):
        for n in range( numpix ):
            arr_data_r[n] = 0

    arr_data_b.reshape( h, w )
    arr_data_g.reshape( h, w )
    arr_data_r.reshape( h, w )

    return
# ------------------------------------------

im = Image.open( "c:/tmp/grad_bpp24.bmp" )
print( im.mode )

w = im.width;
h = im.height;

# Pillow のイメージから ndarray に変換する.
data_src = np.array( im )

# BGR のプレーンとして切り出す.
data_b0 = np.copy( data_src[:,:,2] )
data_g0 = np.copy( data_src[:,:,1] )
data_r0 = np.copy( data_src[:,:,0] )

# 同じものをコピーする.
data_b1 = np.copy( data_b0 )
data_g1 = np.copy( data_g0 )
data_r1 = np.copy( data_r0 )

# 同じものをコピーする.
data_b2 = np.copy( data_b0 )
data_g2 = np.copy( data_g0 )
data_r2 = np.copy( data_r0 )

# 同じものをコピーする.
data_b3 = np.copy( data_b0 )
data_g3 = np.copy( data_g0 )
data_r3 = np.copy( data_r0 )

# 同じものをコピーする.
data_b4 = np.copy( data_b0 )
data_g4 = np.copy( data_g0 )
data_r4 = np.copy( data_r0 )

# 同じものをコピーする.
data_b5 = np.copy( data_b0 )
data_g5 = np.copy( data_g0 )
data_r5 = np.copy( data_r0 )

# 任意のカラープレーンだけをゼロにする関数をコールする.
data_set_zero( data_b0, data_g0, data_r0, w, h, flag_set_zero_B = False,  flag_set_zero_G =  True, flag_set_zero_R =  True )
data_set_zero( data_b1, data_g1, data_r1, w, h, flag_set_zero_B =  True,  flag_set_zero_G = False, flag_set_zero_R =  True )
data_set_zero( data_b2, data_g2, data_r2, w, h, flag_set_zero_B =  True,  flag_set_zero_G =  True, flag_set_zero_R = False )
data_set_zero( data_b3, data_g3, data_r3, w, h, flag_set_zero_B = False,  flag_set_zero_G = False, flag_set_zero_R =  True )
data_set_zero( data_b4, data_g4, data_r4, w, h, flag_set_zero_B = False,  flag_set_zero_G =  True, flag_set_zero_R = False )
data_set_zero( data_b5, data_g5, data_r5, w, h, flag_set_zero_B =  True,  flag_set_zero_G = False, flag_set_zero_R = False )

# 2次元配列を奥行方向にスタックして3次元配列にする.
data_bgr0 = np.stack(( data_r0, data_g0, data_b0 ), axis = 2 ) # blue.
data_bgr1 = np.stack(( data_r1, data_g1, data_b1 ), axis = 2 ) # green.
data_bgr2 = np.stack(( data_r2, data_g2, data_b2 ), axis = 2 ) # red.
data_bgr3 = np.stack(( data_r3, data_g3, data_b3 ), axis = 2 ) # cyan.
data_bgr4 = np.stack(( data_r4, data_g4, data_b4 ), axis = 2 ) # magenta.
data_bgr5 = np.stack(( data_r5, data_g5, data_b5 ), axis = 2 ) # yellow.

# 3次元配列の行列と奥行きを表示する.
print( "src  shape {0}".format( data_src.shape  ) )
print( "bgr0 shape {0}".format( data_bgr0.shape ) )
print( "bgr1 shape {0}".format( data_bgr1.shape ) )
print( "bgr2 shape {0}".format( data_bgr2.shape ) )
print( "bgr3 shape {0}".format( data_bgr3.shape ) )
print( "bgr4 shape {0}".format( data_bgr4.shape ) )
print( "bgr5 shape {0}".format( data_bgr5.shape ) )

# ndarray から Pillow のイメージに変換する.
im_bgr0 = Image.fromarray( data_bgr0 )
im_bgr1 = Image.fromarray( data_bgr1 )
im_bgr2 = Image.fromarray( data_bgr2 )
im_bgr3 = Image.fromarray( data_bgr3 )
im_bgr4 = Image.fromarray( data_bgr4 )
im_bgr5 = Image.fromarray( data_bgr5 )

# 画像を保存したい場合はこれらをコメントインする.
# im_bgr0.save( "c:/tmp/grad_bpp24_0_b.bmp" )
# im_bgr1.save( "c:/tmp/grad_bpp24_1_g.bmp" )
# im_bgr2.save( "c:/tmp/grad_bpp24_2_r.bmp" )
# im_bgr3.save( "c:/tmp/grad_bpp24_3_c.bmp" )
# im_bgr4.save( "c:/tmp/grad_bpp24_4_m.bmp" )
# im_bgr5.save( "c:/tmp/grad_bpp24_5_y.bmp" )

# 書き込み要素を取得する.
fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.set_title( "source" )
ax.axis( "off" )
plt.imshow( data_src, cmap="gray" )
plt.show()

# 書き込み要素を取得する.
fig = plt.figure()

# タイルの縦横の個数.
TILE_NUM_ROW = 2
TILE_NUM_COL = 3

list_img = []
list_img.append( im_bgr0 )
list_img.append( im_bgr1 )
list_img.append( im_bgr2 )
list_img.append( im_bgr3 )
list_img.append( im_bgr4 )
list_img.append( im_bgr5 )

plot_counter = 1
for n in range( len( list_img )):
    ax = fig.add_subplot( TILE_NUM_ROW, TILE_NUM_COL, plot_counter )
    ax.set_title( "{0}".format( plot_counter ))
    ax.axis( "off" )
    plt.imshow( list_img[n], cmap="gray" )
    plot_counter += 1

plt.show()

print( "finish." )

下記が実行結果です。

PS C:\tmp> python test.py
RGB
src  shape (256, 512, 3)
bgr0 shape (256, 512, 3)
bgr1 shape (256, 512, 3)
bgr2 shape (256, 512, 3)
bgr3 shape (256, 512, 3)
bgr4 shape (256, 512, 3)
bgr5 shape (256, 512, 3)
finish.

下記が matplotlib の結果です。

画像1は、B成分を残し、G成分とR成分をゼロにしたもので、白グラデーションのところは Blue になります。
画像2は、G成分を残し、B成分とR成分をゼロにしたもので、白グラデーションのところは Green になります。
画像3は、R成分を残し、B成分とG成分をゼロにしたもので、白グラデーションのところは Red になります。
画像4は、B成分とG成分を残し、R成分をゼロにしたもので、白グラデーションのところは Cyan になります。
画像5は、B成分とR成分を残し、G成分をゼロにしたもので、白グラデーションのところは Magenta になります。
画像6は、G成分とR成分を残し、B成分をゼロにしたもので、白グラデーションのところは Yellow になります。