Pynote

Python、機械学習、画像処理について

OpenCV - cv::Mat の初期化方法について

試した環境

初期化方法

指定した配列で初期化した行列を作成する。

関数
Mat(int rows, int cols, int type, void *data, size_t step=AUTO_STEP)
Mat(Size size, int type, void *data, size_t step=AUTO_STEP)

cv::Mat の型と配列の型が一致していないとおかしくなるので注意。

コード
// 形状が 3x3 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は data の値で初期化される。
uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
cv::Mat mat(3, 3, CV_8UC1, data);
std::cout << mat << std::endl;
// 形状が 3x3 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は data の値で初期化される。
uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
cv::Mat mat(cv::Size(3, 3), CV_8UC1, data);
std::cout << mat << std::endl;
[  1,   2,   3;
   4,   5,   6;
   7,   8,   9]

MatCommaInitializer_ で初期化する。

関数
template<typename _Tp>
Mat(const MatCommaInitializer_<_Tp> &commaInitializer)
コード
cv::Mat mat = (cv::Mat_<uint8_t>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
std::cout << mat << std::endl;
[  1,   2,   3;
   4,   5,   6;
   7,   8,   9]
仕組み

(1) cv::Mat_(3, 3) << 1 で以下の関数が呼ばれる。

template <typename T>
MatCommaInitializer_<T> operator<<(Mat_<T>&, T);

(2) MatCommaInitializer_ オブジェクトに対して、カンマ演算子を用いることで以下の関数が呼ばれる。

template<typename T2>
MatCommaInitializer_<_Tp> & operator, (T2 v);

(3) cv::MatCommaInitializer_ クラスを引数にとる cv::Mat クラスのコンストラクタが呼ばれる。

template<typename _Tp>
Mat(const MatCommaInitializer_<_Tp> &commaInitializer);

すべて同じ値で初期化した行列を作成する。

関数
Mat(int rows, int cols, int type, const Scalar &s)
Mat(Size size, int type, const Scalar &s)
Mat &operator=(const Scalar &s)
コード

1チャンネルの場合

// 形状が 3x2 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は 5 で初期化される。
cv::Mat mat1(cv::Size(3, 2), CV_8UC1, 5);
std::cout << mat1 << std::endl;

// 形状が 3x2 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は 5 で初期化される。
cv::Mat mat2(cv::Size(2, 3), CV_8UC1, 5);

// 形状が 3x2 で要素の型が CV_8UC1 である配列を作成する。
cv::Mat mat3(cv::Size(2, 3), CV_8UC1);
// 要素をすべて5で初期化する。
mat3 = 5;
[  5,   5;
   5,   5;
   5,   5]

3チャンネルの場合

cv::Scalar val(255, 255, 100);

// 形状が 3x2 で要素の型が CV_8UC3 である配列を作成する。
// 各要素は cv::Scalar(255, 255, 100) で初期化される。
cv::Mat mat1(cv::Size(3, 2), CV_8UC3, val);
std::cout << mat1 << std::endl;

// 形状が 3x2 で要素の型が CV_8UC3 である配列を作成する。
// 各要素は cv::Scalar(255, 255, 100) で初期化される。
cv::Mat mat2(cv::Size(2, 3), CV_8UC3, val);

// 形状が 3x2 で要素の型が CV_8UC3 である配列を作成する。
cv::Mat mat3(cv::Size(2, 3), CV_8UC3);
// 各要素は cv::Scalar(255, 255, 100) で初期化される。
mat3 = 5;
[255, 255, 100, 255, 255, 100, 255, 255, 100;
 255, 255, 100, 255, 255, 100, 255, 255, 100]

すべて 0 で初期化した行列を作成する。

関数
static MatExpr zeros(int rows, int cols, int type)
static MatExpr zeros(Size size, int type)
コード
// 形状が 3x2 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は 0 で初期化される。
cv::Mat mat1 = cv::Mat::zeros(3, 2, CV_8UC1);
std::cout << mat1 << std::endl;

// 形状が 3x2 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は 0 で初期化される。
cv::Mat mat2 = cv::Mat::zeros(cv::Size(2, 3), CV_8UC1);
[  0,   0;
   0,   0;
   0,   0]

すべて 1 で初期化した行列を作成する。

関数
static MatExpr ones(int rows, int cols, int type)
static MatExpr ones(Size size, int type)
コード
// 形状が 3x2 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は 1 で初期化される。
cv::Mat mat1 = cv::Mat::ones(3, 2, CV_8UC1);
std::cout << mat1 << std::endl;

// 形状が 3x2 で要素の型が CV_8UC1 である配列を作成する。
// 各要素は 1 で初期化される。
cv::Mat mat2 = cv::Mat::ones(cv::Size(2, 3), CV_8UC1);
[  1,   1;
   1,   1;
   1,   1]

単位行列を作成する。

関数
static MatExpr eye(int rows, int cols, int type)
static MatExpr eye(Size size, int type)
コード
// 形状が 3x3 で要素の型が CV_8UC1 である単位行列を作成する。
cv::Mat mat1 = cv::Mat::eye(3, 3, CV_8UC1);
std::cout << mat1 << std::endl;

// 形状が 3x3 で要素の型が CV_8UC1 である単位行列を作成する。
cv::Mat mat2 = cv::Mat::eye(cv::Size(3, 3), CV_8UC1);
[  1,   0,   0;
   0,   1,   0;
   0,   0,   1]
関数

単位行列の作成は identity() でも行える。
こちらは単位行列をスケール倍した行列を作成できる。

void cv::setIdentity(InputOutputArray mtx, const Scalar &s = Scalar(1))	
コード
// 形状が 3x3 である単位行列を作成する。
cv::Mat dst(3, 3, CV_8UC1);
cv::setIdentity(dst);
std::cout << dst << std::endl;

// 形状が 3x3 である対角成分が3である行列を作成する。
cv::setIdentity(dst, 3);
std::cout << dst << std::endl;
[  1,   0,   0;
   0,   1,   0;
   0,   0,   1]
[  3,   0,   0;
   0,   3,   0;
   0,   0,   3]

一様分布に従う乱数で初期化した行列を作成する。

関数

randu() で各要素を一様分布で初期化した行列を作成できる。

void cv::randu(InputOutputArray dst, InputArray low, InputArray high)
コード
// 各要素を [0, 255] の一様分布に従う乱数で初期化する。
cv::Mat dst(3, 3, CV_8UC1);
cv::randu(dst, 0, 255);
std::cout << dst << std::endl;
[ 91,   2,  79;
 179,  52, 205;
 236,   8, 181]

正規分布に従う乱数で初期化した行列を作成する。

randn() で各要素を正規分布で初期化した行列を作成できる。

関数
void cv::randn(InputOutputArray dst, InputArray mean, InputArray stddev)
コード
// 各要素を平均3、分散5の正規分布に従う乱数で初期化する。
cv::Mat dst(3, 3, CV_32FC1);
cv::randn(dst, 3., 5.);
std::cout << dst << std::endl;

// 各要素を標準正規分布に従う乱数で初期化する。
cv::randn(dst, 0., 1.);
std::cout << dst << std::endl;
[3, 3.7906752, -0.50463986;
 0.85702014, 9.1937103, 1.6099589;
 -0.2419939, 4.5258164, 5.5750732]
[-1.1450437, 0.76984555, -0.04643121;
 1.3059061, -1.9596839, -1.8992141;
 -0.53723824, -0.74828959, 1.8964931]

乱数生成のシードの設定

乱数生成に使用されるシードは setRNGSeed() で設定できる。

関数
void cv::setRNGSeed(int seed)	
コード
cv::Mat dst(3, 3, CV_8UC1);

// seed = 0
cv::setRNGSeed(0);
cv::randu(dst, 0, 255);
std::cout << dst << std::endl;

// seed = 時刻 として実行ごとに異なるシードにする
cv::setRNGSeed(time(NULL));
cv::randu(dst, 0, 255);
std::cout << dst << std::endl;
[ 91,   2,  79;
 179,  52, 205;
 236,   8, 181]
[104,  98, 118;
  48,   0,  54;
  66,  43,  47]