cv::erode / cv::dilate の使い方【OpenCV/C++】〜収縮・膨張処理の基本と実践〜

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

cv::erode / cv::dilate の使い方【OpenCV/C++】〜収縮・膨張処理の基本と実践〜

cv::erode は画像を収縮(エロージョン)、cv::dilate は膨張(ダイレーション)する関数です。二値画像のノイズ除去や輪郭の強調、文字認識前処理など、画像処理の実務で日常的に使います。最小限の呼び出しは次のとおりです。

cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::erode(src, dst, kernel);   // 収縮
cv::dilate(src, dst, kernel);  // 膨張

動作環境

  • OpenCV 4.x
  • コンパイル例: g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4)

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


基本の使い方

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // グレースケールで読み込み
    cv::Mat src = cv::imread("sample.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    // 大津法で二値化
    cv::Mat binary;
    cv::threshold(src, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    // 3×3 の矩形カーネルを作成
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));

    // 収縮(erode)
    cv::Mat eroded;
    cv::erode(binary, eroded, kernel);

    // 膨張(dilate)
    cv::Mat dilated;
    cv::dilate(binary, dilated, kernel);

    cv::imwrite("eroded.png", eroded);
    cv::imwrite("dilated.png", dilated);

    std::cout << "保存完了: eroded.png / dilated.png" << std::endl;
    return 0;
}

実行結果:

保存完了: eroded.png / dilated.png

実行すると、収縮処理が適用された eroded.png(白い領域が一回り小さくなった画像)と、膨張処理が適用された dilated.png(白い領域が一回り大きくなった画像)が出力されます。

コード解説

行の処理 ポイント
cv::IMREAD_GRAYSCALE モルフォロジー処理はグレースケール/二値画像で使うことが多い
cv::THRESH_OTSU 手動で閾値を決めずに済む。照明が安定しない環境でも有効
cv::getStructuringElement カーネル(構造要素)を生成する専用関数。手書きの Mat より推奨
cv::erode カーネル内の最小値をピクセルに適用→白領域が縮む
cv::dilate カーネル内の最大値をピクセルに適用→白領域が広がる

引数と戻り値

cv::erode / cv::dilate 共通シグネチャ

void cv::erode(
    InputArray  src,          // 入力画像
    OutputArray dst,          // 出力画像
    InputArray  kernel,       // 構造要素(カーネル)
    cv::Point   anchor  = cv::Point(-1, -1),  // アンカー位置(-1,-1 で中心)
    int         iterations = 1,               // 繰り返し回数
    int         borderType = cv::BORDER_CONSTANT, // 境界処理の種類
    const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue() // 境界値
);

cv::dilate もシグネチャは同じです。

引数 説明
src InputArray 入力画像。チャンネル数は問わない(各チャンネルに独立して適用)
dst OutputArray 出力画像。src と同サイズ・同型
kernel InputArray 構造要素。cv::getStructuringElement で生成するのが定石
anchor cv::Point カーネル内のアンカー位置。(-1, -1) で中心
iterations int 処理の繰り返し回数。2 以上でより強い効果
borderType int 境界ピクセルの扱い方

cv::getStructuringElement

cv::Mat cv::getStructuringElement(
    int         shape,  // MORPH_RECT / MORPH_ELLIPSE / MORPH_CROSS
    cv::Size    ksize,  // カーネルサイズ
    cv::Point   anchor = cv::Point(-1, -1)
);
shape の選択肢 用途
cv::MORPH_RECT 矩形。最も一般的
cv::MORPH_ELLIPSE 楕円形。丸みのある形状に適する
cv::MORPH_CROSS 十字形。縦横方向のみに作用させたいとき

実践例

1. 塩胡椒ノイズの除去(オープニング処理)

収縮→膨張の順に適用する「オープニング」は、細かい白ノイズ(孤立した白点)の除去に有効です。cv::morphologyEx で一発で書けます。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat src = cv::imread("noisy.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    cv::Mat binary;
    cv::threshold(src, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    // オープニング = erode → dilate
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
    cv::Mat opened;
    cv::morphologyEx(binary, opened, cv::MORPH_OPEN, kernel);

    cv::imwrite("opened.png", opened);
    std::cout << "オープニング完了: opened.png" << std::endl;
    return 0;
}

実行すると、opened.png に細かな白ノイズが除去された二値画像が出力されます。メディアンフィルタ(cv::medianBlur)と用途が近いですが、オープニングは二値化後の後処理に向いており、グレースケールのノイズ除去には medianBlur が適しています。

2. 文字の太さを変える(iterations の活用)

OCR 前処理で文字が細すぎる場合、iterations を増やして太らせると認識率が上がることがあります。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat src = cv::imread("text.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    cv::Mat binary;
    // 文字が黒・背景が白の場合は THRESH_BINARY_INV を使う
    cv::threshold(src, binary, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);

    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));

    // 2回膨張して文字を太らせる
    cv::Mat thick;
    cv::dilate(binary, thick, kernel, cv::Point(-1, -1), 2);

    cv::imwrite("thickened.png", thick);
    std::cout << "太字化完了: thickened.png" << std::endl;
    return 0;
}

実行すると、文字領域が2段階膨張した thickened.png が出力されます。iterations を変えるだけでカーネルを大きくするより細かくコントロールできます。


つまずきポイント

⚠️ カーネルサイズは奇数が基本

cv::getStructuringElement に偶数サイズを渡してもエラーにはなりません。しかしアンカー(中心点)がずれ、意図しない方向に処理が偏ります。3×3 / 5×5 / 7×7 など奇数サイズを使うのが原則です。

⚠️ 白・黒の定義に注意する

cv::erode は「白(前景)が縮む」処理です。二値化したとき、注目対象が黒で背景が白の画像では効果が逆になります。対象が黒い画像には cv::THRESH_BINARY_INV で反転して処理するか、cv::dilatecv::erode を入れ替えてください。

⚠️ カラー画像に適用したときの挙動

cv::erode / cv::dilate はカラー画像(CV_8UC3)にも適用できますが、チャンネルが独立して処理されます。自然画像に使うと色が変色したように見える場合があります。モルフォロジー処理が目的ならグレースケール or 二値化後に適用するのが実務の定石です。


関連する関数


まとめ

  • cv::erode で白領域を縮小、cv::dilate で白領域を拡大する。カーネルは cv::getStructuringElement で生成するのが基本。
  • iterations を増やすことでカーネルを大きくせずに効果を段階的に強められる。
  • ノイズ除去や前処理で erode → dilate(オープニング)の組み合わせが頻出。複合操作は cv::morphologyEx を使うとコードがシンプルになる。

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

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

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