OpenCVでカラー画像を読み込み、グレースケール、二値化処理、というながれでマスク画像を作ります。
1. 画像読み込み
OpenCVで画像を読み込みます。
OpenCVはBGR(Blue/Green/Red)カラーモデル(3色のチャネルの順番の話です)でデータを読み込みますが、
一般的にはRGBカラーモデルであり、またmatplotlib.pyplot
の表示はRGBカラーモデルのため、オリジナルの画像と色合いを合わせるためにRGBカラーモデルへの変換を行います。
>>> import cv2 # 読み込みOpenCVライブラリ
>>> import matplotlib.pyplot as plt # 出力
>>> img = cv2.imread('sample.JPG')
>>> img.shape
(240, 400, 3)
>>> rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
>>> plt.imshow(rgb_img)
>>> plt.show()
2. グレースケール処理
(RGB)カラー画像は1ピクセルごとに3層のパラメータにより色合いが決まっています。
グレー画像に変換すると1ピクセルごとに1つのパラメータにより色合いが決まります。
ではカラー画像からグレー画像へ変換してみます。
>>> gray_img = cv2.cvtColor(rgb_img,cv2.COLOR_RGB2GRAY)
>>> plt.imshow(gray_img)
>>> plt.show()
3. 二値化処理
グレー画像のパラメータについて、基準値を設定して、1ピクセルごとに0か1に変換します。
では適当に基準値を設定してグレー画像からバイナリー画像へ変換してみます。
>>> bin_threshold = 175
>>> ret, bin_img = cv2.threshold(gray_img ,bin_threshold, 1, cv2.THRESH_BINARY_INV)
>>> bin_img
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[1, 1, 1, ..., 1, 1, 1],
[1, 1, 1, ..., 1, 1, 1],
[1, 1, 1, ..., 1, 1, 1]], dtype=uint8)
>>> plt.imshow(bin_img)
>>> plt.show()
booleanな配列・リストの0と1の反転
boolean
なnumpy.array
やlist
の0と1の反転は、方法はいろいろありますが、次の方法がシンプルです。
「1 - np.array(対象の配列やリスト)」
for文でぐるぐるまわしたり、内包表記を使うに及びません。
numpyでスッキリかけます。
リストにしたい場合はこの結果にtolist()
という関数で変換すればよいです。
boolean
な配列・リストの反転
例として簡単な配列、リストに対して上記方法により0と1を反転してみます。
>>> import numpy as np
>>> array1 = np.array([1,0,0])
>>> array1_not = 1 - array1
>>> array1_not
array([0, 1, 1])
>>> array2 = np.array([[1,0,0],[0,1,0]])
>>> array2_not = 1 - array2
>>> array2_not
array([[0, 1, 1],
[1, 0, 1]])
>>> list1 = [1,0,0]
>>> list1_not = (1 - np.array(list1)).tolist()
>>> list1_not
[0, 1, 1]
>>> list2 = [[1,0,0],[0,1,0]]
>>> list2_not = (1 - np.array(list2)).tolist()
>>> list2_not
[[0, 1, 1], [1, 0, 1]]
バイナリー画像の反転
binary画像の反転も配列・リストと同じです。
サイズが変わろうが、行う方法は同じでシンプルです。
「1 - np.array(対象の配列やリスト)」
それでは、作成したバイナリー画像の0と1を反転してみます。
>>> bin_img_not = 1 - bin_img
画像のマスキングの方法
バイナリー画像のマスクイメージを作って、イメージに沿って情報をマスキングします。
必要な個所のみを切り取るCropではなく、同じサイズの画像から必要な情報のみを残す方法です。
グレー画像のマスキング
グレー画像もバイナリー画像も同じ次元であり、バイナリー画像は0と1で構成されるため、
対応するピクセル同士の数値を掛け算してあげれば、簡単にマスキングできます。
numpy.array
で構成されるグレー画像、バイナリー画像であれば、その掛け算も簡単にできます。
作成したバイナリー画像をマスクイメージとしてグレー画像からマスキングを実施してみます。
>>> gray_img_masked = gray_img * bin_img
>>> gray_img_masked_not = gray_img * (1 - bin_img)
カラー画像のマスキング
同じピクセル数でもRGBカラーモデルでは、1ピクセルごとに3層分のデータを保有するため、バイナリー画像で単純に掛け算するにはひと工夫必要です。
numpy.stack
を使って、層の数を合わせることができます。
これにより同じ値のマスクイメージ(バイナリー画像)を3層もつ状態が表現できます。
カラー画像とこの3層に対応したマスクイメージを掛け合わせるとカラー画像のマスキングができます。
それではカラー画像のマスキングを実施してみます。
>>> rgb_img_masked = rgb_img * np.stack([bin_img]*3, axis=2)
>>> rgb_img_masked_not = rgb_img * np.stack([1 - bin_img]*3, axis=2)
(参考)
カラー画像のマスキングについて
OpenCVで cv2.bitwise_and
という関数を使っても同じ結果が得られます。
cv2.bitwise_and(img, img, mask=bin_img)
まとめ
-
numpy
でboolean
な配列やリストの0と1の反転が簡単にできる!
「1 - np.array(対象の配列やリスト)」 -
numpy
で画像のマスキングが簡単にできる!
「画像×マスクイメージ」
ただし、マスクイメージは、バイナリー画像で画像のチャネルと合わせる工夫が必要