Skip to the content.

演習用行列計算ライブラリ

Makefile

円滑に演習が進むようにMakefileを提供している. コードを編集した場合,makeコマンドでコンパイルすること. また,.oファイルを削除したい場合は,make cleanを実行すること.

コンパイルオプションを変更する場合は,CXXFLAG_STを編集すること. CXXFLAGは必要なコンパイルオプションなので,変更しないように注意すること.

Matクラス

本演習では,行列クラスとしてMat_XXXクラスを提供している. XXXには,8U,16S,32S,32F,64Fが入る. これらは順に,unsigned charshortintfloatdouble型の行列であることを表している. これらのクラスには,データを格納しているdata変数,行列の行数を格納しているrows変数,列数を格納しているcols変数がある.

//8Uの場合
struct Mat_8U{
  unsigned char* data;
  int rows;
  int cols;
}

データにアクセスする場合,列優先で格納されているため,以下のようにコードを書くことで指定の位置にアクセスができる.

const int row = 3;
const int col = 3;
Mat_8U a(row, col);

//j行,i列へのアクセス
a.data[j*a.cols+i];

また,showという関数を用意しているため,行列の中身を確認したい場合は,以下のようにすること. ただし,非常に大きな行列を表示すると画面に収まりきらないため注意すること.

Mat_8U a(row, col);
a.show();
//もしくは
mat_show(a);

行列の初期化

行列の初期化には,mat_zeromat_onemat_rand関数を用意している.

Mat_8U a(row, col);

mat_zero(a); //0で初期化
mat_one(a); //1で初期化
mat_rand(a, 0, 100); //0~100の乱数で初期化

なお,mat_rand等のrand関数を使用して乱数を生成しているが,再現性があるようにあえてsrandはしていない. 通常乱数を使う場合は,srand等を使ってより乱数らしくなるようにするが,今回は演習用のために行っていない.

また,行列の内容が最初から決まっている場合は,行列オブジェクトを作成する際に値を代入することもできる.

const int row = 3;
const int col = 3;
const unsigned char data[row*cols] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
Mat_8U a(data, row, col);
// 0, 1, 2,
// 3, 4, 5,
// 6, 7, 8,

行列演算

行列演算を行う関数として以下がある. 適時使用すること.

チュートリアル課題1

3x3の単精度浮動小数点(float)の行列を確保し,すべて1で初期化したのちにshowメソッドで中身を確認せよ.

答え:

  Mat_32F a(3, 3);
  mat_one(a);
  a.show();

チュートリアル課題2

5x5 倍精度浮動小数点(double)の行列を確保し,自分でループを書いて単位行列として初期化し,showメソッドで中身を確認せよ. 単位行列は対角要素がすべて1,それ以外はすべて0の行列である.

答え:

Mat_64F a(5, 5);
for (int j = 0; j < a.rows; j++)
{
	for (int i = 0; i < a.cols; i++)
	{
		if (i == j) a.data[j * a.cols + i] = 1.0;
		else a.data[j * a.cols + i] = 0.0;
	}
}
a.show();

チュートリアル課題3

3x3 の1バイトの符号なし整数(unsigned char)の行列を確保し,自分でループを書いてすべてが255となるようにして,showメソッドで中身を確認せよ.

答え:

Mat_8U a(3, 3);
for (int j = 0; j < a.rows; j++)
{
	for (int i = 0; i < a.cols; i++)
	{
		a.data[j * a.cols + i] = 255;
	}
}
a.show();

なお,すべての要素に対して,行と列が関係ないような関数は以下のようにループを1重にできる.

Mat_8U a(3, 3);
const int size = a.cols * a.rows;
for (int i = 0; i < size; i++)
{
	a.data[i] = 255;
}
a.show();

もし,演習で実行時間に差がないような場合,この形式にすると差が見えるようになる可能性がある. なぜなら,行列へのアクセスのためにj*cols+iをしたり,添え字のi++,j++をしたりするからである.
これをループつぶしとも呼ぶ(演習を参照のこと).