cv::filter2D の使い方【OpenCV/C++】〜任意カーネルで畳み込みフィルタを適用する〜

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

cv::filter2D の使い方【OpenCV/C++】〜任意カーネルで畳み込みフィルタを適用する〜

cv::filter2D は、任意のカーネル行列を指定して画像に畳み込みフィルタを適用する関数です。シャープナー・エッジ検出・独自ノイズ除去フィルタなど、標準関数では対応できない処理を1行で実装できます。

cv::filter2D(src, dst, ddepth, 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("input.jpg");
    if (src.empty()) {
        std::cerr << "画像の読み込みに失敗しました" << std::endl;
        return -1;
    }

    // シャープニングカーネルの定義(3x3)
    cv::Mat kernel = (cv::Mat_<float>(3, 3) <<
         0, -1,  0,
        -1,  5, -1,
         0, -1,  0);

    cv::Mat dst;
    // ddepth = -1 で入力と同じビット深度を維持
    cv::filter2D(src, dst, -1, kernel);

    cv::imwrite("output.jpg", dst);
    std::cout << "完了: output.jpg に保存しました" << std::endl;

    return 0;
}

実行結果:

完了: output.jpg に保存しました

エッジが強調されたシャープな画像が output.jpg に保存されます。

行ごとの解説

内容
cv::Mat_<float>(3, 3) << ... 3×3 の float カーネルをインライン定義
cv::filter2D(src, dst, -1, kernel) ddepth=-1 で出力型を入力と同じにする
cv::imwrite 結果を画像ファイルに保存

引数と戻り値

void cv::filter2D(
    InputArray  src,
    OutputArray dst,
    int         ddepth,
    InputArray  kernel,
    cv::Point   anchor   = cv::Point(-1,-1),
    double      delta    = 0,
    int         borderType = cv::BORDER_DEFAULT
);
引数 説明
src InputArray 入力画像
dst OutputArray 出力画像(src と同サイズ)
ddepth int 出力のビット深度。-1 で入力と同じ
kernel InputArray 畳み込みカーネル(単チャンネルの浮動小数点 Mat)
anchor cv::Point カーネル内のアンカー点。(-1,-1) でカーネル中心
delta double 畳み込み結果に加算するオフセット値
borderType int 境界処理方法(BORDER_DEFAULT / BORDER_REPLICATE 等)

戻り値: なし(dst に結果が書き込まれる)


実践例

例1: 平均ブラー(ボックスフィルタ)を手動実装

cv::blur と同等の処理をカーネルで表現する例です。カーネルの仕組みを理解するのに役立ちます。

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

int main() {
    cv::Mat src = cv::imread("input.jpg");
    if (src.empty()) {
        std::cerr << "画像の読み込みに失敗しました" << std::endl;
        return -1;
    }

    // 5x5 均一カーネル(平均ブラー相当)
    int ksize = 5;
    cv::Mat kernel = cv::Mat::ones(ksize, ksize, CV_32F) / (float)(ksize * ksize);

    cv::Mat dst;
    cv::filter2D(src, dst, -1, kernel);

    cv::imwrite("blur_output.jpg", dst);
    std::cout << "平均ブラー完了: blur_output.jpg" << std::endl;

    return 0;
}
平均ブラー完了: blur_output.jpg

例2: エンボス(浮き彫り)フィルタ

標準関数には存在しない独自フィルタの例です。delta=128 でグレーを基準としてエッジを浮き彫りにします。

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

int main() {
    cv::Mat src = cv::imread("input.jpg");
    if (src.empty()) {
        std::cerr << "画像の読み込みに失敗しました" << std::endl;
        return -1;
    }

    // エンボスカーネル
    cv::Mat kernel = (cv::Mat_<float>(3, 3) <<
        -2, -1,  0,
        -1,  1,  1,
         0,  1,  2);

    cv::Mat dst;
    // delta=128: 出力にオフセットを加えてグレー基準にする
    cv::filter2D(src, dst, -1, kernel, cv::Point(-1, -1), 128.0);

    cv::imwrite("emboss_output.jpg", dst);
    std::cout << "エンボス完了: emboss_output.jpg" << std::endl;

    return 0;
}
エンボス完了: emboss_output.jpg

浮き彫り調のグレースケール風画像が出力されます。カラー画像のまま適用しても動作します。


つまずきポイント

⚠️ カーネルの型は CV_32F または CV_64F にする

カーネルを CV_8U など整数型で定義すると、実行時に assertion エラーが発生します。

// NG: 整数型カーネル
cv::Mat kernel = (cv::Mat_<uchar>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
// ↑ cv::filter2D に渡すと assertion failed が出る

// OK: float 型カーネル
cv::Mat kernel = (cv::Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);

⚠️ ddepth=-1 とカーネル係数の組み合わせに注意

入力が CV_8U(一般的な8ビット画像)の場合、ddepth=-1 では出力も CV_8U になります。カーネルの係数の合計が1より大きい場合、飽和(値のクリッピング)が発生して白飛びや黒潰れが起きます。正規化されていないカーネルを使う際は ddepth=CV_16SCV_32F を指定して精度を確保してください。

// エッジ検出などで出力が負になり得る場合は CV_16S を指定
cv::filter2D(src, dst, CV_16S, kernel);

⚠️ src と dst が同じ変数でも動作するが推奨しない

cv::filter2D(img, img, -1, kernel) のように in-place 指定は OpenCV 内部でコピーされるため結果は正しく得られますが、メモリ効率の観点から別変数を用意するほうが安全です。


関連する関数

cv::filter2D は汎用ですが、特定用途には最適化済みの専用関数を使う方が効率的です。

  • cv::GaussianBlur — ガウシアンカーネルの畳み込み専用
  • cv::Sobel — Sobelカーネルによるエッジ検出専用
  • cv::matchTemplate — 画像全体に対するテンプレートの相関演算。カーネルが入力画像と同オーダーのサイズになる場合はこちら → cv::matchTemplate の使い方【OpenCV/C++】

まとめ

  • cv::filter2D はカーネル行列を自由に定義して畳み込みを行う汎用フィルタ関数です。
  • カーネルは必ず CV_32F または CV_64F で定義し、ddepth は出力精度に合わせて選択してください。
  • 標準フィルタで対応できない独自処理や実験的なカーネルを試す際に特に有効です。

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

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

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

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