LoginSignup
3
3

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-07-20

はじめに

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::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;
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3