OpenCV/C++ cvtColor の使い方 〜グレースケール変換と画像加工〜
cv::cvtColor は画像の色空間を変換する関数です。BGR→グレースケール、BGR→HSV など、OpenCV が扱う主要な色空間間の変換を1行で行えます。最小限の呼び出しは次のとおりです。
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
動作環境
| 項目 | バージョン |
|---|---|
| OpenCV | 4.x |
| C++ 規格 | C++17 |
g++ -std=c++17 main.cpp `pkg-config --cflags --libs opencv4` -o main
基本の使い方
BGR カラー画像をグレースケールに変換する最小構成のプログラムです。
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// 画像読み込み(パスは実行ディレクトリからの相対パス)
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "画像を読み込めませんでした" << std::endl;
return 1;
}
// BGR → グレースケール変換
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
// 結果を表示
cv::imshow("original", src);
cv::imshow("gray", gray);
cv::waitKey(0);
return 0;
}
実行結果
"original" ウィンドウ: 元のカラー画像
"gray" ウィンドウ: グレースケール変換後の画像(チャンネル数 1)
変換後の gray は CV_8UC1(1チャンネル)になります。元の src は CV_8UC3 のままで上書きされません。
行ごとの解説
| 行 | 内容 |
|---|---|
cv::imread |
画像をBGR形式で読み込む。empty() で失敗を確認 |
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY) |
src(入力)を変換し gray(出力)に書き込む |
cv::COLOR_BGR2GRAY |
変換コード。OpenCV の画像はデフォルトで BGR 順 |
引数と戻り値
void cv::cvtColor(
InputArray src, // 入力画像
OutputArray dst, // 出力画像
int code, // 変換コード(cv::ColorConversionCodes)
int dstCn = 0 // 出力チャンネル数(0=自動)
);
| 引数 | 型 | 説明 |
|---|---|---|
src |
InputArray |
入力画像。CV_8U / CV_16U / CV_32F に対応 |
dst |
OutputArray |
出力画像。サイズ・型は自動で決まる |
code |
int |
変換コード。cv::ColorConversionCodes の列挙値を指定 |
dstCn |
int |
出力チャンネル数。0 で変換コードに従い自動設定 |
戻り値はありません(void)。
主な変換コード一覧
| 変換コード | 変換内容 |
|---|---|
cv::COLOR_BGR2GRAY |
BGR → グレースケール |
cv::COLOR_GRAY2BGR |
グレースケール → BGR(3ch化) |
cv::COLOR_BGR2HSV |
BGR → HSV |
cv::COLOR_HSV2BGR |
HSV → BGR |
cv::COLOR_BGR2RGB |
BGR ↔ RGB(チャンネル順を入れ替え) |
cv::COLOR_BGR2Lab |
BGR → CIE L*a*b* |
全変換コードは公式リファレンスを参照してください。
cv::ColorConversionCodes – OpenCV 4.x ドキュメント
実践例
例1: HSV 変換で特定の色を抽出する
色抽出の前処理として BGR→HSV 変換を使うのは実務でよくあるパターンです。
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "画像を読み込めませんでした" << std::endl;
return 1;
}
// BGR → HSV 変換
cv::Mat hsv;
cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV);
// 赤色の範囲(HSV空間)でマスク生成
// 赤は色相が 0〜10 と 170〜180 の両端にまたがる
cv::Mat mask1, mask2, mask;
cv::inRange(hsv, cv::Scalar(0, 100, 100), cv::Scalar(10, 255, 255), mask1);
cv::inRange(hsv, cv::Scalar(170, 100, 100), cv::Scalar(180, 255, 255), mask2);
cv::bitwise_or(mask1, mask2, mask);
// マスクで元画像から赤色領域を抽出
cv::Mat result;
cv::bitwise_and(src, src, result, mask);
cv::imshow("original", src);
cv::imshow("red_extracted", result);
cv::waitKey(0);
return 0;
}
実行結果
"original" ウィンドウ: 入力画像
"red_extracted" ウィンドウ: 赤色の領域のみ残した画像
例2: グレースケール画像を3チャンネルに戻す
グレースケール画像にカラーの描画(cv::rectangle など)を重ねたいとき、チャンネル数を揃える必要があります。
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "画像を読み込めませんでした" << std::endl;
return 1;
}
// グレースケール変換
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
// グレースケール(1ch)を 3ch BGR に戻す
cv::Mat gray_bgr;
cv::cvtColor(gray, gray_bgr, cv::COLOR_GRAY2BGR);
// 3ch になったので赤い矩形を描画できる
cv::rectangle(gray_bgr, cv::Rect(50, 50, 100, 100), cv::Scalar(0, 0, 255), 3);
cv::imshow("gray_with_rect", gray_bgr);
cv::waitKey(0);
return 0;
}
実行結果
"gray_with_rect" ウィンドウ: グレースケール背景に赤い矩形が描画された画像
つまずきポイント
⚠️ OpenCV の画像チャンネル順は BGR であって RGB ではない
cv::imread で読み込んだ画像は BGR 順です。cv::COLOR_RGB2GRAY を使っても処理は通りますが、赤と青チャンネルを取り違えたまま計算されるため変換後の輝度値がズレます。cv::COLOR_BGR2GRAY を使うのが正しい選択です。
⚠️ グレースケール画像に cv::COLOR_BGR2GRAY を適用しようとしてアサーションエラー
すでに1チャンネルの cv::Mat に cv::COLOR_BGR2GRAY(入力3ch前提)を渡すと実行時にアサーションエラーが出ます。
OpenCV Error: Assertion failed (scn == 3 || scn == 4)
変換前に src.channels() でチャンネル数を確認するか、処理フローを整理して二重変換しないよう注意してください。
⚠️ dst に src と同じ cv::Mat を渡すと型が変わる(型不一致の連鎖)
cv::cvtColor(img, img, cv::COLOR_BGR2GRAY); // img がその場で1chに上書きされる
インプレース(同一変数への上書き)は動作しますが、後続の処理で img が3チャンネルのつもりで使われると assertion エラーになります。別変数に受けるほうが意図が明確で安全です。
関連する関数
cv::inRange– HSV 変換後の色抽出マスク生成に組み合わせることが多いcv::threshold/cv::adaptiveThreshold– グレースケール変換後の二値化処理に使うcv::imread– 読み込み時にcv::IMREAD_GRAYSCALEフラグを渡すとcvtColorを省略できる(ただし途中でカラーも使いたい場合はcvtColorのほうが柔軟)cv::Mat::convertTo– 色空間ではなく型(CV_8U→CV_32F等)の変換をしたい場合はこちら
まとめ
cv::cvtColorは第3引数の変換コード(cv::ColorConversionCodes)で変換内容を指定する- OpenCV の画像は BGR 順なので
COLOR_BGR2GRAY/COLOR_BGR2HSVを使う - インプレース変換は可能だが、後続処理での型・チャンネル数の不一致に注意する
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

