Python 備忘録

Python-ver: 3.6.3

Pythonで画像処理② マスキング

閾値

本日は閾値というものを使って、画像のマスキングをしてみたいと思います。

閾値(しきいち)とは

閾値とは、その値を境にして、動作や意味などが変わる値のことである。

http://www.weblio.jp/content/%E9%96%BE%E5%80%A4?edc=BINIT

今回はこの意味の方が正しいでしょう。

そして、マスキングとはある画像のある部分だけ隠すこと。

つまり、閾値という色の範囲を指定してその部分だけ画像を隠そうということです。

閾値を使ったマスキング

それでは実際にプラグラムを書いてみたいと思います。
使うのはまたこの画像

f:id:sh0122:20171015140811j:plain
こちらの画像の空の部分だけマスキングしたいと思います。

プログラムはこちらを参考にさせていただきました。変数など少し変えてます。
画像処理入門講座 : OpenCVとPythonで始める画像処理 | プログラミング | POSTD

import cv2, matplotlib
import numpy as np
import matplotlib.pyplot as plt

blue_min = np.array([140, 0, 0], np.uint8)
blue_max = np.array([255, 255, 255], np.uint8)

img = cv2.imread('../images/field.jpg')
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
plt.imshow(cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB))

まずは、最初の部分から。ここからどんどん付け足す形で書いていきます。
blue_minは青色の最少値、blue_maxは青色の最大値で、ここで青色の色の範囲を指定してます。

そのあと、イメージを読んで、表示させています。
ここで画像をHSVに一回変換していますが、HSVとは

HSVとは,Hueが色相,Saturation(Chroma)が彩度,Value(Lightness)が明度である.それぞれHueは[0,179], Saturationは[0,255],Valueは[0,255]の範囲の値をとるが、使用するソフトウェアによっては値の範囲が異なるので,OpenCVで得られた値と別ソフトウェアで得られた値を比較する場合は,値の正規化をしなければならない.

http://lang.sist.chukyo-u.ac.jp/classes/OpenCV/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html

のことだそうです。
ここでplt.show()で画像を表示させてみると

f:id:sh0122:20171015142015p:plain

普通に表示されます。

その次

# 青の領域のマスクを取得
mask_blue = cv2.inRange(img, blue_min, blue_max)

# 青の領域のマスクから青じゃない部分を取得
mask = cv2.bitwise_not(mask_blue)
plt.imshow(cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB))

cv2.inRangeで青の部分のマスクを取得しmask_blueにいれています。
そのあとにその青のマスクを利用して、青じゃない部分を取得しています。

この部分をRGBに変換して表示させます。
ここでplt.show()をしてみると。

f:id:sh0122:20171017215912p:plain

こうなります。

黒の部分が表示されない、部分。白の部分が表示されるマスクされた部分。
(余計な部分が少し消えてます。この部分はまた今度やりたいと思います。)

そして、最後

mask_rgb = cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB)
# 青じゃない部分の領域をカット
masked_img = cv2.bitwise_and(img, mask_rgb)

# 切り取った部分を白で補完
masked_replace_white = cv2.addWeighted(masked_img, 1, \
                                       cv2.cvtColor(mask_blue, cv2.COLOR_GRAY2RGB), 1, 0)

plt.imshow(cv2.cvtColor(masked_replace_white, cv2.COLOR_BGR2RGB))

実際に元のデータをカットして、空の部分を消しています。
ここで表示させてみると。

f:id:sh0122:20171017220108p:plain

こんな感じ。道の部分が少し消えちゃってますね。
何か変換をかければよいのか。わかりませんが、調べてみようと思います。

プログラム全体

import cv2, matplotlib
import numpy as np
import matplotlib.pyplot as plt

blue_min = np.array([140, 0, 0], np.uint8)
blue_max = np.array([255, 255, 255], np.uint8)

img = cv2.imread('../images/field.jpg')
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
plt.imshow(cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB))

# 青の領域のマスクを取得
mask_blue = cv2.inRange(img, blue_min, blue_max)

# 青の領域のマスクから青じゃない部分を取得
mask = cv2.bitwise_not(mask_blue)
plt.imshow(cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB))


mask_rgb = cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB)

# 青じゃない部分の領域をカット
masked_img = cv2.bitwise_and(img, mask_rgb)

# 切り取った部分を白で補完
masked_replace_white = cv2.addWeighted(masked_img, 1, \
                                       cv2.cvtColor(mask_blue, cv2.COLOR_GRAY2RGB), 1, 0)

plt.imshow(cv2.cvtColor(masked_replace_white, cv2.COLOR_BGR2RGB))

plt.show()

次は、画像認識に入ってゆきたいと思います。