概要
OpenCV の cv2.floodFill()
は指定した点に似た画素値を持つ領域を抽出し、塗りつぶすことができる関数です。この関数の本質は領域の抽出であるため、塗りつぶす代わりに、セグメンテーションにも活用できます。
cv2.floodFill
retval, image, mask, rect = cv2.floodFill(
image, mask, seedPoint, newVal[, loDiff[, upDiff[, flags]]])
公式リファレンス: cv2.floodFill
名前 | 型 | デフォルト値 |
---|---|---|
image | ndarray | |
1または3チャンネルで型が 8bit または浮動小数点数の画像 | ||
mask | ndarray | |
image に1画素分パディングした型が 8bit の画像 | ||
seedPoint | tuple of 2 ints | |
塗りつぶしを開始する画素 | ||
newVal | int / tuple of ints | |
塗りつぶし後の値 | ||
loDiff | int / tuple of ints | 0 / (0, 0, 0) |
連結成分を探す際の下限 | ||
upDiff | int / tuple of ints | 0 / (0, 0, 0) |
連結成分を探す際の上限 | ||
flags | int | 4 |
塗りつぶし方法などを指定するフラグ |
名前 | 説明 | ||
---|---|---|---|
retval | 塗りつぶした画素数 | ||
image | 塗りつぶし後の画像 | ||
mask | マスク | ||
rect | 連結成分に外接する長方形 |
塗りつぶす基準
seedPoint
に指定した画素と画素値の差が指定範囲内の画素を同じグループ (連結成分) と見なして塗りつぶしを行います。flags
引数で cv2.FLOODFILL_FIXED_RANGE
を指定したかどうかで連結成分を探す方法が異なります。
cv2.FLOODFILL_FIXED_RANGE
を指定した場合
cv2.FLOODFILL_FIXED_RANGE
を指定した場合、seedPoint
との画素値の差が指定範囲内の画素は連結成分に追加されます。この場合、画素値が以下の範囲にある画素が連結成分として追加されます。$$ \text{src}({seedPoint}_x, {seedPoint}_y) − loDiff \le \text{src}(x, y) \le \text{src}({seedPoint}_x, {seedPoint}_y) + upDiff $$
cv2.FLOODFILL_FIXED_RANGE
を指定しない場合
cv2.FLOODFILL_FIXED_RANGE
を指定しない場合、すでに見つかっている隣の連結成分との画素値の差が指定範囲内の画素は連結成分に追加します。$$ \text{src}(x’, y’) – loDiff \le \text{src}(x, y) \le \text{src}(x’, y’) + upDiff $$
まとめると、
cv2.FLOODFILL_FIXED_RANGE
を指定した場合:seedPoint
で指定した色と似た色は同じ領域と判定cv2.FLOODFILL_FIXED_RANGE
を指定しない場合:seedPoint
から探索を開始し、輝度勾配が閾値未満は同じ領域と判定
flags の指定方法
flags
引数はビット列で塗りつぶしの方法を設定します。各ビットの設定によって、cv2.floodFill()
関数の動作が制御されます。
ビット | 意味 | 許容値 | デフォルト |
---|---|---|---|
1 ~ 8 | 近傍の種類 (4: 4 近傍、8: 8 近傍) | {4, 8} | 4 |
9 ~ 16 | 塗りつぶした画素に対応したマスクの位置の値も変更されるが、その値 | [1, 255] | 1 |
17 | 走査する際に塗りつぶすかどうかを判定する基準 | {0, 1} | 1 |
18 | 1 の場合、マスクのみ変更し、入力画像の塗りつぶしは行わない | {0, 1} | 0 |
フラグ指定方法の例
以下のコード例では、4 連結、マスクの値を 255 に設定し、cv2.FLOODFILL_FIXED_RANGE
と cv2.FLOODFILL_MASK_ONLY
オプションを有効にしています。
flag = 4 | 255 << 8 | cv2.FLOODFILL_FIXED_RANGE | cv2.FLOODFILL_MASK_ONLY
画像内の特定の領域の塗りつぶす
import cv2
import numpy as np
from IPython.display import Image, display
def imshow(img):
"""ndarray 配列をインラインで Notebook 上に表示する。"""
ret, encoded = cv2.imencode(".jpg", img)
display(Image(encoded))
# 画像を読み込む。
img = cv2.imread("sample.jpg")
# 幅、高さとも2ピクセルずつ大きいサイズのマスクを作成する。
img_h, img_w = img.shape[:2]
mask = np.zeros((img_h + 2, img_w + 2), dtype=np.uint8)
# 塗りつぶす。
retval, img, mask, rect = cv2.floodFill(
img,
mask,
seedPoint=(100, 100), # 塗りつぶしの開始点
newVal=(0, 0, 255), # 塗りつぶす色
loDiff=(20, 20, 20), # 画素値の差が -20 〜 20 の範囲は同じ領域と判断する
upDiff=(20, 20, 20),
flags=4 | 255 << 8, # 4 連結、マスクの値を 255
)
print("retval", retval) # retval 6339
print("rect", rect) # rect (49, 42, 90, 90)
imshow(mask)
imshow(img)
retval 6146 rect (50, 43, 88, 88)
青色の円が赤色に塗りつぶされました。マスクには塗りつぶした領域が 255 で表されています。
マスク画像を使用する
mask
の画素値が 0 のピクセルのみが塗りつぶしの対象になります。塗りつぶしの対象から外したい画素は、mask
に 0 以外の値を設定しておきます。
以下の例では、cv2.circle()
を使用してマスクに白い円を描画することで、その部分を塗りつぶしの対象から外しています。
# 画像を読み込む。
img = cv2.imread("sample.jpg")
# 幅、高さとも2ピクセルずつ大きいサイズのマスクを作成する。
img_h, img_w = img.shape[:2]
mask = np.zeros((img_h + 2, img_w + 2), dtype=np.uint8)
cv2.circle(mask, (150, 100), 70, color=100, thickness=-1)
# 塗りつぶす。
retval, img, mask, rect = cv2.floodFill(
img,
mask,
seedPoint=(60, 100),
newVal=(0, 0, 255),
loDiff=(20, 20, 20),
upDiff=(20, 20, 20),
flags=4 | 255 << 8,
)
imshow(mask)
imshow(img)
cv2.floodFill()
に渡したマスクの灰色の画素(255 以外の値)は塗りつぶされず、元の青色のまま残っていることがわかります。
指定した色を透過する
塗りつぶしの代わりに、背景の 1 点を指定して、その色に似た画素を cv2.floodFill()
の結果として受け取ることができます。そのためには、flags に cv2.FLOODFILL_MASK_ONLY
フラグを指定します。
# 画像を読み込む。
img = cv2.imread("sample.jpg")
# 幅、高さとも2ピクセルずつ大きいサイズのマスクを作成する。
img_h, img_w = img.shape[:2]
mask = np.zeros((img_h + 2, img_w + 2), dtype=np.uint8)
# 塗りつぶしを実行する。
flags = 4 | 255 << 8 | cv2.FLOODFILL_MASK_ONLY
cv2.floodFill(
img,
mask,
seedPoint=(2, 2),
newVal=(0, 0, 255),
loDiff=(20, 20, 20),
upDiff=(20, 20, 20),
flags=flags,
)
# マスク作成時に追加した周囲1ピクセルは除く
mask = mask[1:-1, 1:-1]
# アルファチャンネル追加する。
dst = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
# マスクの値が 255 のアルファチャンネルは0にする。
dst[mask == 255] = 0
cv2.imwrite("result.png", dst)
True
コメント