Numpyのndarray型を使ったOpenCVの画像データ覚書

pythonコンピュータ
python

Pythonで画像データを操作する際numpyライブラリのndarray型を使います。
一見普通の配列と同じようにも思えますが、配列を操作に便利な機能が沢山あるようなので少しずつ調べて学びたいと思います。

スポンサーリンク

ndarray型の初期化

初期値を指定しない

import numpy as np

a = np.ndarray(shape=(3,3), dtype='uint8')

print(a)

#[[48 22 206]
# [4 1 0]
# [0 0 20]]
引数shapeの(高さ,幅[,チャンネル数])で配列の要素数を指定
dtypeで要素の型を指定
今回のサンプルは符号なし整数8ビット、3×3の2次元配列が出来上がります。
主にグレースケールの画像に使います。
カラーの場合shapeのチャンネル数に3、透明度を含む場合4をセットします。
ndarrayは初期値を指定しない為、初期化された配列の値は不定で、実行するたびに結果が異なりました。

 

0で初期化

import numpy as np

b = np.zeros((3,3), dtype='uint8')
print(b)
#[[0 0 0]
# [0 0 0]
# [0 0 0]]
引数はndarrayと同じ値をセットしましたが、zerosの場合初期値が0でセットされます。
この配列を画像として保存すると真っ黒な画像ファイルが出来上がります。

任意の値で初期化

グレースケール

import numpy as np

c = np.full(shape=(3,3), fill_value=255, dtype='uint8')
print(c)
[[255 255 255]
 [255 255 255]
 [255 255 255]]
fill_valueに配列の要素の初期価値をセットします。サンプルでは255で初期化しました。

カラー(透明度付き)

import numpy as np

c = np.full(shape=(3,3,4), fill_value=(255,255,255,0), dtype='uint8')
print(c)
[[[255 255 255   0]
  [255 255 255   0]
  [255 255 255   0]]

 [[255 255 255   0]
  [255 255 255   0]
  [255 255 255   0]]

 [[255 255 255   0]
  [255 255 255   0]
  [255 255 255   0]]]
fill_valueに配列をセットしました。

既存のndarrayオブジェクトの構造をコピー

0で初期化

import numpy as np

c = np.full(shape=(3,3,4), fill_value=(255,255,255,0), dtype='uint8')
d = np.zeros_like(c)
print(d)
[[[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]]]

任意の数値で初期化

import numpy as np

a = np.zeros(shape=(3,3), dtype='uint8')
b = np.full_like(a, 255)
print(b)
[[255 255 255]
 [255 255 255]
 [255 255 255]]

既存のndarrayオブジェクトをコピー

import numpy as np

org = np.zeros(shape=(3,3), dtype='uint8')
clon = org.copy()
clon[1][1] = np.uint8(255)
print(clon)
#[[  0   0   0]
# [  0 255   0]
# [  0   0   0]]
# コピー先を書き換えても
print(org)
#[[0 0 0]
# [0 0 0]
# [0 0 0]]
# コピー元(オリジナル)は変更されない
コピー先を書き換えてもコピー元が変更されていないので、コピー元とコピー先は別のオブジェクトになっていることが、確認出来る。

チャンネル

チャンネル配列の並びはBGR、アルファチャンネル付きでBGRA

import cv2
import numpy as np

img = np.full(shape=(64,64,3), fill_value=(255,0,0), dtype='uint8')

cv2.imwrite('blur.png', img)

import cv2
import numpy as np

img = np.full(shape=(64,64,3), fill_value=(0,255,0), dtype='uint8')

cv2.imwrite('green.png', img)

import cv2
import numpy as np

img = np.full(shape=(64,64,3), fill_value=(0,0,255), dtype='uint8')

cv2.imwrite('red.png', img)

アルファチャンネル

import cv2
import numpy as np

img = np.full(shape=(64,64,4), fill_value=(0,0,0,255), dtype='uint8')

cv2.imwrite('black.png', img)

アルファチャンネル:0透明~255不透明

チャンネルの分離

import cv2
import numpy as np

h = 3
w = 3
img = np.full(shape=(h,w,4), fill_value=(127,127,255,255), dtype='uint8')

blur = img[:,:,0]
green = img[:,:,1]
red = img[:,:,2]
alpha = img[:,:,3]
print(blur)
#[[127 127 127]
# [127 127 127]
# [127 127 127]]
print(green)
#[[127 127 127]
# [127 127 127]
# [127 127 127]]
print(red)
#[[255 255 255]
# [255 255 255]
# [255 255 255]]
print(alpha)
#[[255 255 255]
# [255 255 255]
# [255 255 255]]

チャンネルの結合

import cv2
import numpy as np

h = 128
w = 64
r = np.full(shape=(h,w), fill_value=255, dtype='uint8')
g = np.full(shape=(h,w), fill_value=127, dtype='uint8')
b = np.full(shape=(h,w), fill_value=127, dtype='uint8')
a = np.full(shape=(h,w), fill_value=255, dtype='uint8')

img = np.stack(arrays=(b,g,r, a), axis=-1)

print(img)

cv2.imwrite('pink.png', img)

グレースケールの配列同士の加算

import cv2
import numpy as np

h = 3
w = 3
a = np.full(shape=(h,w), fill_value=128, dtype='uint8')
b = np.full(shape=(h,w), fill_value=128, dtype='uint8')

# uint8をint64にキャストして加算
c = np.add(a.astype(np.int64), b.astype(np.int64))

# uint8に収まらない数値を置き換え
c[c>255] = 255
c[c<0] = 0

# int64をuint8にキャスト
c = c.astype(np.uint8)
print(c)
#[[255 255 255]
# [255 255 255]
# [255 255 255]]
配列同士は普通にc = a + bの様に計算することが出来ます。
上記のサンプルの128+128では答えが256となってしまいuint8で表現できる最大値255超えてしまいます。
エラーではありませんが結果が0となります。
これだと都合が悪い場合があるので、uint8の最大値(最小値)を超える計算結果になる場合、置き換えるようにしています。
もっと良い方法がありそうですが、見つけることが出来ません。

コメント