はじめに
Halideに関するリンクは以下の記事にまとめてあります.
Halideによる画像処理まとめ
メンバ変数へのアクセス
画像サイズやチャネル数,先頭ポインタの取得などのネイティブな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()//バイト数(縦x横xチャネルxsizeof(T)).
uchar* data = output2.begin();//RAWデータの先頭ポインタ
uchar* data = output2.data();//RAWデータの先頭ポインタ.テストしたところ上と同じ.
uchar* data = output2.end();//RAWデータの最後尾のポインタ
その他参考ページ
- より詳細な情報は,Halide.hに書いてます(少し読みにくいです).
- その他の初期化はこのstackoverflowのやり取りを参照.
- OpenCVでHalideを使ってDNNを高速化したmoduleのコード
色々な初期化とデータのやり取り
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が効率的なコンパイルをしてくれるわけではないので遅い.
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;
}