cv::medianBlur の使い方【OpenCV/C++】〜メディアンフィルタで塩胡椒ノイズを除去する〜
cv::medianBlur は、注目ピクセルの周辺領域を中央値(メジアン)で置き換えるフィルタです。塩胡椒ノイズ(ランダムな白/黒点ノイズ)の除去に特に効果的で、ガウシアンフィルタと異なりエッジをある程度保持しやすい特性があります。
cv::medianBlur(src, dst, ksize);
動作環境
- OpenCV 4.x
- C++17
- ビルド例:
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.png");
if (src.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return -1;
}
cv::Mat dst;
// カーネルサイズ 5 のメディアンフィルタを適用
cv::medianBlur(src, dst, 5);
cv::imwrite("output.png", dst);
std::cout << "保存完了: output.png" << std::endl;
return 0;
}
実行結果
保存完了: output.png
output.png を確認すると、元画像に含まれていた白/黒の点状ノイズが取り除かれた画像が得られます。カーネルサイズを大きくするほどぼかし効果が強まります。
各行の解説
cv::imread("input.png")— 画像をBGR形式で読み込みます。読み込み失敗時はempty()で必ず確認します(cv::imread の詳細はこちら)。cv::medianBlur(src, dst, 5)— カーネルサイズ5(5×5の近傍)でメディアンフィルタを適用します。cv::imwrite— フィルタ後の画像をファイルに保存します。
引数と戻り値
| 引数 | 型 | 説明 |
|---|---|---|
src |
cv::InputArray |
入力画像。1・3・4チャンネルの CV_8U、または ksize==1 時に限り CV_16U / CV_32F も可 |
dst |
cv::OutputArray |
出力画像(src と同じサイズ・型) |
ksize |
int |
カーネルサイズ(奇数・1以上。1のとき処理なしと同等) |
戻り値: なし(void)
⚠️ ksize は 奇数でなければなりません(1・3・5・7…)。偶数を渡すと実行時に assertion エラーが発生します。
実践例
1. 塩胡椒ノイズの除去
実務でよくあるパターンとして、スキャン画像やカメラ映像に混入した塩胡椒ノイズをメディアンフィルタで除去します。ガウシアンフィルタと並べて比較できるサンプルです。
#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 dst_median, dst_gaussian;
// メディアンフィルタ(塩胡椒ノイズに強い)
cv::medianBlur(src, dst_median, 5);
// ガウシアンフィルタ(比較用)
cv::GaussianBlur(src, dst_gaussian, cv::Size(5, 5), 0);
cv::imwrite("result_median.png", dst_median);
cv::imwrite("result_gaussian.png", dst_gaussian);
std::cout << "保存完了: result_median.png / result_gaussian.png" << std::endl;
return 0;
}
保存完了: result_median.png / result_gaussian.png
result_median.png ではノイズの白/黒点がほぼ消え、エッジ付近のシャープさが result_gaussian.png より保たれているのが確認できます。
2. 動画フレームへのリアルタイム適用
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
cv::VideoCapture cap(0); // デフォルトカメラ
if (!cap.isOpened()) {
std::cerr << "カメラを開けませんでした" << std::endl;
return -1;
}
cv::Mat frame, dst;
while (true) {
cap >> frame;
if (frame.empty()) break;
// カーネルサイズ 3(速度優先のリアルタイム処理)
cv::medianBlur(frame, dst, 3);
cv::imshow("MedianBlur", dst);
if (cv::waitKey(1) == 'q') break;
}
return 0;
}
(カメラウィンドウが開き、フィルタ適用済み映像がリアルタイムで表示されます。q キーで終了)
ksize=3 はリアルタイム処理での現実的な選択肢です。ksize を上げるほど計算コストが増加するため、用途に合わせて調整してください。
つまずきポイント
⚠️ ksize に偶数を渡すと実行時エラー
cv::medianBlur の ksize は奇数のみ有効です。
// NG: 偶数は assertion エラー
cv::medianBlur(src, dst, 4);
// OK: 奇数
cv::medianBlur(src, dst, 5);
実行時に OpenCV Error: Assertion failed (ksize % 2 == 1) のようなメッセージが出た場合はここを確認してください。
⚠️ 入力画像の型制約
cv::medianBlur が受け付ける型は ksize によって変わります。
ksize == 1→CV_8U/CV_16U/CV_32F(1・3・4ch)ksize >= 3→CV_8Uのみ(1・3・4ch)
CV_16U や CV_32F のまま ksize=5 などで渡すと assertion エラーになります。CV_32F の画像を処理したい場合は、いったん CV_8U に変換してからフィルタを適用するか、cv::bilateralFilter など別のフィルタを検討してください。
// CV_32F を CV_8U に変換してから適用する例
src.convertTo(src8u, CV_8U, 255.0);
cv::medianBlur(src8u, dst, 5);
⚠️ Windows 環境でのリンクエラー
Visual Studio で LNK2019 / unresolved external symbol が出る場合、opencv_imgproc モジュールが含まれていない可能性があります。opencv_world を使うとモジュール管理が楽になります(opencv_world の使い方とリンク方法【OpenCV/C++ Windows】を参照)。Debug/Release・x64/x86 の取り違えも必ず確認してください。
関連する関数
cv::GaussianBlur— ガウシアンフィルタ。ランダムノイズ全般に広く使われるcv::blur— 単純な平均フィルタ。軽量だがノイズ除去性能は低めcv::bilateralFilter— エッジ保持に最も優れたフィルタ。ただし処理速度はメディアンより遅い
まとめ
cv::medianBlur(src, dst, ksize)で塩胡椒ノイズを効果的に除去できる。ksizeは奇数必須・ksize>=3のとき入力はCV_8Uのみ対応。- エッジを保持しながらノイズを除くため、ガウシアンフィルタより塩胡椒ノイズへの効果が高い。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

