株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。Raspberry Pi や Arduino その他新規開発案件のご依頼をお待ちしております。

OpenCV

OpenCV2 cv::Matクラスの基礎

投稿日:2014年6月8日 更新日:

0001OpenCV2のcv::Matクラスの基礎についてです。OpenCV 2.0からはC++のインターフェースが追加されました。cv::MatクラスはそのC++インターフェースで画像を扱うクラスです。まずこのクラスの基礎を理解してみようと思います。Matという名前である通り、このMatクラスは行列でもあります。つまり、行列で画像を表現して管理しているということです。このあたりをプログラムで確認してみます。ここでのスクリーンショットはこのcv::Matクラスで生成した単色の画像です。

ここでのバージョンは、OpenCV 2.4.8で、開発環境は、Microsoft Visual Studio Express 2013 for Windows Desktopです。OpenCVの導入はNuGetを使っています。(以下参照)
NuGetでOpenCVを導入する

今回の内容についてより詳細が必要な場合は以下等を参照して下さい。
cv::Matの基本処理 OpenCV-CookBook
OpenCV 2.x の入門 画像の簡単操作

それでは本題です。以下、コンソールアプリケーションでのプログラムです。まずは、行列としてMatを使ってみます。3×3の要素を持つ行列を定義して簡単な演算を実行しています。

#include "stdafx.h"

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

/*-----------------------------------------
	行列演算テスト関数
------------------------------------------*/
void  matTest1()
{
	//行列 mat1 を生成
	unsigned char data1[] = { 3, 2, 1, 4, 5, 6, 1, 2, 3 };
	Mat mat1(3, 3, CV_8U, data1);

	//行列 mat2 を生成
	unsigned char data2[] = { 2, 1, 3, 6, 4, 7, 8, 9, 10 };
	Mat mat2(3, 3, CV_8U, data2);

	//関数名表示
	cout << "-- matTest1() -- " << endl;

	// mat1とmat2をそれぞれ表示
	cout << "mat1 =" << mat1 << endl << endl;
	cout << "mat2 =" << mat2 << endl << endl;

	// mat1 + mat2 と mat1 * mat2 を表示
	cout << "mat1+mat2 =" << mat1 + mat2 << endl << endl;
	cout << "mat1*mat2 =" << mat1.mul(mat2) << endl << endl;

	return;
}

これを別途 main()関数から実行すると、以下のような出力になります。
0003

ここで確認したいことは、確かに行列を扱うことが出来るということだけです。これを踏まえて次のプログラムで簡単な画像を生成してその画像の情報を表示してみます。(ラベンダー色というのは適当です。RGBそれぞれの要素に適当な値が入る色だったという程度です。)

#include "stdafx.h"

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

/*---------------------------------------
Matでの単純画像生成とその情報表示
-----------------------------------------*/
void matImage1()
{
	 //関数名表示
	 cout << "-- matImage1() -- " << endl;

	 //ラベンダー色系の画像生成
	 Mat lavender(Size(320, 240), CV_8UC3, Scalar(184, 101, 204));

	 //この画像の情報を表示
	 cout << "行数 = " << lavender.rows << endl;
	 cout << "列数 = " << lavender.cols << endl;
	 cout << "次元数 = " << lavender.dims << endl;

	 cout << "チャンネル数 = " << lavender.channels() << endl;
	 cout << "1画素のバイト数 = " << lavender.elemSize() << endl;

	 cout << "タイプ CV_8UC3 = " << CV_8UC3 << endl;
	 cout << "タイプ(ID) = " << lavender.type() << endl;
	 cout << "タイプ CV_8U = " << CV_8U << endl;
	 cout << "画像の深さ = " << lavender.depth() << endl;

	 //表示
	 imshow("labender", lavender);

	 //キー入力待ち
	 waitKey(0);

	return;
}

これを実行すると、コンソールには以下の情報が出力されます。画像は冒頭のスクリーンショットが表示されます。

— matImage1() —
行数 = 240
列数 = 320
次元数 = 2
チャンネル数 = 3
1画素のバイト数 = 3
タイプ CV_8UC3 = 16
タイプ(ID) = 16
タイプ CV_8U = 0
画像の深さ = 0

(プログラムでの出力は以上です。)

間違いなく Mat lavender()で指定した値が入っているのですが、これを順に見ていきます。

行数:240、列数:320でこれが画像のx、yのサイズです。
次元数は、x、yの2次元です。

チャンネル数は、RGBの3チャンネルです。
1画素のバイト数は、3バイトでRGBそれぞれ1バイトです。

タイプは、CV_8UC3でdefineされている値で、3個のCV_8Uで表現するカラー画像の画素値です。
画像の深さのCV_8Uは、符号なしの8ビット整数で、C言語では、unsigned charで表現される型です。
(確かに RGBそれぞれunsigned charの範囲で表現しています。Scalarクラスは、4要素の要素ベクトルを表現できるクラスでここでは3要素を使っています。詳細は以下を参照して下さい。)
Scalarクラス

ここで今回のポイントです。画像のデータがどのようにMatクラスで表現されているかを理解すれば、Matクラスを画像として使いこなしていけるのではということです。

今回はここまでです。

行列の演算部分は以下の書籍の「Chapter.3 リファレンス編 cv::Matの基本処理、画像処理」を見ながら書きました。もちろん値や書き方は変えています。

AdSense

AdSense

-OpenCV

執筆者:

関連記事

OpenCVで背景差分とテスト的な動体検知

OpenCVで背景差分を試してみました。あとテスト的な動体検知も試してみました。背景差分とはあらかじめ取得した画像を背景画像として、観測時点の画像とその背景画像との差分を取ることによりその差分を前景領 …

OpenCVをWin32ベースで利用する(その3)カメラ入力からの画像処理

OpenCVをWin32ベースで利用するの3回目です。前回は画像ファイルを入力にしてその画像に対してOpenCVで画像処理を行うというプログラムでした。今回は大きくは変わらないですが、カメラからの画像 …

OpenCVで輪郭抽出から隣接領域の切り出し(その3)凸包の取得

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を切り出すという処理を作ってみました。前回までのプログラムとほぼ同じですが、前回までは輪郭抽出 → 直線近似 → 隣接領域 …

OpenCVをWin32ベースで利用する(その2)OpenCVの組み込み

OpenCVをWin32ベースで利用するの2回目です。前回はベースになるダイアログベースのアプリケーションを作成しました。今回はこのアプリケーションにOpenCVを組み込んで実際に動かしてみます。 ( …

OpenCVをWin32ベースで利用する(その4)カメラ入力からの動画処理

OpenCVをWin32ベースで利用するの4回目です。前回はカメラ入力からの画像処理(静止画)を扱いましたが、今回は動画を処理します。動画と言っても特に変わることはなくキャプチャしたフレームごとに処理 …