#はじめに
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;
}