Cv2.FloodFill の使い方【OpenCV/C#(OpenCvSharp)】〜塗りつぶし処理〜

OpenCV for C#
📌 準備: OpenCV の環境構築がまだの方はこちら → C++ 環境構築ガイド / C#(OpenCvSharp)セットアップ

Cv2.FloodFill の使い方【OpenCV/C#(OpenCvSharp)】〜塗りつぶし処理〜

Cv2.FloodFill は、指定したシードポイントを起点に、隣接する同色(近似色)ピクセルを一定の色で塗りつぶす関数です。ペイントソフトのバケツツールと同じ動作で、背景除去・領域抽出・欠陥検査など幅広い用途に使えます。

最小構成のコードは次のとおりです。

int area = Cv2.FloodFill(mat, new Point(x, y), new Scalar(0, 255, 0));

動作環境

項目 内容
OpenCV 4.x(OpenCvSharp4)
言語 C# / .NET 8
NuGet OpenCvSharp4 + OpenCvSharp4.runtime.win

環境構築がまだの方は環境構築ガイドを先にどうぞ。


基本の使い方

白背景に黒い矩形を描いた画像を用意し、背景部分をシードポイントとして緑色に塗りつぶします。

using OpenCvSharp;

// 白背景(500x400)に黒い矩形を描画
using var src = new Mat(400, 500, MatType.CV_8UC3, Scalar.White);
Cv2.Rectangle(src, new Rect(100, 80, 200, 180), Scalar.Black, -1);

// FloodFill: シードポイント(10, 10)から背景を緑に塗りつぶす
using var dst = src.Clone();
// 塗りつぶし後の面積(塗られたピクセル数)が戻り値
int filledArea = Cv2.FloodFill(
    dst,                        // 対象画像(in-place で書き換わる)
    new Point(10, 10),          // シードポイント(塗り始め座標)
    new Scalar(0, 255, 0),      // 塗りつぶし色(BGR: 緑)
    out Rect boundingRect,      // 塗りつぶされた領域のバウンディングボックス
    new Scalar(10, 10, 10),     // loDiff: シードとの許容差(下方向)
    new Scalar(10, 10, 10),     // upDiff: シードとの許容差(上方向)
    FloodFillFlags.Link4        // 4近傍 or 8近傍
);

Console.WriteLine($"塗りつぶし面積: {filledArea} px");
Console.WriteLine($"バウンディングボックス: {boundingRect}");

Cv2.ImWrite("floodfill_result.png", dst);
Console.WriteLine("floodfill_result.png を保存しました");

実行すると次のような出力が得られます。

塗りつぶし面積: 136400 px
バウンディングボックス: {X=0,Y=0,Width=500,Height=400}
floodfill_result.png を保存しました

コード解説

  • Cv2.FloodFill は第1引数の Mat を 直接書き換えます。元画像を保持したい場合は .Clone() してから渡します。
  • loDiff / upDiff は「シードピクセルの色 ± この差分」の範囲内にあるピクセルを塗りつぶし対象とします。Scalar.All(0) にすると完全一致のみ。
  • 戻り値の int が塗りつぶされたピクセル数です。面積フィルタとして利用できます。
  • boundingRect はオプションの out 引数で、塗りつぶし領域の外接矩形を受け取れます。

引数と戻り値

引数 型 説明
image Mat 入出力画像(CV_8U または CV_32F、1ch or 3ch)。in-place で変更される
seedPoint Point 塗りつぶしを開始する座標
newVal Scalar 塗りつぶす色
rect out Rect 塗りつぶされた領域のバウンディングボックス(省略可)
loDiff Scalar 塗りつぶし対象にする色差の下限。省略時は Scalar.All(0)
upDiff Scalar 塗りつぶし対象にする色差の上限。省略時は Scalar.All(0)
flags FloodFillFlags 近傍方式・マスク処理オプション
戻り値 int 塗りつぶされたピクセル数

FloodFillFlags の主な値

フラグ 意味
Link4 4近傍で連結判定(デフォルト的な挙動)
Link8 8近傍で連結判定(斜め方向も伝播)
MaskOnly マスク画像のみ書き換え、元画像は変更しない
(1 << 8) FixedRange: 隣接ピクセルではなくシードピクセルとの差分で判定

実践例

実践例1: マスクを使って塗りつぶし領域を制限する

マスクを使うと、特定領域への塗りつぶし伝播を防げます。マスクは元画像より 縦横それぞれ2ピクセル大きい 1ch 画像が必要な点に注意してください。

using OpenCvSharp;

using var src = new Mat(400, 500, MatType.CV_8UC3, Scalar.White);
Cv2.Rectangle(src, new Rect(100, 80, 200, 180), Scalar.Black, -1);
Cv2.Rectangle(src, new Rect(300, 80, 80, 80), Scalar.Black, -1);

using var dst = src.Clone();

// マスクは (src.Rows+2) x (src.Cols+2) の CV_8UC1
using var mask = new Mat(src.Rows + 2, src.Cols + 2, MatType.CV_8UC1, Scalar.Black);

// マスクに境界線を引いて右側の矩形への伝播をブロック
Cv2.Rectangle(mask, new Rect(295, 75, 2, 200), Scalar.White, -1);

int filled = Cv2.FloodFill(
    dst,
    mask,                        // マスク指定オーバーロード
    new Point(10, 10),
    new Scalar(0, 128, 255),     // オレンジ
    out _,
    new Scalar(10, 10, 10),
    new Scalar(10, 10, 10),
    FloodFillFlags.Link4
);

Console.WriteLine($"塗りつぶし面積(マスクあり): {filled} px");
Cv2.ImWrite("floodfill_mask.png", dst);
Cv2.ImWrite("floodfill_mask_result.png", mask);

実践例2: 二値化後の穴埋め(孔のある領域を塗りつぶす)

閾値処理で抽出したオブジェクト内部の穴を FloodFill で埋めるテクニックです。

using OpenCvSharp;

// ドーナツ型の図形を作成
using var src = new Mat(300, 300, MatType.CV_8UC1, Scalar.Black);
Cv2.Circle(src, new Point(150, 150), 100, Scalar.White, -1);
Cv2.Circle(src, new Point(150, 150), 50, Scalar.Black, -1);

// 画像の外周(0,0)からFloodFillして背景を確定
using var filled = src.Clone();
Cv2.FloodFill(filled, new Point(0, 0), new Scalar(128));

// 未塗りつぶし(値=0)が穴→白に変換して穴埋め完了
using var result = new Mat();
Cv2.Threshold(filled, result, 127, 255, ThresholdTypes.BinaryInv);

// src と result を OR することで穴埋め画像を得る
using var holeFilled = new Mat();
Cv2.BitwiseOr(src, result, holeFilled);

Cv2.ImWrite("floodfill_holefill.png", holeFilled);
Console.WriteLine("穴埋め処理完了: floodfill_holefill.png");

つまずきポイント

⚠️ マスク画像のサイズは元画像より2px大きくする

FloodFill にマスクを渡すオーバーロードでは、マスクのサイズが (image.Rows + 2) × (image.Cols + 2) である必要があります。image.Size() そのままで作ると OpenCVException が発生します。

// NG: 同じサイズで作成
using var mask = new Mat(src.Size(), MatType.CV_8UC1, Scalar.Black);

// OK: +2 する
using var mask = new Mat(src.Rows + 2, src.Cols + 2, MatType.CV_8UC1, Scalar.Black);

⚠️ 元画像が in-place で書き換わる

Cv2.FloodFill は戻り値で新しい Mat を返さず、第1引数の Mat を直接変更します。Python の OpenCV も同様ですが、C++ に慣れているとついコピーを渡し忘れます。元画像を保持するなら必ず .Clone() してから渡してください。

⚠️ FloodFillFlags の数値合成に注意

FixedRange(シードとの絶対差分で判定)は (FloodFillFlags)(1 << 16) として合成します。Link8 と組み合わせる場合は FloodFillFlags.Link8 | (FloodFillFlags)(1 << 16) のようにビット OR します。フラグの数値定義は OpenCV 4.x のソースで確認するのが確実です。


関連する関数


まとめ

  • Cv2.FloodFill はシードポイントから隣接する近似色ピクセルを指定色で塗りつぶす関数で、背景除去・穴埋め・領域検出に活用できます。
  • loDiff / upDiff で許容色差を調整し、マスクで伝播範囲を制限するのが実務での典型パターンです。
  • 元画像が in-place で変更される点と、マスクサイズの +2 制約はハマりやすいので最初に押さえておきましょう。

🛠 画像処理のプロが開発するSDK/API

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

タイトルとURLをコピーしました