Cv2.Canny の使い方【OpenCV/C#(OpenCvSharp)】〜エッジ検出で輪郭を抽出する〜
Cv2.Canny は、画像からエッジ(輪郭)を検出する OpenCV の代表的な関数です。ヒステリシスしきい値を使った Canny エッジ検出アルゴリズムを 1 行で呼び出せます。
Cv2.Canny(src, dst, threshold1: 50, threshold2: 150);
動作環境
- OpenCV 4.x(OpenCvSharp4)
- .NET 8 コンソールアプリ(トップレベルステートメント)
- NuGet:
OpenCvSharp4+OpenCvSharp4.runtime.win(Windows 実行時)
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
using OpenCvSharp;
// 入力画像を読み込む
using var src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像を読み込めませんでした");
// Canny エッジ検出(しきい値 50/150 はよく使われる出発点)
using var edges = new Mat();
Cv2.Canny(src, edges, threshold1: 50, threshold2: 150);
// 結果を保存
Cv2.ImWrite("edges.png", edges);
Console.WriteLine("エッジ画像を edges.png に保存しました");
実行結果
エッジ画像を edges.png に保存しました
edges.png を開くと、白いラインとして輪郭が抽出されたグレースケール画像が得られます。
各行の解説
| 行 | ポイント |
|---|---|
ImRead(..., Grayscale) |
Canny はグレースケール入力を受け取る。カラー画像を渡すとエラーになる |
threshold1: 50 |
弱いエッジの下限しきい値。これを下回るエッジは除外される |
threshold2: 150 |
強いエッジの上限しきい値。これを超えるエッジは確実に採用される |
edges |
出力は 8bit シングルチャンネル(グレースケール)の Mat |
引数と戻り値
Cv2.Canny(Mat src, Mat dst, double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false)
| 引数 | 型 | 説明 |
|---|---|---|
src |
Mat |
入力画像(8bit グレースケール) |
dst |
Mat |
出力エッジ画像(src と同サイズ・8bit 1ch) |
threshold1 |
double |
ヒステリシスの低しきい値 |
threshold2 |
double |
ヒステリシスの高しきい値 |
apertureSize |
int |
Sobel フィルタのカーネルサイズ(3/5/7、省略可) |
L2gradient |
bool |
true にすると L2 ノルムでグラジェント計算(精度向上・省略可) |
戻り値はありません(dst に結果が書き込まれます)。
実践例
実践例 1: ガウシアンぼかしでノイズを除去してからエッジ検出
Canny は微分演算を使うため、ノイズに敏感です。事前にぼかしを入れることで不要なエッジを抑制できます。
using OpenCvSharp;
using var src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像を読み込めませんでした");
// ノイズ除去のためガウシアンぼかしを前処理として適用
using var blurred = new Mat();
Cv2.GaussianBlur(src, blurred, new Size(5, 5), sigmaX: 0);
// ぼかし後にエッジ検出
using var edges = new Mat();
Cv2.Canny(blurred, edges, threshold1: 50, threshold2: 150);
Cv2.ImWrite("edges_blurred.png", edges);
Console.WriteLine("前処理ありのエッジ画像を保存しました");
ガウシアンぼかしの詳細はCv2.GaussianBlur の使い方【OpenCV/C#(OpenCvSharp)】〜ガウシアンぼかしで画像を平滑化する〜を参照してください。
実践例 2: カラー画像からエッジを検出してオーバーレイ表示
カラー画像を読み込み、エッジを赤色で元画像に重ねて保存します。
using OpenCvSharp;
// カラーで読み込み
using var colorSrc = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (colorSrc.Empty()) throw new Exception("画像を読み込めませんでした");
// グレースケールに変換して Canny に渡す
using var gray = new Mat();
Cv2.CvtColor(colorSrc, gray, ColorConversionCodes.BGR2GRAY);
using var blurred = new Mat();
Cv2.GaussianBlur(gray, blurred, new Size(5, 5), sigmaX: 0);
using var edges = new Mat();
Cv2.Canny(blurred, edges, threshold1: 50, threshold2: 150);
// エッジ部分を赤色で元画像に重ねる
using var overlay = colorSrc.Clone();
overlay.SetTo(new Scalar(0, 0, 255), edges); // edges をマスクとして使用
Cv2.ImWrite("overlay.png", overlay);
Console.WriteLine("オーバーレイ画像を overlay.png に保存しました");
Mat.SetTo(value, mask) の第 2 引数にエッジ画像を渡すことで、エッジのピクセルのみを赤に塗り替えられます。
しきい値の選び方
threshold1 と threshold2 の比率は 1:2 〜 1:3 が一般的な目安です(Canny 本人の推奨比)。
| 用途 | threshold1 | threshold2 |
|---|---|---|
| 細かいエッジまで拾う | 30 | 90 |
| 標準的な設定(出発点) | 50 | 150 |
| 太く明確なエッジのみ | 100 | 200 |
⚠️ 画像の明るさや被写体によって最適値は変わるため、実際の画像で試しながら調整してください。
つまずきポイント
⚠️ カラー画像をそのまま渡すとエラーになる
Canny はグレースケール(8bit 1ch)の入力を要求します。カラー画像(3ch)を渡すと実行時例外が発生します。Cv2.CvtColor で BGR2GRAY に変換してから渡してください。
// NG: カラー画像をそのまま渡す
Cv2.Canny(colorMat, edges, 50, 150); // → 例外
// OK: グレースケールに変換してから渡す
Cv2.CvtColor(colorMat, gray, ColorConversionCodes.BGR2GRAY);
Cv2.Canny(gray, edges, 50, 150);
⚠️ Mat の Dispose 漏れに注意
new Mat() で生成した中間画像(blurred、edges など)は using で解放してください。解放しないとネイティブメモリがリークします。Canny のように複数の中間 Mat を扱うコードほど注意が必要です。
⚠️ しきい値の大小が逆だと全エッジが消える
threshold1 > threshold2 になるよう渡してもエラーにはなりませんが、ほとんどのエッジが弱エッジとして棄却され、真っ黒な画像が出力されます。必ず threshold1 < threshold2 になっているか確認してください。
関連する関数
- Cv2.GaussianBlur — Canny の前処理として最も相性の良いぼかし。詳細はCv2.GaussianBlur の使い方【OpenCV/C#(OpenCvSharp)】〜ガウシアンぼかしで画像を平滑化する〜を参照。
- Cv2.BilateralFilter — エッジを残しながらノイズを除去したい場合の前処理に有効。詳細はCv2.BilateralFilter の使い方【OpenCV/C#(OpenCvSharp)】バイラテラルフィルタで輪郭を残してぼかすを参照。
- Cv2.Threshold / Cv2.AdaptiveThreshold — エッジではなく明度で輪郭を抽出したい場合の代替手段。
- Cv2.FindContours — Canny で得たエッジ画像を輪郭座標として取り出す次の処理ステップ。
まとめ
Cv2.Canny は threshold1・threshold2 の 2 つのしきい値を指定するだけで実用的なエッジ検出が行えます。ノイズに弱い性質があるため、Cv2.GaussianBlur による前処理をセットで使うのが現場のセオリーです。カラー画像はグレースケール変換を忘れずに行い、using による Mat の解放を徹底することで安定したコードになります。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

