web-dev-qa-db-ja.com

マスク付きOpenCVフラッドフィル

ドキュメント OpenCVのフラッドフィル機能の状態:

この関数はマスクを使用および更新するため、ユーザーはマスクコンテンツを初期化する必要があります。塗りつぶしは、マスク内のゼロ以外のピクセルを超えることはできません。たとえば、エッジ検出器の出力をマスクとして使用して、エッジでの塗りつぶしを停止できます。関数の複数の呼び出しで同じマスクを使用して、塗りつぶされた領域が重ならないようにすることができます。

関数はどのようにマスクを更新しますか?フラッドフィル内のすべてのピクセルをゼロ以外の値に設定しますか?

19
1''

マスクのシードポイントと同じ接続コンポーネント内のすべてのゼロ値ピクセルは、指定した値に置き換えられます。この値は、8ビット左にシフトされたflagsパラメーターに追加する必要があります。

uchar fillValue = 128;
cv::floodFill(img, mask, seed, cv::Scalar(255) ,0, cv::Scalar(), cv::Scalar(), 4 | cv::FLOODFILL_MASK_ONLY | (fillValue << 8));

簡単ですが、おそらく啓発的な例を次に示します。次のような画像を作成します。

//Create simple input image
cv::Point seed(4,4);
cv::Mat img = cv::Mat::zeros(100,100,CV_8UC1);
cv::circle(img, seed, 20, cv::Scalar(128),3);

この画像の結果:

Original image

次に、マスクを作成して塗りつぶします。

//Create a mask from edges in the original image
cv::Mat mask;
cv::Canny(img, mask, 100, 200);
cv::copyMakeBorder(mask, mask, 1, 1, 1, 1, cv::BORDER_REPLICATE);

//Fill mask with value 128
uchar fillValue = 128;
cv::floodFill(img, mask, seed, cv::Scalar(255) ,0, cv::Scalar(), cv::Scalar(), 4 | cv::FLOODFILL_MASK_ONLY | (fillValue << 8));

この結果を与えます:

Flood-filled mask

マスク内の白いピクセルはエッジ検出の結果であり、グレーのピクセルは塗りつぶしの結果です。

PDATE:コメントへの応答で、フラグ値4は、色値の差を比較するピクセル近傍を指定します。ドキュメントから:

下位ビットには、関数内で使用される接続値4(デフォルト)または8が含まれます。接続性は、ピクセルのどの近傍を考慮するかを決定します。

cv::FLOODFILL_MASK_ONLYフラグは渡されません。both画像とマスクは更新されますが、塗りつぶしはゼロ以外のマスク値で停止します。

26
Aurelius

そしてpythonバージョン

im = cv2.imread("seagull.jpg")
h,w,chn = im.shape
seed = (w/2,h/2)

mask = np.zeros((h+2,w+2),np.uint8)

floodflags = 4
floodflags |= cv2.FLOODFILL_MASK_ONLY
floodflags |= (255 << 8)

num,im,mask,rect = cv2.floodFill(im, mask, seed, (255,0,0), (10,)*3, (10,)*3, floodflags)

cv2.imwrite("seagull_flood.png", mask)

(ウィキメディアのシーガル画像: https://commons.wikimedia.org/wiki/Commons:Quality_images#/media/File:Gull_portrait_ca_usa.jpg

結果: result

7
Roy Shilkrot

アウレリウスの答えによると、マスクはゼロにする必要があります。

ソース内のコメントを確認すると、

これは入力パラメーターと出力パラメーターの両方であるため、初期化の責任を負う必要があります。塗りつぶしは、入力マスク内のゼロ以外のピクセルを超えることはできません。

マスクは結果に影響するため、使用する前にゼロにする必要があります。

cv::Mat mask;
mask = cv::Mat::zeros(img.rows + 2, img.cols + 2, CV_8UC1);
0
MK Yung