LoginSignup
8
7

More than 3 years have passed since last update.

HalideとOpenCVとの連携

Last updated at Posted at 2019-08-31

Halideは画像処理記述用のDSLです。
どういったものかは公式ページをご覧いただくか、福嶋先生がある程度の日本語資料を投稿されていますので、そちらを参照ください。

HalideとOpenCVとの連携

Halideには画像ファイルの読み込み/書き込み関数がありませんので、別途用意する必要があります。
ここではOpenCVのimread/imwriteを使ってみましょう。
処理はカラー画像のグレイスケール化にでもしておきましょうか。
rgb.png

gray1.cpp
#include <Halide.h>
#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat cv_src = cv::imread("rgb.png");
    cv::Mat cv_dst(cv_src.size(), CV_8UC1);

    Halide::Buffer<uint8_t> hal_src(cv_src.data, cv_src.cols, cv_src.rows, 3);  
    Halide::Buffer<uint8_t> hal_dst(cv_dst.data, cv_dst.cols, cv_dst.rows);    // 1chなのでx,yだけでOK

    Halide::Func GrayScale;
    Halide::Var x, y;

    Halide::Expr gray =
        0.114f * hal_src(x, y, 0) +     //B
        0.587f * hal_src(x, y, 1) +     //G
        0.299f * hal_src(x, y, 2);      //R

    GrayScale(x, y) = Halide::cast<uint8_t>(Halide::min(gray, 255));

    GrayScale.realize(hal_dst);     // 出力先をhal_dstにして、グレイスケール化の実行

    cv::imwrite("gray1.png", cv_dst);
}

Buffer<T>のコンストラクタ先頭の引数にMatのdataポインタを渡すことで、直接Mat画像をHalideで扱うことができます。
ポインタを共用しているので、Bufferを書き換えればMatの中身も書き換わります。

HalideとOpenCVのメモリ配置の違い

さて、実際に生成された画像はというと…
gray1.png
なんじゃこりゃ。失敗ですね。

なにが原因かというと、Halideのデフォルトのメモリ配置がプレーナ型を想定しているためです。
プレーナ型とは、以下のようなメモリ配置です。
画像が色チャンネル枚分並んでいる、という形でしょうか。

BBBBBBBBGGGGGGGGRRRRRRRR

一方、OpenCVのMatはインターリーブ型になっています。
1pixelごとにB,G,Rと並んでいる、素直な形です。
OpenCVを触っている人ならおなじみですね。

BGRBGRBGRBGRBGRBGRBGRBGR

ということで、上記のプログラムはhal_srcの作成時に齟齬が生じてしまっています。
直すのは簡単で、HalideのBufferにインターリーブ型であると教えてやれば大丈夫です。

gray2.cpp
#include <Halide.h>
#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat cv_src = cv::imread("rgb.png");
    cv::Mat cv_dst(cv_src.size(), CV_8UC1);

    Halide::Buffer<uint8_t> hal_src = 
        Halide::Buffer<uint8_t>::make_interleaved(cv_src.data, cv_src.cols, cv_src.rows, 3);   // ここでインターリーブ型だと教えてやる    
    Halide::Buffer<uint8_t> hal_dst(cv_dst.data, cv_dst.cols, cv_dst.rows);

    Halide::Func GrayScale;
    Halide::Var x, y;

    Halide::Expr gray =
        0.114f * hal_src(x, y, 0) +     //B
        0.587f * hal_src(x, y, 1) +     //G
        0.299f * hal_src(x, y, 2);      //R

    GrayScale(x, y) = Halide::cast<uint8_t>(Halide::min(gray, 255));

    GrayScale.realize(hal_dst);     // 出力先をhal_dstにして、グレイスケール化の実行

    cv::imwrite("gray2.png", cv_dst);
}

こうすると、うまくできます。
gray2.png

8
7
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
8
7