OpenCV/C++ Mat の基礎① 〜画像を行列として扱う〜
OpenCV で画像を扱う中心的なクラスが cv::Mat です。画像ファイルを読み込んだ結果も、処理途中の中間データも、すべて cv::Mat として扱います。本記事では Mat の作成・初期化・画素アクセス という実装上の基礎を C++ コードで押さえます。
先出し: Mat を生成して画素に直接アクセスする最小パターンは次のとおりです。
cv::Mat img(480, 640, CV_8UC3, cv::Scalar(0, 0, 0)); // 黒画像を生成
img.at<cv::Vec3b>(100, 200) = cv::Vec3b(0, 255, 0); // (row=100, col=200) を緑に
動作環境
| 項目 | 内容 |
|---|---|
| OpenCV | 4.x |
| 言語 | C++17 |
| ビルド例 | g++ -std=c++17 main.cpp \pkg-config –cflags –libs opencv4“ |
基本の使い方
cv::Mat を直接生成し、初期化・画素アクセスまでを一本のプログラムで確認します。
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// --- 1. コンストラクタで生成(高さ4, 幅4, 8ビットグレースケール, 初期値0)
cv::Mat gray(4, 4, CV_8UC1, cv::Scalar(0));
// --- 2. 特定画素に書き込む(行, 列の順)
gray.at<uchar>(1, 2) = 128;
gray.at<uchar>(3, 3) = 255;
// --- 3. 画素値を読み出して表示
std::cout << "gray(1,2) = " << static_cast<int>(gray.at<uchar>(1, 2)) << std::endl;
std::cout << "gray(3,3) = " << static_cast<int>(gray.at<uchar>(3, 3)) << std::endl;
// --- 4. Mat 全体を行列として出力
std::cout << "Mat =\n" << gray << std::endl;
// --- 5. BGR カラー画像を生成して1画素だけ緑にする
cv::Mat color(4, 4, CV_8UC3, cv::Scalar(0, 0, 0));
color.at<cv::Vec3b>(2, 1) = cv::Vec3b(0, 255, 0); // BGR 順
std::cout << "color(2,1) = " << color.at<cv::Vec3b>(2, 1) << std::endl;
return 0;
}
実行結果
gray(1,2) = 128
gray(3,3) = 255
Mat =
[ 0, 0, 0, 0;
0, 0, 128, 0;
0, 0, 0, 0;
0, 0, 0, 255]
color(2,1) = [0, 255, 0]
コード解説
| 行 | 内容 |
|---|---|
cv::Mat gray(4, 4, CV_8UC1, cv::Scalar(0)) |
高さ・幅・型・初期値を指定して生成。CV_8UC1 は 8 ビット符号なし1チャンネル |
gray.at<uchar>(row, col) |
グレースケール画素の読み書き。引数は (行, 列) の順 |
static_cast<int>(...) |
uchar のまま cout すると文字コードが出力されるためキャスト必須 |
CV_8UC3 |
8 ビット符号なし3チャンネル(BGR)。OpenCV の色順は BGR |
cv::Vec3b |
3チャンネル 8bit 画素の型。at<cv::Vec3b>(row, col) でアクセス |
引数と戻り値
Mat コンストラクタ(主要形式)
| 引数 | 型 | 説明 |
|---|---|---|
rows |
int |
高さ(ピクセル数) |
cols |
int |
幅(ピクセル数) |
type |
int |
型定数(CV_8UC1 等) |
s |
cv::Scalar |
初期値(省略可) |
よく使う型定数
| 定数 | 意味 | 用途例 |
|---|---|---|
CV_8UC1 |
uint8, 1ch | グレースケール |
CV_8UC3 |
uint8, 3ch | BGR カラー |
CV_32FC1 |
float32, 1ch | 浮動小数点処理 |
CV_64FC1 |
double, 1ch | 精度が必要な演算 |
主なメンバー
| メンバー | 型 | 説明 |
|---|---|---|
rows |
int |
高さ |
cols |
int |
幅 |
channels() |
int |
チャンネル数 |
type() |
int |
型定数(CV_8UC3 等) |
empty() |
bool |
データが空なら true |
実践例
実践例①:zeros / ones で初期化した Mat を作る
cv::Mat::zeros と cv::Mat::ones は全要素を 0 または 1 で初期化した Mat を返す静的メソッドです。
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// 全要素 0 の 3x3 float Mat
cv::Mat z = cv::Mat::zeros(3, 3, CV_32FC1);
// 全要素 1 の 3x3 float Mat
cv::Mat o = cv::Mat::ones(3, 3, CV_32FC1);
// スカラー倍して足し合わせる(行列演算もそのまま使える)
cv::Mat result = z + o * 5.0f;
std::cout << "result =\n" << result << std::endl;
return 0;
}
実行結果
result =
[5, 5, 5;
5, 5, 5;
5, 5, 5]
実践例②:画像ファイルを読み込んで画素値を確認する
実務では cv::imread で読み込んだ結果が cv::Mat です。empty() チェックを忘れずに。
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
cv::Mat img = cv::imread("sample.jpg");
if (img.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return 1;
}
std::cout << "サイズ: " << img.cols << " x " << img.rows << std::endl;
std::cout << "チャンネル数: " << img.channels() << std::endl;
std::cout << "型: " << img.type() << " (CV_8UC3=" << CV_8UC3 << ")" << std::endl;
// 左上画素の BGR 値を表示
cv::Vec3b px = img.at<cv::Vec3b>(0, 0);
std::cout << "左上画素 BGR: " << static_cast<int>(px[0])
<< ", " << static_cast<int>(px[1])
<< ", " << static_cast<int>(px[2]) << std::endl;
return 0;
}
実行結果(例)
サイズ: 640 x 480
チャンネル数: 3
型: 16 (CV_8UC3=16)
左上画素 BGR: 32, 87, 210
img.type() が返す整数は CV_8UC3 マクロの値(16)と一致します。型が想定どおりか確認するのに使えます。
つまずきポイント
⚠️ at<> の型と Mat の型が一致しないと実行時アサーションが出る
CV_8UC3 の Mat に img.at<uchar>(r, c) とアクセスすると、Debug ビルドで cv::Exception が投げられます。
// NG: CV_8UC3 の Mat に uchar でアクセス
uchar val = img.at<uchar>(0, 0); // アサーション失敗
// OK: チャンネル数・型に合わせる
cv::Vec3b px = img.at<cv::Vec3b>(0, 0);
型と at<> のテンプレート引数の対応を必ず合わせてください。
| Mat 型 | at<> の型 |
|---|---|
CV_8UC1 |
uchar |
CV_8UC3 |
cv::Vec3b |
CV_32FC1 |
float |
CV_32FC3 |
cv::Vec3f |
⚠️ at<> の座標は (行, 列) = (y, x) の順
画面座標では「(x, y)」で書きがちですが、at<> は (row, col) = (y, x) の順です。cv::Point を使うときは (x, y) 順なのと逆になるため、混在するコードでは特に注意してください。
img.at<uchar>(y, x) // Mat::at は (row, col) = (y, x)
img.at<uchar>(pt) // cv::Point pt(x, y) を渡す形式もある(内部で変換される)
⚠️ imread が空 Mat を返す場合は作業ディレクトリと日本語パスを確認
cv::imread はファイルが見つからなくてもエラーを投げず、空の cv::Mat を返します。相対パスはプログラムの実行ディレクトリ基準です。IDE(Visual Studio 等)ではプロジェクトファイルのある場所と実行ディレクトリが異なることがあります。また Windows 環境では日本語を含むパスを正しく扱えないケースがあるため、パスには ASCII のみを使うのが安全です。
関連する関数
cv::imread/cv::imwrite— ファイルから Mat を読み込む・保存するcv::cvtColor— BGR ↔ グレースケール等の色空間変換cv::Mat::clone/cv::Mat::copyTo— Mat の深いコピー(浅いコピーとの違いに注意)cv::Mat::ptr<>— 行ポインタを直接取得するループ高速化手法(at<>より高速)
まとめ
cv::Matは型定数(CV_8UC1等)とサイズを指定して生成し、cv::Scalarで初期値を与える。- 画素アクセスは
at<T>(row, col)で行う。T は Mat の型と必ず一致させること。 imread直後のempty()チェックは必須。空 Mat のまま処理を続けると実行時クラッシュになる。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

