Cv2.CvtColor の使い方【OpenCV/C#】色空間をグレースケール・HSVに変換する
Cv2.CvtColor は Mat の色空間を変換する関数です。BGR→グレースケール、BGR→HSV など、画像処理パイプラインの入口でほぼ必ず登場します。最小の呼び出しは以下のとおりです。
Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2GRAY);
動作環境
- OpenCV 4.x(OpenCvSharp4 4.9.x 系で確認)
- NuGet:
OpenCvSharp4+OpenCvSharp4.runtime.win(Windows 実行時) - .NET 8 コンソールアプリ(トップレベルステートメント)
基本の使い方
BGR 画像をグレースケールに変換して保存するシンプルなサンプルです。
using OpenCvSharp;
// 入力画像を読み込む(BGR形式)
using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");
// BGR → グレースケール に変換
using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
// 結果を保存
Cv2.ImWrite("output_gray.jpg", gray);
Console.WriteLine($"変換後チャンネル数: {gray.Channels()}"); // 1
実行すると以下がコンソールに表示され、output_gray.jpg が出力されます。
変換後チャンネル数: 1
コード解説
| 行 | ポイント |
|---|---|
ImRead(..., ImreadModes.Color) |
常に 3ch BGR で読み込む |
new Mat() |
出力用 Mat は空で渡す。サイズ・型は自動設定される |
ColorConversionCodes.BGR2GRAY |
変換コードを列挙体で指定。可読性が高い |
gray.Channels() |
グレースケールなので戻り値は 1 |
引数と戻り値
void Cv2.CvtColor(Mat src, Mat dst, ColorConversionCodes code, int dstCn = 0)
| 引数 | 型 | 説明 |
|---|---|---|
src |
Mat |
入力画像 |
dst |
Mat |
出力画像(サイズ・型は自動決定) |
code |
ColorConversionCodes |
色空間変換コード(後述) |
dstCn |
int |
出力チャンネル数。0 で自動(通常は省略) |
戻り値は void。変換結果は dst に書き込まれます。
よく使う ColorConversionCodes
| コード | 変換内容 |
|---|---|
BGR2GRAY |
BGR → グレースケール(1ch) |
GRAY2BGR |
グレースケール → BGR(3ch) |
BGR2HSV |
BGR → HSV |
HSV2BGR |
HSV → BGR |
BGR2Lab |
BGR → CIE L*a*b* |
BGR2YCrCb |
BGR → YCbCr |
⚠️ OpenCV の既定読み込み形式は BGR(RGB ではない)。RGB2GRAY ではなく BGR2GRAY を使います。
実践例
HSV に変換して特定色をマスク抽出する
色抽出・色追跡でよく使われるパターンです。HSV 空間に変換してから Cv2.InRange で色域を絞ります。
using OpenCvSharp;
// 入力画像を BGR で読み込む
using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");
// BGR → HSV に変換
using var hsv = new Mat();
Cv2.CvtColor(src, hsv, ColorConversionCodes.BGR2HSV);
// 赤色の HSV 範囲でマスクを生成(低域側)
using var mask1 = new Mat();
Cv2.InRange(hsv,
new Scalar(0, 100, 100),
new Scalar(10, 255, 255),
mask1);
// 赤色の HSV 範囲でマスクを生成(高域側)
using var mask2 = new Mat();
Cv2.InRange(hsv,
new Scalar(160, 100, 100),
new Scalar(180, 255, 255),
mask2);
// 2つのマスクを合成
using var mask = new Mat();
Cv2.BitwiseOr(mask1, mask2, mask);
// マスクを適用して赤色領域だけを抽出
using var result = new Mat();
Cv2.BitwiseAnd(src, src, result, mask);
Cv2.ImWrite("output_red.jpg", result);
Console.WriteLine("赤色領域の抽出が完了しました");
実行すると赤色領域だけが残った画像が output_red.jpg に保存されます。
赤色領域の抽出が完了しました
HSV 空間で色を扱う場合、赤は H 値がゼロ付近と 180 付近にまたがるため、2つの範囲を合成するのが定石です。
グレースケール画像を 3ch に戻してカラー描画に備える
アノテーション(矩形・テキスト描画)を加えたい場合、グレースケール Mat は 1ch なので描画関数で色が扱えません。一度 BGR に戻します。
using OpenCvSharp;
using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");
// グレースケールに変換
using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
// 1ch → 3ch に戻す(色付き描画のため)
using var grayBgr = new Mat();
Cv2.CvtColor(gray, grayBgr, ColorConversionCodes.GRAY2BGR);
// グレー背景に赤い矩形を描画
Cv2.Rectangle(grayBgr, new Rect(50, 50, 200, 150), new Scalar(0, 0, 255), 3);
Cv2.ImWrite("output_annotated.jpg", grayBgr);
Console.WriteLine("アノテーション付き画像を保存しました");
アノテーション付き画像を保存しました
つまずきポイント
⚠️ BGR2GRAY と RGB2GRAY の混同
OpenCV は画像を BGR 順で保持します。Cv2.ImRead で読んだ画像に RGB2GRAY を適用すると、R と B チャンネルの重みが入れ替わり、微妙に異なるグレー値になります。ImRead 経由の画像には必ず BGR2GRAY を使ってください。
⚠️ グレースケール Mat への色指定が無効になる
1ch の Mat(グレースケール)に Cv2.Rectangle 等で new Scalar(0, 0, 255) を指定しても赤色にはなりません。1ch の場合は明度値(0〜255 の整数)しか扱えないためです。カラー描画が必要なら GRAY2BGR で 3ch に変換してから行います。
⚠️ using を省略した Mat のメモリリーク
Cv2.CvtColor の出力 dst に渡す new Mat() は、ネイティブヒープにメモリを確保します。using を付け忘れると GC が回収するまでメモリが解放されず、ループ処理などで顕著なリークになります。出力 Mat は必ず using var dst = new Mat(); と宣言してください。
関連する関数
- Cv2.InRange — HSV 変換後の色域抽出に組み合わせる定番関数
- Cv2.Split — 変換後の Mat をチャンネルごとに分離して個別処理する
- Cv2.ImRead / Cv2.ImWrite — 読み込み・保存の基本操作
まとめ
Cv2.CvtColor は ColorConversionCodes 列挙体で変換コードを指定するだけで色空間を切り替えられます。OpenCV は BGR 基準であることを常に意識し、用途に応じてグレースケール・HSV を使い分けてください。出力 Mat の using 宣言はメモリリーク防止のために必須です。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

