OpenCV/C++ cvtColor の使い方 〜グレースケール変換と画像加工〜

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

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)

変換後の grayCV_8UC1(1チャンネル)になります。元の srcCV_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::Matcv::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_8UCV_32F 等)の変換をしたい場合はこちら

まとめ

  • cv::cvtColor は第3引数の変換コード(cv::ColorConversionCodes)で変換内容を指定する
  • OpenCV の画像は BGR 順なので COLOR_BGR2GRAY / COLOR_BGR2HSV を使う
  • インプレース変換は可能だが、後続処理での型・チャンネル数の不一致に注意する

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

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

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