Cv2.CountNonZero の使い方【OpenCV/C#(OpenCvSharp)】〜非ゼロ画素を数える〜
Cv2.CountNonZero は、シングルチャンネル画像の中で値が 0 でない画素の数を返す関数です。二値マスクの面積確認・差分検出・異物検査など、「白画素がいくつあるか」を把握したい場面で頻繁に使います。
int nonZeroCount = Cv2.CountNonZero(mask);
動作環境
- OpenCV 4.x(OpenCvSharp4)
- .NET 8 コンソールアプリ
- NuGet:
OpenCvSharp4+OpenCvSharp4.runtime.win(Windows 実行時)
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
using OpenCvSharp;
// グレースケール画像を生成して閾値処理し、白画素数をカウントする
using var src = new Mat(new Size(400, 400), MatType.CV_8UC1, Scalar.All(0));
// 中心に白い矩形を描画
src.Rectangle(new Rect(100, 100, 200, 200), Scalar.White, -1);
// 閾値処理(今回はすでに2値だが、念のため適用)
using var binary = new Mat();
Cv2.Threshold(src, binary, 127, 255, ThresholdTypes.Binary);
// 非ゼロ画素をカウント
int count = Cv2.CountNonZero(binary);
Console.WriteLine($"非ゼロ画素数: {count}");
Console.WriteLine($"期待値(200×200): {200 * 200}");
実行すると以下が出力されます。
非ゼロ画素数: 40000
期待値(200×200): 40000
行ごとの解説
new Mat(...)/src.Rectangle(...)— 400×400 のゼロ画像に 200×200 の白矩形を描画してテスト用 Mat を作成しています。Cv2.Threshold(...)— 入力が既に 2値でも、処理パイプラインとしてセットで使うことが多いため入れています。Cv2.CountNonZero(binary)— 0 以外の画素数をintで返します。シングルチャンネルの Mat のみ受け付ける点に注意。using var—MatはIDisposableなので必ずusingで解放します。
引数と戻り値
| 項目 | 型 | 説明 |
|---|---|---|
src(第1引数) |
Mat |
入力画像。シングルチャンネル(CV_8UC1 等)のみ有効 |
| 戻り値 | int |
値が 0 でない画素の総数 |
⚠️ マルチチャンネル画像(CV_8UC3 等)を渡すと OpenCvSharpException が発生します。カラー画像は Cv2.CvtColor でグレースケールに変換するか、チャンネルを分離してから渡してください。
実践例
1. 色抽出マスクの面積確認
HSV 色空間で特定色を抽出した後、マスクの面積(白画素数)が閾値以上かどうかで「色が見つかったか」を判定するパターンです。
using OpenCvSharp;
// カメラや画像ファイルの代わりにサンプル画像を生成
using var src = new Mat(new Size(640, 480), MatType.CV_8UC3, new Scalar(30, 180, 200));
// HSV変換
using var hsv = new Mat();
Cv2.CvtColor(src, hsv, ColorConversionCodes.BGR2HSV);
// 黄緑〜黄色の範囲でマスク生成
using var mask = new Mat();
Cv2.InRange(hsv, new Scalar(20, 100, 100), new Scalar(40, 255, 255), mask);
int area = Cv2.CountNonZero(mask);
Console.WriteLine($"検出面積: {area} px");
// 全画素の5%以上あれば「検出」と判断
double ratio = (double)area / (640 * 480);
Console.WriteLine(ratio >= 0.05 ? "✅ 色を検出" : "色なし");
Cv2.InRange の詳細はCv2.InRange の使い方【OpenCV/C#(OpenCvSharp)】〜色範囲でマスクを作る(色抽出)〜を参照してください。
2. フレーム差分による動体検出
2 枚のフレームの差分画像に対して CountNonZero を使い、変化画素数が閾値を超えたら「動きあり」と判定します。
using OpenCvSharp;
// 静止フレームと変化フレームをシミュレート
using var frame1 = new Mat(new Size(640, 480), MatType.CV_8UC3, new Scalar(100, 100, 100));
using var frame2 = frame1.Clone();
// frame2 に矩形(動体)を追加
frame2.Rectangle(new Rect(200, 150, 80, 80), new Scalar(200, 200, 200), -1);
// グレースケール変換
using var gray1 = new Mat();
using var gray2 = new Mat();
Cv2.CvtColor(frame1, gray1, ColorConversionCodes.BGR2GRAY);
Cv2.CvtColor(frame2, gray2, ColorConversionCodes.BGR2GRAY);
// 差分 → 閾値処理
using var diff = new Mat();
using var diffBin = new Mat();
Cv2.Absdiff(gray1, gray2, diff);
Cv2.Threshold(diff, diffBin, 30, 255, ThresholdTypes.Binary);
int changedPixels = Cv2.CountNonZero(diffBin);
Console.WriteLine($"変化画素数: {changedPixels}");
Console.WriteLine(changedPixels > 500 ? "✅ 動きを検出" : "動きなし");
変化画素数: 6400
✅ 動きを検出
つまずきポイント
⚠️ マルチチャンネル Mat を渡すと例外
Cv2.CountNonZero はシングルチャンネルの Mat のみ対応しています。BGR 画像をそのまま渡すと実行時に例外が発生します。
// NG: CV_8UC3 の Mat を直接渡す
int n = Cv2.CountNonZero(bgrMat); // → OpenCvSharpException
// OK: グレースケールに変換してから渡す
Cv2.CvtColor(bgrMat, grayMat, ColorConversionCodes.BGR2GRAY);
int n = Cv2.CountNonZero(grayMat);
⚠️ Mat の Dispose 漏れによるネイティブメモリリーク
Cv2.Threshold や Cv2.Absdiff などで生成した中間 Mat を using で解放しないと、ネイティブヒープが増え続けます。ループ処理内では特に注意が必要です。処理件数が多い場合は using ブロックをループの内側に置いて確実に解放してください。
// ループ内では using をループの内側に
for (int i = 0; i < frames.Length; i++)
{
using var diff = new Mat();
using var bin = new Mat();
Cv2.Absdiff(frames[i], reference, diff);
Cv2.Threshold(diff, bin, 30, 255, ThresholdTypes.Binary);
int count = Cv2.CountNonZero(bin);
}
⚠️ 全画素ゼロのケースで 0 が返る(null ではない)
マスクや差分が空(全黒)の場合、例外ではなく 0 が返ります。「検出なし」と「エラー」を区別するために、呼び出し側で count == 0 のハンドリングを明示的に書くようにしましょう。
関連する関数
- Cv2.InRange の使い方【OpenCV/C#(OpenCvSharp)】〜色範囲でマスクを作る(色抽出)〜 — CountNonZero と組み合わせて色検出の面積評価に使います
- Cv2.ConnectedComponentsWithStats の使い方【OpenCV/C#(OpenCvSharp)】〜ラベリング処理で連結領域を解析する〜 — 白画素の面積だけでなく、連結した領域ごとに分析したい場合に使います
- Cv2.CalcHist の使い方【OpenCV/C#(OpenCvSharp)】〜ヒストグラムを計算する〜 — 画素値の分布全体を把握したい場合は CountNonZero より CalcHist が適しています
Cv2.Absdiff— フレーム差分の生成に使います(上記実践例参照)Cv2.Threshold— CountNonZero の前処理として二値化に使います
まとめ
Cv2.CountNonZero は1行で非ゼロ画素数を取得できる軽量な関数です。シングルチャンネル限定という制約を守れば、マスク面積の確認・差分検出・合否判定のしきい値比較といった実務用途に広く使えます。処理パイプラインの中で「何画素残ったか」を素早く確認したいときにまず使う関数として覚えておきましょう。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

