Skip to content

[OpenVX Tutorial]OpenVXを使った簡単なプログラム(Sobelフィルタ)

atinfinity edited this page Jul 27, 2016 · 25 revisions

[OpenVX Tutorial]OpenVXを使った簡単なプログラム(Sobelフィルタ)

はじめに

2016/3/13現在,OpenVX Implementationとして

などがリリースされています.

ここではNVIDIA VisionWorksに入っているOpenVXを使った簡単なプログラム(Sobelフィルタ)の実装手順について紹介します.

ちなみに2016/3/13現在で配布されているNVIDIA VisionWorks v1.0.25には以下の記載があり,
OpenVX 1.0.1に対応しているようです(NVIDIA独自の拡張もある).

Features:

  • CUDA accelerated OpenVX 1.0.1 conformant API and NVIDIA extension primitives

NVIDIA CUDA Toolkitのインストール

NVIDIA VisionWorks v1.0.25はNVIDIA CUDA Toolkit v7.0に依存しているため,NVIDIA CUDA Toolkitをインストールします.

NVIDIA VisionWorksのインストール

NVIDIAのNVIDIA VisionWorksサイトからインストーラをダウンロードしてインストールします.
筆者の環境はWindowsのため,Windows用インストーラ(VisionWorks-1.0.25-win64.exe)をダウンロードしてインストールしました.
※デフォルトではC:\Program Files\NVIDIA VisionWorksにインストールされます.

また,DLL(visionworks.dll)をロードするために環境変数Pathに以下のパスを追加します.
C:\Program Files\NVIDIA VisionWorks\bin

プロジェクト設定

Visual Studioでプロジェクトを作成し,以下のパス,ライブラリを設定します.

インクルードパス:C:\Program Files\NVIDIA VisionWorks\include
ライブラリパス:C:\Program Files\NVIDIA VisionWorks\lib
ライブラリ:visionworks.lib

また,後述のサンプルコードでは画像ファイルの入出力にOpenCVを用いているため,OpenCVのパス,ライブラリも設定しています.

基本的な処理の流れ

OpenVXでSobelフィルタを実現するための基本的な処理の流れは以下の通りです.

  1. vxCreateContext関数でコンテキストを生成する
  2. vx_image型の変数を定義する
  3. vxuSobel3x3関数を実行する(x,y方向の微分画像が生成される)
  4. vxuMagnitude関数を実行する
  5. vxuMagnitude関数の結果はVX_DF_IMAGE_S16なのでVX_DF_IMAGE_U8にするためにvxuConvertDepth関数でdepth変換する
  6. vxReleaseImage関数でvx_image型の変数を解放する
  7. vxReleaseContext関数でコンテキストを解放する

後述のサンプルコードでは以下のヘルパー関数を作成し,OpenCVで画像の読み書きをしています.

  • createImageFromMat
  • createMatFromImage

サンプルコード

読み込んだ画像に対してSobelフィルタを適用して,その結果を保存するサンプルコードです.
今回のサンプルではシンプルにするためにgraphやnodeは使用していません.

// OpenVXのヘッダ
#include <VX/vx.h>
#include <VX/vxu.h>

// OpenCVのヘッダ
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>

#include <stdio.h>

vx_df_image convertMatTypeToImageFormat(int mat_type);

// Mat型データからvx_image型データを生成するヘルパー関数(自作)
vx_image createImageFromMat(vx_context context, const cv::Mat & mat);

// vx_image型データからMat型データを生成するヘルパー関数(自作)
vx_status createMatFromImage(cv::Mat &mat, vx_image image);

int main(int argc, char* argv[])
{
    // コンテキスト生成
    vx_context context = vxCreateContext();

    // 画像読み込み
    cv::Mat srcMat = cv::imread("lena.jpg", cv::IMREAD_GRAYSCALE);
    cv::Mat dstMat(srcMat.size(), srcMat.type());

    // Mat型データからvx_image型データを生成するヘルパー関数(自作)
    vx_image src = createImageFromMat(context, srcMat);

    int width  = srcMat.cols;
    int height = srcMat.rows;

    // vx_image型変数の定義
    vx_image dx  = vxCreateImage(context, width, height, VX_DF_IMAGE_S16);
    vx_image dy  = vxCreateImage(context, width, height, VX_DF_IMAGE_S16);
    vx_image mag = vxCreateImage(context, width, height, VX_DF_IMAGE_S16);
    vx_image dst = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);

    // Sobelフィルタの適用
    if(vxuSobel3x3(context, src, dx, dy) != VX_SUCCESS)
    {
        fprintf(stderr, "ERROR: failed to do sobel!\n");
        goto error;
    }

    if(vxuMagnitude(context, dx, dy, mag) != VX_SUCCESS)
    {
        fprintf(stderr, "ERROR: failed to do magnitude!\n");
        goto error;
    }

    // depth変換(VX_DF_IMAGE_S16→VX_DF_IMAGE_U8)
    if(vxuConvertDepth(context, mag, dst, VX_CONVERT_POLICY_WRAP, 0) != VX_SUCCESS)
    {
        fprintf(stderr, "ERROR: failed to do color convert!\n");
        goto error;
    }

    // vx_image型データからMat型データを生成するヘルパー関数(自作)
    createMatFromImage(dstMat, dst);

    // 結果の保存
    cv::imwrite("dst_lena.png", dstMat);

error:
    // vx_image型変数の解放
    vxReleaseImage(&src);
    vxReleaseImage(&dst);
    vxReleaseImage(&dx);
    vxReleaseImage(&dy);
    vxReleaseImage(&mag);

    // コンテキストの解放
    vxReleaseContext(&context);
}

vx_df_image convertMatTypeToImageFormat(int mat_type)
{
    switch (mat_type)
    {
    case CV_8UC1:
        return VX_DF_IMAGE_U8;
    case CV_16SC1:
        return VX_DF_IMAGE_S16;
    case CV_8UC3:
        return VX_DF_IMAGE_RGB;
    case CV_8UC4:
        return VX_DF_IMAGE_RGBX;
    }
    CV_Error(CV_StsUnsupportedFormat, "Unsupported format");
    return 0;
}

// Mat型データからvx_image型データを生成するヘルパー関数(自作)
vx_image createImageFromMat(vx_context context, const cv::Mat & mat)
{
    vx_imagepatch_addressing_t patch = { (vx_uint32)mat.cols, (vx_uint32)mat.rows,
        (vx_int32)mat.elemSize(), (vx_int32)mat.step,
        VX_SCALE_UNITY, VX_SCALE_UNITY,
        1u, 1u };
    void *ptr = (void*)mat.ptr();
    vx_df_image format = convertMatTypeToImageFormat(mat.type());
    return vxCreateImageFromHandle(context, format, &patch, (void **)&ptr, VX_IMPORT_TYPE_HOST);
}

// vx_image型データからMat型データを生成するヘルパー関数(自作)
vx_status createMatFromImage(cv::Mat &mat, vx_image image)
{
    vx_status status = VX_SUCCESS;
    vx_uint32 width = 0;
    vx_uint32 height = 0;
    vx_df_image format = VX_DF_IMAGE_VIRT;
    int cv_format = CV_8U;
    vx_size planes = 0;

    vxQueryImage(image, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width));
    vxQueryImage(image, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height));
    vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format));
    vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &planes, sizeof(planes));

    switch (format)
    {
    case VX_DF_IMAGE_U8:
        cv_format = CV_8U;
        break;
    case VX_DF_IMAGE_S16:
        cv_format = CV_16S;
        break;
    case VX_DF_IMAGE_RGB:
        cv_format = CV_8UC3;
        break;
    default:
        return VX_ERROR_INVALID_FORMAT;
    }

    vx_rectangle_t rect{ 0, 0, width, height };
    vx_uint8 *src[4] = { NULL, NULL, NULL, NULL };
    vx_uint32 p;
    void *ptr = NULL;
    vx_imagepatch_addressing_t addr[4] = { 0, 0, 0, 0 };
    vx_uint32 y = 0u;

    for (p = 0u; (p < (int)planes); p++)
    {
        vxAccessImagePatch(image, &rect, p, &addr[p], (void **)&src[p], VX_READ_ONLY);
        size_t len = addr[p].stride_x * (addr[p].dim_x * addr[p].scale_x) / VX_SCALE_UNITY;
        for (y = 0; y < height; y += addr[p].step_y)
        {
            ptr = vxFormatImagePatchAddress2d(src[p], 0, y - rect.start_y, &addr[p]);
            memcpy(mat.data + y * mat.step, ptr, len);
        }
    }

    for (p = 0u; p < (int)planes; p++)
    {
        vxCommitImagePatch(image, &rect, p, &addr[p], src[p]);
    }

    return status;
}

実行例

出力画像
出力画像

備考

筆者は以下の環境で動作確認しました.

参考URL


Menu

Computer Vision

GPGPU

AR

ROS

Docker

Jetson

ARM

プログラミング言語

開発環境

勉強会

Clone this wiki locally