HalideにおけるバッファHalide::Buffer<T>の操作（HalideとOpenCVの相互変換）

#はじめに
Halideに関するリンクは以下の記事にまとめてあります．
[Halideによる画像処理まとめ](https://qiita.com/fukushima1981/items/fa3537234e19baffc761)

#メンバ変数へのアクセス

画像サイズやチャネル数，先頭ポインタの取得などのネイティブなC/C++コードとデータをやり取りするために必要なメンバ変数の情報取得は以下通り．

```c++
//Halideのデータ生成用テスト
Func grad;
grad(x, y, c) = cast<uint8_t>((x + y) % 256);
Halide::Buffer<uint8_t> output = realize(256,256);
//ここまで

output.width();//横サイズ
output.height();//縦サイズ
output.channels()//チャネル数
output.dimensions()//次元数，テストしたところチャネル数と一緒だと思う．
output2.size_in_bytes()//バイト数（縦ｘ横ｘチャネルｘsizeof(T)）．

uchar* data = output2.begin();//RAWデータの先頭ポインタ
uchar* data = output2.data();//RAWデータの先頭ポインタ．テストしたところ上と同じ．
uchar* data = output2.end();//RAWデータの最後尾のポインタ
```

##その他参考ページ
* より詳細な情報は，`Halide.h`に書いてます（少し読みにくいです）．
* その他の初期化は[このstackoverflowのやり取り](https://stackoverflow.com/questions/39779149/initializing-halide-buffer-in-c)を参照．
* [OpenCVでHalideを使ってDNNを高速化したmoduleのコード](https://github.com/opencv/opencv/blob/master/modules/dnn/src/op_halide.cpp)



#色々な初期化とデータのやり取り
`Halide::Buffer<uint8_t>`の代表的な初期化の方法は以下の通り


* 確保だけ
`Buffer<uint8_t> input(width, height, channel);`
* 計算時に確保
`Buffer<uint8_t> output = grad.realize(width, height, channel);`
* 先頭ポインタを指定(`uchar* data`が先頭ポインタ)
`Buffer<uint8_t> input(data, width, height, channel);`


以下，OpenCVとHalideのデータをやり取りするためのサンプルコード．
Halide処理中で余計なメモリ確保をしないようにするにはTest3とTest5の形になる．
Test6は，ループでコピーしているが，Halideが効率的なコンパイルをしてくれるわけではないので遅い．

```cpp
void halideInitTest1(Mat& dest)
{
	Var x, y, c;
	Func grad;
	grad(x, y, c) = cast<uint8_t>((x + y) % 256);

	Halide::Buffer<uint8_t> output = grad.realize(dest.cols, dest.rows, dest.channels());

	uchar* data = output.data();
	//uchar* data = output.begin();//こっちでも同じ

	memcpy(dest.data, data, output.size_in_bytes());
	//memcpy(dest.data, data, output.width()*output.height()*output.channels());//こっちでも同じ
	//memcpy(dest.data, data, output.width()*output.height()*output.dimensions());//こっちでも同じ
}

void halideInitTest2(Mat& dest)
{
	Var x, y, c;
	Func grad;
	grad(x, y, c) = cast<uint8_t>((x + y) % 256);
	Halide::Buffer<uint8_t> output(dest.cols, dest.rows, dest.channels());

	grad.realize(output);

	uchar* data = output.data();
	memcpy(dest.data, data, output.size_in_bytes());
}

void halideInitTest3(Mat& dest)
{
	Var x, y, c;
	Func grad;
	grad(x, y, c) = cast<uint8_t>((x + y) % 256);
	//dest.ptr<uchar>(0)はOpenCVの画像データの先頭ポインタ
	Halide::Buffer<uint8_t> output(dest.ptr<uchar>(0), dest.cols, dest.rows, dest.channels());

	grad.realize(output);
}

void halideInitTest4(Mat& src, Mat& dest)
{
	Var x, y, c;
	Halide::Buffer<uint8_t> input(src.ptr<uchar>(0), src.cols, src.rows, src.channels());
	Func adder;
	adder(x, y, c) = cast<uint8_t>(min((cast<int16_t>(input(x, y, c)) + (short)50), 255));

	Halide::Buffer<uint8_t> output = adder.realize(dest.cols, dest.rows, dest.channels());

	uchar* data = output.data();
	memcpy(dest.data, data, output.size_in_bytes());
}

void halideInitTest5(Mat& src, Mat& dest)
{
	Var x, y, c;
	Halide::Buffer<uint8_t> input(src.ptr<uchar>(0), src.cols, src.rows, src.channels());
	Halide::Buffer<uint8_t> output(dest.ptr<uchar>(0), dest.cols, dest.rows, dest.channels());
	Func adder;
	adder(x, y, c) = cast<uint8_t>(min((cast<int16_t>(input(x, y, c)) + (short)50), 255));

	adder.realize(output);
}

void halideInitTest6(Mat& src, Mat& dest)
{
	Var x, y, c;
	Halide::Buffer<uint8_t> input(src.cols, src.rows, src.channels());
	Halide::Buffer<uint8_t> output(dest.cols, dest.rows, dest.channels());
	//srcからコピー
	for (int j = 0; j < src.rows; j++)
	{
		for (int i = 0; i < src.cols; i++)
		{
			for (int n = 0; n < src.channels(); n++)
			{
				input(i, j, n) = src.at<uchar>(j, i*src.channels() + n);
			}
		}
	}

	Func adder;
	adder(x, y, c) = cast<uint8_t>(min((cast<int16_t>(input(x, y, c)) + (short)50), 255));

	adder.realize(output);

	//destへコピー
	for (int j = 0; j < dest.rows; j++)
	{
		for (int i = 0; i < dest.cols; i++)
		{
			for (int n = 0; n < dest.channels(); n++)
			{
				dest.at<uchar>(j, i*dest.channels() + n) = (uchar)output(i, j, n);
			}
		}
	}
}

int main(int argc, char **argv)
{
	Mat src = imread("lenna.png");
	Mat dest = Mat::zeros(src.size(), src.type());

	halideInitTest1(dest);//realizeでデータサイズを指定
	imshow("Halide1", dest);

	halideInitTest2(dest);//事前にbufferのサイズを指定
	imshow("Halide2", dest);

	halideInitTest3(dest);//事前にbufferのサイズと先頭ポインタを指定．メモリ確保の無駄が無い
	imshow("Halide3", dest);

	halideInitTest4(src, dest);//OpenCVのMat中のRAW先頭ポインタを使って初期化して計算結果をmemcpyで返す
	imshow("Halide4", dest);

	halideInitTest5(src, dest);//上記に加えて，計算結果のバッファも初期化で指定
	imshow("Halide5", dest);

	halideInitTest6(src, dest);//何をやっているか直感的にわかるが遅くなる例
	imshow("Halide6", dest);

	waitKey();
	return 0;
}
```