Cv2.MorphologyEx の使い方【OpenCV/C#(OpenCvSharp)】〜モルフォロジー変換でノイズ除去・穴埋めを行う〜

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

Cv2.MorphologyEx は、膨張・収縮を組み合わせたモルフォロジー変換をワンコールで実行できる関数です。オープニング(ノイズ除去)・クロージング(穴埋め)・トップハット変換など、二値画像処理の定番操作をすべてカバーします。

Cv2.MorphologyEx(src, dst, MorphTypes.Open, kernel);

動作環境

  • OpenCV 4.x(OpenCvSharp4)
  • .NET 8 / コンソールアプリ(トップレベルステートメント)
  • NuGet: OpenCvSharp4、OpenCvSharp4.runtime.win(Windows実行時)

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


基本の使い方

まずオープニング処理(小さなノイズを除去する)の完全なサンプルを示します。

using OpenCvSharp;

// グレースケール画像を読み込む
using var src = Cv2.ImRead("input.png", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");

// 二値化(大津の方法)
using var binary = new Mat();
Cv2.Threshold(src, binary, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);

// 構造化要素(カーネル)を生成: 5×5 の楕円形
using var kernel = Cv2.GetStructuringElement(
    MorphShapes.Ellipse,
    new Size(5, 5));

// オープニング: 収縮 → 膨張(小さなノイズを除去)
using var opened = new Mat();
Cv2.MorphologyEx(binary, opened, MorphTypes.Open, kernel);

// クロージング: 膨張 → 収縮(小さな穴・隙間を埋める)
using var closed = new Mat();
Cv2.MorphologyEx(binary, closed, MorphTypes.Close, kernel);

Cv2.ImWrite("opened.png", opened);
Cv2.ImWrite("closed.png", closed);

Console.WriteLine("オープニング・クロージング処理が完了しました");

実行すると、カレントディレクトリに opened.png(ノイズ除去済み)と closed.png(穴埋め済み)が出力され、コンソールに次のメッセージが表示されます。

オープニング・クロージング処理が完了しました

コードのポイント

  • Cv2.GetStructuringElement でカーネルを生成します。形状は Rect(矩形)・Cross(十字)・Ellipse(楕円)から選べます。サイズが大きいほど処理の影響範囲が広がります。
  • MorphTypes.Open が「収縮 → 膨張」(オープニング)、MorphTypes.Close が「膨張 → 収縮」(クロージング)です。この組み合わせを手動で2回呼ぶ代わりに MorphologyEx 1回で完結します。
  • Mat はすべて using で管理し、ネイティブメモリを確実に解放しています。

引数と戻り値

引数 型 内容
src Mat 入力画像(グレースケール・カラー両対応)
dst Mat 出力画像(srcと同サイズ・同チャンネル)
op MorphTypes 変換の種類(下表参照)
element Mat 構造化要素(カーネル)。GetStructuringElement で生成
anchor Point (省略可)カーネルのアンカー点。デフォルトは中心 (-1,-1)
iterations int (省略可)反復回数。デフォルトは 1
borderType BorderTypes (省略可)境界の補完方法。デフォルトは Reflect101
borderValue Scalar (省略可)Constant 境界時の値

戻り値はありません(dst に結果が書き込まれます)。

MorphTypes の主な値

値 内容
Erode 収縮(Erosion)
Dilate 膨張(Dilation)
Open オープニング(収縮 → 膨張)
Close クロージング(膨張 → 収縮)
Gradient モルフォロジー勾配(膨張 − 収縮)
TopHat トップハット変換(元画像 − オープニング)
BlackHat ブラックハット変換(クロージング − 元画像)

実践例

実践例 1: 指紋・文書画像の細線ノイズ除去(オープニング)

スキャン文書や指紋画像では、二値化後に孤立した細かいノイズが残りがちです。オープニングで短時間に除去できます。

using OpenCvSharp;

using var src = Cv2.ImRead("document.png", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");

using var binary = new Mat();
Cv2.Threshold(src, binary, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);

// 3×3 の矩形カーネルで軽めのオープニング
using var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
using var result = new Mat();
Cv2.MorphologyEx(binary, result, MorphTypes.Open, kernel, new Point(-1, -1), iterations: 2);

Cv2.ImWrite("document_cleaned.png", result);
Console.WriteLine("ノイズ除去完了");

iterations: 2 で反復回数を増やすことで、カーネルサイズを変えずに処理を強くできます。


実践例 2: 欠陥検査での穴埋め(クロージング)

工業製品の外観検査では、対象領域の内側に小さな欠落(穴)が生じることがあります。クロージングで安定した塗りつぶしが行えます。

using OpenCvSharp;

using var src = Cv2.ImRead("defect.png", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");

using var binary = new Mat();
Cv2.Threshold(src, binary, 128, 255, ThresholdTypes.Binary);

// 楕円カーネルで穴埋め(カーネルが大きいほど大きな穴も閉じる)
using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(9, 9));
using var result = new Mat();
Cv2.MorphologyEx(binary, result, MorphTypes.Close, kernel);

Cv2.ImWrite("defect_filled.png", result);
Console.WriteLine("クロージング処理完了");

二値化については Cv2.Threshold の使い方【OpenCV/C#(OpenCvSharp)】〜画像を二値化する(大津の方法含む)〜 も合わせてご覧ください。照明ムラがある環境では Cv2.AdaptiveThreshold の使い方【OpenCV/C#(OpenCvSharp)】〜適応的二値化で照明ムラに強い処理を実現する〜 との組み合わせが有効です。


つまずきポイント

⚠️ カーネル(Mat)を Dispose し忘れる

Cv2.GetStructuringElement の戻り値は Mat です。通常の画像と同様に using で管理しないとネイティブメモリがリークします。カーネルは小さいので気づきにくいですが、ループ内で繰り返し生成する処理では確実に問題になります。

// NG: using なし
var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(5, 5));

// OK: using で解放を保証
using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(5, 5));

⚠️ MorphTypes の Open / Close と処理順の混同

MorphTypes.Open(オープニング)は「収縮 → 膨張」、MorphTypes.Close(クロージング)は「膨張 → 収縮」です。名前だけ覚えると順番を逆に実装してしまうことがあります。効果で覚えるのが確実です。

  • Open → 白い前景の 小さな点(ノイズ)を消す(前景が収縮されるため)
  • Close → 白い前景の 小さな穴・隙間を埋める(前景が膨張されるため)

⚠️ カーネルサイズは奇数でなければならない

GetStructuringElement に偶数サイズを渡すとアンカー中心が曖昧になり、意図しない位置ずれが発生することがあります。Size(5, 5) や Size(9, 9) のように奇数を使う習慣をつけてください。


関連する関数

  • Cv2.Erode / Cv2.Dilate: 収縮・膨張を単体で行う関数。MorphologyEx の内部でも使われており、単純な1ステップ処理ならこちらが直感的です。
  • Cv2.GetStructuringElement: MorphologyEx に渡すカーネルを生成する関数。形状とサイズがそのまま処理の挙動を決めます。
  • Cv2.Threshold / Cv2.AdaptiveThreshold: モルフォロジー処理は通常二値化後に適用します。内部リンク先の記事も参照してください。
  • ノイズ除去という観点では、グレースケール画像に対しては Cv2.MedianBlur の使い方【OpenCV/C#(OpenCvSharp)】〜メディアンフィルタで画像のノイズを除去する〜 との使い分けも検討に値します。二値化前のノイズ抑制にはメディアンフィルタ、二値化後の形状調整にはモルフォロジー処理、という役割分担が現場ではよく使われます。

まとめ

  • Cv2.MorphologyEx はオープニング・クロージングをはじめ7種類のモルフォロジー変換を統一的に呼び出せる関数です。
  • カーネルは Cv2.GetStructuringElement で生成し、using で確実に解放することが C# では必須です。
  • 用途に合わせて MorphTypes と iterations・カーネルサイズを調整するだけで、ノイズ除去から穴埋めまで幅広い二値画像処理に対応できます。

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

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

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

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