OpenCV2の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()関数から実行すると、以下のような出力になります。
ここで確認したいことは、確かに行列を扱うことが出来るということだけです。これを踏まえて次のプログラムで簡単な画像を生成してその画像の情報を表示してみます。(ラベンダー色というのは適当です。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の基本処理、画像処理」を見ながら書きました。もちろん値や書き方は変えています。