Cv2.InRange の使い方【OpenCV/C#(OpenCvSharp)】〜色範囲でマスクを作る(色抽出)〜

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

Cv2.InRange は、画像の各ピクセルが指定した色範囲(下限〜上限)に収まるかどうかを判定し、マスク画像(2値)を生成する関数です。HSV 色空間と組み合わせることで、照明変化に強い色抽出が1行で実装できます。

Cv2.InRange(src, lowerBound, upperBound, dst);

動作環境

  • OpenCV 4.x(OpenCvSharp4)
  • .NET 8 コンソールアプリケーション
  • NuGet: OpenCvSharp4 + OpenCvSharp4.runtime.win(Windows 実行時)

環境構築がまだの方は環境構築ガイドを先にどうぞ。


基本の使い方

まず、BGR 画像を HSV に変換してから Cv2.InRange で色範囲マスクを生成する基本例を示します。ここでは「赤色」を抽出します。

using OpenCvSharp;

// --- 動作確認用のサンプル画像を生成(赤・緑・青の矩形)
using var canvas = new Mat(300, 600, MatType.CV_8UC3, Scalar.White);
Cv2.Rectangle(canvas, new Rect(0,   0, 200, 300), new Scalar(0, 0, 220), -1); // 赤
Cv2.Rectangle(canvas, new Rect(200, 0, 200, 300), new Scalar(0, 200, 0), -1); // 緑
Cv2.Rectangle(canvas, new Rect(400, 0, 200, 300), new Scalar(200, 0, 0), -1); // 青

// BGR → HSV 変換
using var hsv = new Mat();
Cv2.CvtColor(canvas, hsv, ColorConversionCodes.BGR2HSV);

// 赤色の HSV 範囲(色相が 0 付近)
// 赤は色相が 0〜10 と 170〜180 にまたがるため 2 範囲を OR する
using var mask1 = new Mat();
using var mask2 = new Mat();
using var mask  = new Mat();

Cv2.InRange(hsv, new Scalar(0,   120, 120), new Scalar(10,  255, 255), mask1);
Cv2.InRange(hsv, new Scalar(170, 120, 120), new Scalar(180, 255, 255), mask2);
Cv2.BitwiseOr(mask1, mask2, mask); // 2 つの範囲を合算

// マスクを元画像に適用して赤色領域だけ抽出
using var result = new Mat();
Cv2.BitwiseAnd(canvas, canvas, result, mask);

Cv2.ImWrite("mask.png",   mask);
Cv2.ImWrite("result.png", result);

Console.WriteLine("mask.png / result.png を出力しました");

実行すると mask.png(赤色領域が白、それ以外が黒の2値画像)と result.png(赤色領域のみ残った画像)が出力されます。

mask.png / result.png を出力しました

コードの要点

行の処理 説明
CvtColor(BGR2HSV) 色抽出前に HSV へ変換。BGR のまま扱うより照明変化に強くなる
InRange(hsv, lower, upper, mask1) 各ピクセルが範囲内なら 255、範囲外なら 0 のマスクを生成
2 範囲の OR 赤色は HSV の色相が 0〜10 と 170〜180 に分かれるため両方を取得してから合算
BitwiseAnd(..., mask) マスクを使って元画像から該当領域のみ切り出す

引数と戻り値

Cv2.InRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);
引数 型 説明
src InputArray 入力画像(チャンネル数は任意)
lowerb InputArray 各チャンネルの下限値(Scalar を渡すのが一般的)
upperb InputArray 各チャンネルの上限値(Scalar を渡すのが一般的)
dst OutputArray 出力マスク(CV_8UC1・範囲内 = 255、範囲外 = 0)

戻り値は void。結果は dst に書き込まれます。

⚠️ lowerb と upperb はチャンネル数が src と一致している必要があります。3チャンネル画像なら new Scalar(H, S, V) のように3値を指定してください。


実践例

実践例 1: 緑色オブジェクトを検出して外接矩形を描画

色抽出で得たマスクを輪郭検出に渡せば、オブジェクトの位置・サイズを取得できます。
Cv2.BoundingRect の使い方と組み合わせると、色ベースのオブジェクト検出が簡単に実装できます。

using OpenCvSharp;

// サンプル画像(緑の円)
using var canvas = new Mat(400, 400, MatType.CV_8UC3, Scalar.White);
Cv2.Circle(canvas, new Point(200, 200), 100, new Scalar(0, 200, 50), -1);

// HSV 変換 → 緑色抽出
using var hsv  = new Mat();
using var mask = new Mat();
Cv2.CvtColor(canvas, hsv, ColorConversionCodes.BGR2HSV);
Cv2.InRange(hsv, new Scalar(40, 100, 100), new Scalar(80, 255, 255), mask);

// 輪郭検出 → 外接矩形
Cv2.FindContours(mask, out Point[][] contours, out _,
    RetrievalModes.External, ContourApproximationModes.ApproxSimple);

using var output = canvas.Clone();
foreach (var contour in contours)
{
    // 面積が小さいノイズを除外
    if (Cv2.ContourArea(contour) < 500) continue;

    Rect rect = Cv2.BoundingRect(contour);
    Cv2.Rectangle(output, rect, new Scalar(0, 0, 255), 3);
    Console.WriteLine($"検出: x={rect.X} y={rect.Y} w={rect.Width} h={rect.Height}");
}

Cv2.ImWrite("detected.png", output);

実行すると、緑の円に外接する矩形が描画された detected.png が出力され、コンソールには次のように表示されます。

検出: x=100 y=100 w=200 h=200

実践例 2: BGR 画像でのしきい値範囲指定(グレースケール)

HSV 以外でも使えます。グレースケール画像に対して特定の輝度範囲を抽出する場合は Scalar に1値だけ渡します。

using OpenCvSharp;

using var src  = Cv2.ImRead("input.png", ImreadModes.Grayscale);
using var mask = new Mat();

// 輝度 100〜200 の範囲を抽出
Cv2.InRange(src, new Scalar(100), new Scalar(200), mask);

Cv2.ImWrite("gray_mask.png", mask);
Console.WriteLine("gray_mask.png を出力しました");

つまずきポイント

⚠️ 赤色は2回 InRange が必要

HSV の色相(H)は 0〜180(OpenCV の場合)で循環しており、赤色は 0〜10 と 170〜180 の両端にまたがります。1回の InRange だけでは赤色を完全に抽出できません。2回呼んで BitwiseOr で合算する実装を必ず行ってください。

⚠️ HSV の値域は OpenCV 固有のスケール

OpenCV の HSV は H: 0〜180、S: 0〜255、V: 0〜255 です。一般的なカラーピッカーの H: 0〜360 とスケールが異なります。ウェブツール等で調べた色相値は ÷2 して使う必要があります。混同するとマスクが意図どおりに生成されず、デバッグに時間を取られがちです。

⚠️ Mat の Dispose 漏れ

InRange の出力 dst(マスク Mat)もネイティブメモリを消費します。using を付け忘れると GC タイミングに依存したメモリリークが発生します。中間マスク(mask1・mask2・mask など)がいくつも増えやすい処理なので、using var を徹底してください。


関連する関数

  • Cv2.FindContours / Cv2.BoundingRect — 色抽出後のマスクから輪郭・外接矩形を求めるセットで使います。Cv2.BoundingRect の使い方
  • Cv2.ContourArea — 小さなノイズ輪郭を面積でフィルタするときに使います。Cv2.ContourArea の使い方
  • Cv2.BitwiseAnd / Cv2.BitwiseOr — マスクを元画像に適用したり、複数マスクを合算するときに使います。
  • Cv2.CvtColor — InRange の前処理として BGR→HSV 変換に使います。

まとめ

Cv2.InRange は色範囲マスクを1行で生成できるシンプルかつ強力な関数です。HSV 色空間と組み合わせることで照明変化に強い色抽出が実現でき、その後の輪郭検出や外接矩形取得とも自然につながります。赤色の2範囲問題と HSV のスケール差に注意すれば、実務での色ベース検出の基盤として十分に機能します。

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

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

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