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_16S や CV_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)を開発しています。顔認証システムへの組み込み実績多数。

