python・numpy 3次元配列へのパディング(numpy.pad)

shapeが(10, 9, 14)のような3次元配列(volume)を周りをゼロで埋めて立方体にしたい場合

numpy.padが便利です。

numpy.pad(arraypad_widthmode='constant'**kwargs)

pad_widthに((1,1),(1,1),(1,1)) かつmodeを'constant'にすると周りを0で埋めてくれます。

次のような3次元配列があるとして

arr = 
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]

arr = np.pad(arr, ((1, 1), (1, 1), (1, 1)))
[[[0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [0 1 2 0]
  [0 3 4 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [0 5 6 0]
  [0 7 8 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]]]

#constant_value という引数があってpaddingの値として使われる,defaultはゼロだが、変更できる。

#linear_rampにするとend_values(defaultは0)に向かって、edge_valueと滑らかにつないでくれる
arr = np.pad(arr, ((2, 2), (2, 2), (2, 2)), mode="linear_ramp")
[[[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]]

 [[0 0 0 0 0 0]
  [0 0 0 0 0 0]
  [0 0 0 1 0 0]
  [0 0 1 2 1 0]
  [0 0 0 1 0 0]
  [0 0 0 0 0 0]]

 [[0 0 0 0 0 0]
  [0 0 0 1 0 0]
  [0 0 1 2 1 0]
  [0 1 3 4 2 0]
  [0 0 1 2 1 0]
  [0 0 0 0 0 0]]

 [[0 0 0 0 0 0]
  [0 1 2 3 1 0]
  [0 2 5 6 3 0]
  [0 3 7 8 4 0]
  [0 1 3 4 2 0]
  [0 0 0 0 0 0]]

 [[0 0 0 0 0 0]
  [0 0 1 1 0 0]
  [0 1 2 3 1 0]
  [0 1 3 4 2 0]
  [0 0 1 2 1 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 0]
  [0 0 0 0 0 0]]]

#edgeを選択するとedgeの値をそのままつなぐ
arr = np.pad(arr, ((2, 2), (2, 2), (2, 2)), mode="edge")
[[[1 1 1 2 2 2]
  [1 1 1 2 2 2]
  [1 1 1 2 2 2]
  [3 3 3 4 4 4]
  [3 3 3 4 4 4]
  [3 3 3 4 4 4]]

 [[1 1 1 2 2 2]
  [1 1 1 2 2 2]
  [1 1 1 2 2 2]
  [3 3 3 4 4 4]
  [3 3 3 4 4 4]
  [3 3 3 4 4 4]]

 [[1 1 1 2 2 2]
  [1 1 1 2 2 2]
  [1 1 1 2 2 2]
  [3 3 3 4 4 4]
  [3 3 3 4 4 4]
  [3 3 3 4 4 4]]

 [[5 5 5 6 6 6]
  [5 5 5 6 6 6]
  [5 5 5 6 6 6]
  [7 7 7 8 8 8]
  [7 7 7 8 8 8]
  [7 7 7 8 8 8]]

 [[5 5 5 6 6 6]
  [5 5 5 6 6 6]
  [5 5 5 6 6 6]
  [7 7 7 8 8 8]
  [7 7 7 8 8 8]
  [7 7 7 8 8 8]]

 [[5 5 5 6 6 6]
  [5 5 5 6 6 6]
  [5 5 5 6 6 6]
  [7 7 7 8 8 8]
  [7 7 7 8 8 8]
  [7 7 7 8 8 8]]]

arr = np.pad(arr, ((2, 2), (2, 2), (2, 2)), mode="reflect")
[[[1 2 1 2 1 2]
  [3 4 3 4 3 4]
  [1 2 1 2 1 2]
  [3 4 3 4 3 4]
  [1 2 1 2 1 2]
  [3 4 3 4 3 4]]

 [[5 6 5 6 5 6]
  [7 8 7 8 7 8]
  [5 6 5 6 5 6]
  [7 8 7 8 7 8]
  [5 6 5 6 5 6]
  [7 8 7 8 7 8]]

 [[1 2 1 2 1 2]
  [3 4 3 4 3 4]
  [1 2 1 2 1 2]
  [3 4 3 4 3 4]
  [1 2 1 2 1 2]
  [3 4 3 4 3 4]]

 [[5 6 5 6 5 6]
  [7 8 7 8 7 8]
  [5 6 5 6 5 6]
  [7 8 7 8 7 8]
  [5 6 5 6 5 6]
  [7 8 7 8 7 8]]

 [[1 2 1 2 1 2]
  [3 4 3 4 3 4]
  [1 2 1 2 1 2]
  [3 4 3 4 3 4]
  [1 2 1 2 1 2]
  [3 4 3 4 3 4]]

 [[5 6 5 6 5 6]
  [7 8 7 8 7 8]
  [5 6 5 6 5 6]
  [7 8 7 8 7 8]
  [5 6 5 6 5 6]
  [7 8 7 8 7 8]]]

という感じになる。

numpy.pad のmodeの説明

modeを使いこなすと、簡単にedgeの感じを調整できる

上で見たようにmodeを使うとpaddingする感じを色々調整できる。

滑らかにpadding領域と繋ぎたい場合はlinear_rampを使うと良い。

立方体でない3次元配列をpaddingする場合は以下のようにする。

import numpy as np

def padding(trimed_vol):
    max_val = np.amax(trimed_vol.shape)
    xd = max_val - trimed_vol.shape[0]
    yd = max_val - trimed_vol.shape[1]
    zd = max_val - trimed_vol.shape[2]
    hxd = int((max_val - trimed_vol.shape[0])/2)
    hyd = int((max_val - trimed_vol.shape[1])/2)
    hzd = int((max_val - trimed_vol.shape[2])/2)
    new_vol = np.pad(trimed_vol,((hxd, xd-hxd),(hyd, yd-hyd),(hzd, zd-hzd)),'constant')
    return new_vol

コメント