モルフォロジー演算の基礎 - 膨張・収縮・オープニング・クロージングの原理と実践
モルフォロジー演算とは - 形状に基づく画像処理の基礎概念
モルフォロジー (形態学) 演算は、画像内のオブジェクトの形状を操作する画像処理手法です。1964 年に Georges Matheron と Jean Serra によって数学的に体系化され、二値画像のノイズ除去、輪郭抽出、領域の分離・結合など、幅広い応用を持ちます。
基本的な考え方: モルフォロジー演算は「構造要素 (Structuring Element)」と呼ばれる小さなテンプレートを画像上でスライドさせ、各位置での集合演算 (和集合、積集合) の結果を出力画像とします。構造要素の形状とサイズが演算の効果を決定します。
適用対象: 本来は二値画像 (白黒 2 値) に対する演算として定義されましたが、グレースケール画像やカラー画像にも拡張されています。二値画像では前景 (白) と背景 (黒) の境界を操作し、グレースケールでは局所的な最大値・最小値フィルタとして機能します。
構造要素 (カーネル): 演算の「形」を定義する小さな行列です。一般的な形状には以下があります。
- 矩形 (Rectangle): 最も基本的。水平・垂直方向に均等に作用します。
- 楕円 (Ellipse): 円形に近い等方的な作用。自然な形状の処理に適しています。
- 十字 (Cross): 水平・垂直方向のみに作用。斜め方向の接続を保持したい場合に使用します。
OpenCV では cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) で 5x5 の矩形構造要素を生成します。サイズが大きいほど効果が強くなりますが、処理時間も増加します。
膨張 (Dilation) と収縮 (Erosion) - 2 つの基本演算
膨張と収縮はモルフォロジー演算の最も基本的な 2 つの操作で、他の全ての演算はこの 2 つの組み合わせで構成されます。二値画像における直感的な理解と、グレースケールでの動作を解説します。
膨張 (Dilation): 構造要素を画像上でスライドさせ、構造要素が前景ピクセルに 1 つでも重なる位置を全て前景とします。結果として、前景領域が構造要素のサイズ分だけ拡大します。
- 白い領域が膨らむ (拡大する)
- 黒い穴が埋まる (小さな穴が消える)
- 近接するオブジェクトが結合する
- ノイズ (小さな黒点) が除去される
OpenCV: dilated = cv2.dilate(img, kernel, iterations=1)
収縮 (Erosion): 構造要素を画像上でスライドさせ、構造要素が前景ピクセルに完全に含まれる位置のみを前景とします。結果として、前景領域が構造要素のサイズ分だけ縮小します。
- 白い領域が縮む (縮小する)
- 細い線や突起が消える
- 接触しているオブジェクトが分離する
- ノイズ (小さな白点) が除去される
OpenCV: eroded = cv2.erode(img, kernel, iterations=1)
グレースケールでの動作: グレースケール画像では、膨張は局所最大値フィルタ (各ピクセルを構造要素内の最大値に置換)、収縮は局所最小値フィルタ (最小値に置換) として動作します。明るい領域を拡大/縮小する効果があり、テクスチャ分析やエッジ検出の前処理に使用されます。
オープニングとクロージング - ノイズ除去と穴埋めの実践
オープニング (Opening) とクロージング (Closing) は、膨張と収縮を組み合わせた複合演算で、元のオブジェクトのサイズをほぼ保持しながらノイズ除去や形状の整形を行います。実務で最も頻繁に使用されるモルフォロジー演算です。
オープニング (Opening) = 収縮 → 膨張:
まず収縮で小さなノイズ (白い点) を除去し、次に膨張で元のオブジェクトサイズを復元します。結果として、構造要素より小さい前景ノイズが除去され、大きなオブジェクトはほぼ元のサイズを維持します。
opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
用途: 二値化後の小さなノイズ除去、文字認識 (OCR) の前処理、細胞画像の分離
クロージング (Closing) = 膨張 → 収縮:
まず膨張で小さな穴 (黒い点) を埋め、次に収縮で元のオブジェクトサイズを復元します。結果として、構造要素より小さい背景ノイズ (穴) が埋められ、オブジェクトの輪郭が滑らかになります。
closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
用途: オブジェクト内部の穴埋め、途切れた輪郭の接続、マスク画像の整形
反復適用の効果: オープニングやクロージングを複数回適用する (iterations パラメータを増やす) と、より大きなノイズや穴を処理できますが、オブジェクトの形状も変化します。大きなノイズを除去したい場合は、反復回数を増やすよりも構造要素のサイズを大きくする方が形状の保持に優れます。
オープニングとクロージングの組み合わせ: 実務では「オープニング → クロージング」の順で適用することが多く、これにより白ノイズと黒ノイズの両方を除去できます。逆順 (クロージング → オープニング) でも有効ですが、結果が若干異なります。
高度なモルフォロジー演算 - 勾配、トップハット、ブラックハット
基本演算の組み合わせから派生する高度なモルフォロジー演算は、エッジ検出、照明補正、テクスチャ抽出など、より専門的な画像処理タスクに活用されます。
モルフォロジー勾配 (Morphological Gradient): 膨張結果から収縮結果を減算した画像で、オブジェクトの輪郭 (エッジ) を抽出します。
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
Canny エッジ検出と異なり、閾値パラメータが不要で、構造要素のサイズのみで制御できるシンプルさが利点です。エッジの太さは構造要素のサイズに比例します。
トップハット (Top Hat) = 元画像 - オープニング:
オープニングで除去された小さな明るい構造 (ノイズや小さなオブジェクト) を抽出します。不均一な照明下での二値化前処理として非常に有効です。
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
用途: 不均一照明の補正 (背景の明暗ムラを除去)、微小な明るい構造の検出 (星、細胞核)、テクスチャの抽出
ブラックハット (Black Hat) = クロージング - 元画像:
クロージングで埋められた小さな暗い構造 (穴や暗い点) を抽出します。トップハットの逆で、暗い微細構造の検出に使用します。
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
用途: 暗い欠陥の検出 (製品検査)、血管の抽出 (眼底画像)、文字の抽出 (暗い文字 on 明るい背景)
照明補正への応用: 大きな構造要素 (画像サイズの 1/10 程度) でオープニングを適用すると、背景の照明パターンが推定されます。元画像からこの推定背景を減算すると、照明ムラが除去された均一な画像が得られます。スキャン画像や顕微鏡画像の前処理として広く使用されています。
実務での活用パターン - OCR、物体検出、医療画像
モルフォロジー演算は理論的な美しさだけでなく、実務の画像処理パイプラインで不可欠な役割を果たしています。代表的な活用パターンを具体的なコード例とともに紹介します。
OCR (文字認識) の前処理: スキャンされた文書画像から文字を認識する際、モルフォロジー演算で画像を整形します。(1) 適応的二値化で文字を抽出。(2) オープニングで小さなノイズ (紙の汚れ、スキャンノイズ) を除去。(3) クロージングで文字の途切れを接続。(4) 膨張で文字領域を検出し、バウンディングボックスを取得。Tesseract OCR の前処理として、この手順で認識精度が 10-20% 向上します。
接触オブジェクトの分離 (Watershed の前処理): 接触している細胞や粒子を個別に計数する場合、(1) 二値化。(2) オープニングで接触部分を細くする。(3) 距離変換 (cv2.distanceTransform) で各オブジェクトの中心を検出。(4) Watershed アルゴリズムで分離。この手順は細胞計数、粒度分析、コロニーカウントに使用されます。
マスク画像の整形: セグメンテーション (背景除去、物体検出) で得られたマスクは、エッジが粗かったり穴があったりします。クロージング → オープニングの順で適用し、(1) 内部の穴を埋め、(2) 外部のノイズを除去、(3) 輪郭を滑らかにします。構造要素サイズ 5x5〜11x11 が一般的です。
製品検査 (欠陥検出): 均一な表面の製品 (半導体ウェハー、ガラス、金属板) の欠陥を検出する場合、トップハット演算で微小な明るい欠陥 (傷、異物)、ブラックハット演算で暗い欠陥 (穴、凹み) を抽出します。検出感度は構造要素のサイズで制御し、検出したい最小欠陥サイズより若干大きい構造要素を使用します。
パフォーマンスと構造要素の設計 - 最適な実装のために
モルフォロジー演算の計算効率と、目的に応じた構造要素の設計方法を解説します。大量画像のバッチ処理やリアルタイムアプリケーションでの最適化ポイントを紹介します。
計算量と最適化: モルフォロジー演算の計算量は O(N × M) (N: ピクセル数、M: 構造要素のピクセル数) です。5x5 の構造要素で 1,920 × 1,080画像を処理する場合、約 5000 万回の比較演算が必要です。OpenCV の実装は SIMD 命令 (SSE/AVX) で最適化されており、CPU で約 3-5ms で処理可能です。
分解可能な構造要素: 矩形の構造要素は水平方向と垂直方向の 1 次元演算に分解できます。NxN の 2 次元演算を Nx1 + 1xN の 2 回の 1 次元演算に分解すると、計算量が O(N²) から O(2N) に削減されます。OpenCV は矩形構造要素に対してこの最適化を自動的に適用します。
構造要素サイズの選定基準:
- ノイズ除去: 除去したいノイズの最大サイズ + 1 ピクセル。3x3 で 1px のノイズ、5x5 で 2px のノイズを除去。
- 穴埋め: 埋めたい穴の最大サイズ + 1 ピクセル。
- オブジェクト分離: 接触部分の幅の 2 倍程度。
- 照明補正: 画像の短辺の 1/10〜1/5 程度の大きなサイズ。
カスタム構造要素の設計: 特定方向のエッジのみを処理したい場合、方向性のある構造要素を設計します。例えば水平線のみを検出する場合は横長の 1xN 構造要素、斜め 45 度の線を検出する場合は対角線上にのみ値を持つ構造要素を使用します。NumPy で任意形状の構造要素を作成できます。
GPU アクセラレーション: OpenCV の CUDA モジュールで GPU 上のモルフォロジー演算が利用可能です。4K 画像でも 1ms 以下で処理でき、リアルタイム動画処理に対応します。大量画像のバッチ処理では、GPU メモリに複数画像を転送してまとめて処理することで、転送オーバーヘッドを削減できます。